CHECK constraint in SQL Server not allowing to exceed value from foreign key - sql

I have the following two tables:
CREATE TABLE test1
(
ID int IDENTITY UNIQUE,
length int not null
)
CREATE TABLE test2
(
ID int IDENTITY UNIQUE,
test1number int references test1(ID),
distance int not null
)
Example: lets insert into test1 values 1 and 100 (ID=1 and length=100). Now lets insert into test2 values 1 as ID and test1number=1 as reference from test1. I want to create a constraint which will not allow to write distance bigger than 100 (length from test1).
Any other way than procedure?

If this is for individual rows, and we don't need to assert some property about all rows with the same test1number values then one way to do it is this:
CREATE TABLE test1
(
ID int IDENTITY UNIQUE,
length int not null,
constraint UQ_test1_Length_XRef UNIQUE (ID,Length)
)
go
CREATE TABLE _test2
(
ID int IDENTITY UNIQUE,
test1number int references test1(ID),
_test1length int not null,
distance int not null,
constraint FK_test2_test1_length_xref foreign key (test1number,_test1length)
references test1 (ID,length) on update cascade,
constraint CK_length_distance CHECK (distance <= _test1length)
)
go
create view test2
as
select ID,test1number,distance from _test2
go
create trigger T_I_t2 on test2
instead of insert
as
insert into _test2(test1number,_test1length,distance)
select test1number,length,distance
from inserted i inner join test1 t on i.test1number = t.id
go
We only need the view and trigger if you're trying to hide the existence of this extra column in the _test2 table from your users.

Related

Build correct logical db

I use 4 table in database.
Example:
Create table applicant(
Id int not null primary key,
IdName integer
idSkill integer,
idContact integer
Constraint initial foreign key (idName) References Initiale(id)
CONSTRAINT contacT foreign key (idContact) References contact(id)
CONSTRAINT Skills foreign key (idSkill) references skill(id))
Create table Initiale(
Id int not null primary key,
firstname text,
middlename text)
Create table contact(
Id int not null primary key,
phone text,
email text)
Create tabke Skills(
Id int not null primary key,,
Nane text)
I want insert data promptly in 4 table,but i not understand, what get id and insert in applicant.
Create tabke Skills ..... will fail. You should use Create table Skills.
Nor should you have Id int not null primary key,, (two commas), this would fail.
You should very likely be using Id INTEGER PRIMARY KEY not Id int not null primary key.
That is because generally an Id column should be a unique identifier of the row. With SQLite INTEGER PRIMARY KEY has a special meaining whilst INT PRIMARY KEY does not.
That is, if INTEGER PRIMARY KEY is used then the column will be an alias of the rowid column which has to be a unique signed 64 bit integer and importantly if no value is provided when inserting a row then SQLite will assign a unique integer. i.e. the all important Id.
This Id will initially be 1, then likely 2, then likely 3 and so on, although there is no guarantee that the Id will be monotonically increasing.
There are additional errors, mainly comma's omitted. The following should work :-
CREATE TABLE IF NOT EXISTS applicant(
Id INTEGER PRIMARY KEY,
IdName integer,
idSkill integer,
idContact integer,
Constraint initial foreign key (idName) References Initiale(id),
CONSTRAINT contacT foreign key (idContact) References contact(id),
CONSTRAINT Skills foreign key (idSkill) references Skills(id));
Create table IF NOT EXISTS Initiale(
Id INTEGER PRIMARY KEY,
firstname text,
middlename text);
Create table IF NOT EXISTS contact(
Id INTEGER PRIMARY KEY,
phone text,
email text);
Create table IF NOT EXISTS Skills(
Id INTEGER PRIMARY KEY,
Nane text);
You could then insert data along the lines of :-
INSERT INTO Initiale (firstname,middlename) -- Note absence of Id so SQLite will generate
VALUES
('Fred','James'), -- very likely id 1
('Alan','Roy'), -- very likely id 2
('Simon','Gerorge')-- very likely id 3
;
INSERT INTO contact -- alternative way of getting Id generated (specify null for Id)
VALUES
(null,'0123456789','email01#email.com'), -- very likely id 1
(null,'0987654321','email02#email.com'), -- very likely id 2
(null,'3333333333','email03.#email.com') -- very likely id 3
;
INSERT INTO Skills (Nane)
VALUES
('Skill01'),('Skill02'),('Skill03') -- very likely id's 1,2 and 3
;
INSERT INTO applicant (IdName,idSkill,idContact)
VALUES
-- First applicant
(2, -- Alan Roy
3, -- Skill 3
1), -- Contact 0123456789 )
-- Second Applicant
(3, -- Simon George
3, -- Skill 3
2), -- Contact 0987654321 )
-- Third Applicant
(2, -- Alan Roy again????
1, -- Skill 1
3), -- contact 3333333333)
(1,1,1) -- Fred James/ Skill 1/ Contact 0123456789
--- etc
;
Noting that Rows on the Initiale, Contact and Skills table MUST exists before insertions can be made into the Applicant table.
You could then run a query such as :-
SELECT * FROM applicant
JOIN Initiale ON Initiale.Id = idName
JOIN contact ON contact.Id = idContact
JOIN Skills ON Skills.Id = idSkill
This would result in (using the data as inserted above) :-

How to create a table with ONE existing row from another table?

I'm frankly new to sql and this is a project I'm doing.
I would like to know if there's a way to connect one column in one table to another table when creating tables. I know of the join method to show results of, but I want to minimized my code as possible.
CREATE TABLE players (
id INT PRIMARY KEY, -->code I want connect with table match_record
player_name CHARACTER
);
CREATE TABLE match_records (
(id INT PRIMARY KEY /*FROM players*/), --> the code I want it to be here
winner INT,
loser INT
);
CREATE TABLE players (
id INT not null PRIMARY KEY, -->code I want connect with table match_record
player_name CHARACTER
);
CREATE TABLE match_records (
id INT not null PRIMARY KEY references players(id), --> the code I want it to be here
winner INT,
loser INT
);
this way you restrict that match_records.id is only from players.id:
t=# insert into match_records select 1,1,0;
ERROR: insert or update on table "match_records" violates foreign key constraint "match_records_id_fkey"
DETAIL: Key (id)=(1) is not present in table "players".
So I add players:
t=# insert into players(id) values(1),(2);
INSERT 0 2
And now it allows insert:
t=# insert into match_records select 1,1,0;
INSERT 0 1
update
https://www.postgresql.org/docs/current/static/app-psql.html#APP-PSQL-PROMPTING
%#
If the session user is a database superuser, then a #, otherwise a >.
(The expansion of this value might change during a database session as
the result of the command SET SESSION AUTHORIZATION.)
in this way:
CREATE TABLE new_table as SELECT id,... from old_table where id = 1;

How is unique constraint applied from more than one table in oracle?

I have 3 tables is shown this tables:
table A
A(
code1
.
.
.
)
table B
B(
code2
.
.
.
)
table C
C(
code3
.
.
.
)
I want to be unique between code1,code2,code3 of this tables.
How do i recieve to my goal in oracle?
Does any syntax of oracle exist about this problem?
Based on materialized view.
P.s.
The code is not validated.
I currently have access only to oracle XE 11gR2, so I'm not able to use the materialized view log feature.
create table A (code int primary key);
create table B (code int primary key);
create table C (code int primary key);
create materialized view log on a with primary key;
create materialized view log on b with primary key;
create materialized view log on c with primary key;
create materialized view ABC_MV
refresh fast
as
select code from A
union all select code from B
union all select code from C
;
alter table ABC_MV add unique (code);
You can do that with trigger.
CREATE OR REPLACE TRIGGER table1_check
BEFORE INSERT OR UPDATE ON table1
FOR EACH ROW
BEGIN
IF EXISTS (
SELECT attribute FROM table2
WHERE attribute = :NEW.attribute
) THEN
RAISE_APPLICATION_ERROR(-20001,
'Already exist in table2');
END IF;
END;
/
You can modify it to check in more tables as well.
Using a 4th table
create table ABC (tab char(1) not null ,code int primary key, unique (tab,code));
create table A (tab char(1) as ('A') virtual not null,code int primary key,foreign key (tab,code) references ABC(tab,code));
create table B (tab char(1) as ('B') virtual not null,code int primary key,foreign key (tab,code) references ABC(tab,code));
create table C (tab char(1) as ('C') virtual not null,code int primary key,foreign key (tab,code) references ABC(tab,code));
insert into ABC (tab,code) values ('A',1);
insert into A (code) values (1);
insert into A (code) values (1);
[Code: 1, SQL State: 23000] ORA-00001: unique constraint (SYS.SYS_C0012834) violated
insert into B (code) values (1);
[Code: 2291, SQL State: 23000] ORA-02291: integrity constraint
(SYS.SYS_C0012839) violated - parent key not found

How do you enforce unique across 2 tables in SQL Server

Requirements:
Every employee has a unique ID. (EPID)
A employee can only be either one of below,
FT - Full Time
PT - Part Time
Any employee can never be both FT and PT.
FT & PT have lots of different fields to capture.
Implementation:
Create Table EmpFT( EPID int primary key, F1, F2, etc)
Create Table EmpPT( EPID int primary key, P1, P2, etc)
--This does not prevent same EPID on both EmpFT and EmpPT.
How do you implement No. 3 in database?
I am using SQL Server 2012 standard edition.
Try this method:
CREATE TABLE Emp(EPID INT PRIMARY KEY,
t CHAR(2) NOT NULL, UNIQUE (EPID,t));
CREATE TABLE EmpFT(EPID INT PRIMARY KEY, ... other columns
t CHAR(2) NOT NULL CHECK (t = 'FT'),
FOREIGN KEY (EPID,t) REFERENCES Emp (EPID,t));
CREATE TABLE EmpPT(EPID INT PRIMARY KEY, ... other columns
t CHAR(2) NOT NULL CHECK (t = 'PT'),
FOREIGN KEY (EPID,t) REFERENCES Emp (EPID,t));
You can add check constraints. Something like this for both tables
ALTER TABLE EmpFT
ADD CONSTRAINT chk_EmpFT_EPID CHECK (dbo.CHECK_EmpPT(EPID)= 0)
ALTER TABLE EmpPT
ADD CONSTRAINT chk_EmpPT_EPID CHECK (dbo.CHECK_EmpFT(EPID)= 0)
And the functions like so:
CREATE FUNCTION CHECK_EmpFT(#EPID int)
RETURNS int
AS
BEGIN
DECLARE #ret int;
SELECT #ret = count(*) FROM EmpFT WHERE #EPID = EmpFT.EPID
RETURN #ret;
END
GO
CREATE FUNCTION CHECK_EmpPT(#EPID int)
RETURNS int
AS
BEGIN
DECLARE #ret int;
SELECT #ret = count(*) FROM EmpPT WHERE #EPID = EmpPT.EPID
RETURN #ret;
END
GO
Further reading here:
http://www.w3schools.com/sql/sql_check.asp
http://technet.microsoft.com/en-us/library/ms188258%28v=sql.105%29.aspx
You could create a combined table for all employees. The FT and PT tables could use foreign keys to the employee table.
You cannot have primary keys span tables. So, one method is to create a table employee with the appropriate constraints. This might look like this:
create table employee (
EPID int not null identity(1, 1) primary key,
FTID int references empft(empftid),
PTID int references emppt(empptid),
CHECK (FTID is not null and PTID is null or FTID is null and PTID is not null),
UNIQUE (FTID),
UNIQUE (PTID)
. . .
);
create table empft (
EmpFTId int not null identity(1, 1) primary key,
. . .
);
create table emppt (
EmpPTId int not null identity(1, 1) primary key,
. . .
);
Of course, you could also use triggers if you wanted to.

insertion in a self referenced table

If I have a table
Table
{
ID int primary key identity,
ParentID int not null foreign key references Table(ID)
}
how does one insert first row into a table?
From a business logic point of view not null constraint on ParentID should not be dropped.
In SQL Server, a simple INSERT will do:
create table dbo.Foo
(
ID int primary key identity,
ParentID int not null foreign key references foo(ID)
)
go
insert dbo.Foo (parentId) values (1)
select * from dbo.Foo
results in
ID ParentID
----------- -----------
1 1
If you're trying to insert a value that will be different from your identity seed, the insertion will fail.
UPDATE:
The question is not too clear on what the context is (i.e. is the code supposed to work in a live production system or just a DB setup script) and from the comments it seems hard-coding the ID might not be an option. While the code above should normally work fine in the DB initialization scripts where the hierarchy root ID might need to be known and constant, in case of a forest (several roots with IDs not known in advance) the following should work as intended:
create table dbo.Foo
(
ID int primary key identity,
ParentID int not null foreign key references foo(ID)
)
go
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
Then one could query the last identity as usual (SCOPE_IDENTITY, etc.). To address #usr's concerns, the code is in fact transactionally safe as the following example demonstrates:
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
select * from dbo.Foo
select IDENT_CURRENT('dbo.Foo')
begin transaction
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
rollback
select IDENT_CURRENT('dbo.Foo')
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
select * from dbo.Foo
The result:
ID ParentID
----------- -----------
1 1
2 2
3 3
currentIdentity
---------------------------------------
3
currentIdentity
---------------------------------------
4
ID ParentID
----------- -----------
1 1
2 2
3 3
5 5
If you need to use an explicit value for the first ID, when you insert your first record, you can disable the checking of the IDENTITY value (see: MSDN: SET IDENTITY_INSERT (Transact-SQL)).
Here's an example that illistrates this:
CREATE TABLE MyTable
(
ID int PRIMARY KEY IDENTITY(1, 1),
ParentID int NOT NULL,
CONSTRAINT MyTable_ID FOREIGN KEY (ParentID) REFERENCES MyTable(ID)
);
SET IDENTITY_INSERT MyTable ON;
INSERT INTO MyTable (ID, ParentID)
VALUES (1, 1);
SET IDENTITY_INSERT MyTable OFF;
WHILE ##IDENTITY <= 5
BEGIN
INSERT INTO MyTable (ParentID)
VALUES (##IDENTITY);
END;
SELECT *
FROM MyTable;
IF OBJECT_ID('MyTable') IS NOT NULL
DROP TABLE MyTable;
It seems like the NOT NULL constraint is not true for the root node in the tree. It simply does not have a parent. So the assumption that ParentID is NOT NULL is broken from the beginning.
I suggest you make it nullable and add an index on ParentID to validate that there is only one with value NULL:
create unique nonclustered index ... on T (ParentID) where (ParentID IS NULL)
It is hard to enforce a sound tree structure in SQL Server. You can get multiple roots for example or cycles in the graph. It is hard to validate all that and it is unclear if it is worth the effort. It might well be, depending on the specific case.