Foreign key referencing a 2 columns primary key in SQL Server - sql

This question is pretty much similar to this one, but for SQL Server 2005 :
I have 2 tables in my database:
--'#' denotes the primary key
[Libraries]
#ID #Application Name
1 MyApp Title 1
2 MyApp Title 2
[Content]
#ID Application LibraryID Content
10 MyApp 1 xxx
11 MyApp 1 yyy
(the database is obviously much more complex and having this double key makes sense)
Each library is identified by its unique ID and Application name. I'm trying to ensure that each content is properly referencing an existing library.
When creating the constraint (using the Wizard) as
Primary key table Foreign key table
[Libraries] [Content]
ID ---> LibraryID
Application ---> Application
I have the following error:
The columns in table 'Libraries' do
not match an existing primary key or
UNIQUE constraint
Do you have any idea of what is going on? and if it's possible at all using SQL Server? (I can't modify the [Library] table at all)
Thanks a lot for your help!

Of course it's possible to create a foreign key relationship to a compound (more than one column) primary key. You didn't show us the statement you're using to try and create that relationship - it should be something like:
ALTER TABLE dbo.Content
ADD CONSTRAINT FK_Content_Libraries
FOREIGN KEY(LibraryID, Application)
REFERENCES dbo.Libraries(ID, Application)
Is that what you're using?? If (ID, Application) is indeed the primary key on dbo.Libraries, this statement should definitely work.
Luk: just to check - can you run this statement in your database and report back what the output is??
SELECT
tc.TABLE_NAME,
tc.CONSTRAINT_NAME,
ccu.COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
INNER JOIN
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
ON ccu.TABLE_NAME = tc.TABLE_NAME AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
WHERE
tc.TABLE_NAME IN ('Libraries', 'Content')

Note that the fields must be in the same order. If the Primary Key you are referencing is specified as (Application, ID) then your foreign key must reference (Application, ID) and NOT (ID, Application) as they are seen as two different keys.

The key is "the order of the column should be the same"
Example:
create Table A (
A_ID char(3) primary key,
A_name char(10) primary key,
A_desc desc char(50)
)
create Table B (
B_ID char(3) primary key,
B_A_ID char(3),
B_A_Name char(10),
constraint [Fk_B_01] foreign key (B_A_ID,B_A_Name) references A(A_ID,A_Name)
)
the column order on table A should be --> A_ID then A_Name; defining the foreign key should follow the same order as well.

The Content table likely to have multiple duplicate Application values that can't be mapped to Libraries. Is it possible to drop the Application column from the Libraries Primary Key Index and add it as a Unique Key Index instead?

I had the same problem and I think I have the solution.
If your field Application in table Library has a foreign key that references a field in another table (named Application I would bet), then your field Application in table Library has to have a foreign key to table Application too.
After that you can do your composed foreign key.
Excuse my poor english, and sorry if I'm wrong.

Related

NULL values for referential_constraints.unique_constraint_* columns in information schema

In Postgres 10 I have declared the following:
create table test_abc (
pk integer not null,
id integer not NULL,
id2 integer not null,
PRIMARY KEY (pk)
);
CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);
And then a second table with a FK referencing the first:
create table test_def (
id integer not null,
abc_id integer,
abc_id2 integer,
PRIMARY KEY (id),
FOREIGN KEY (abc_id,abc_id2) references test_abc(id,id2)
);
Now consider the output of this query:
SELECT unique_constraint_catalog, unique_constraint_schema, unique_constraint_name
FROM information_schema.referential_constraints r
WHERE r.constraint_name = 'test_def_abc_id_fkey'
----------------------
NULL NULL NULL
All unique_constraint_* columns have a null value.
From the Postgres documentation it seems these meta columns should contain the
name of the [object] that contains the unique or primary key constraint that the foreign key constraint references (always the current database)
Question:
I'm surely in the same database, and the unique index declared on test_abc table is a unique constraint (otherwise I wouldn't be able to declare the FK to begin with), so why are these columns empty?
I'm using the referential_constraints with some joins to get information about the columns referenced by my foreign keys, but this way I'm missing all those where the unique constraint is set with an index.
Test setup
You assume the constraint name test_def_abc_id_fkey, the default name resulting from your setup in Postgres 11 or older. Worth noting, though, that default names have been improved for Postgres 12, where the same setup results in test_def_abc_id_abc_id2_fkey. The release notes for Postgres 12:
Use all key columns' names when selecting default constraint names for foreign keys (Peter Eisentraut)
Previously, only the first column name was included in the constraint name, resulting in ambiguity for multi-column foreign keys.
See:
db<>fiddle here
So let's use the explicit name test_def_abc_fkey for the FK constraint to avoid confusion:
CREATE TABLE test_abc (
pk int PRIMARY KEY
, id int NOT NULL
, id2 int NOT NULL
);
CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);
CREATE TABLE test_def (
id int PRIMARY KEY
, abc_id int
, abc_id2 int
, CONSTRAINT test_def_abc_fkey -- !
FOREIGN KEY (abc_id,abc_id2) REFERENCES test_abc(id,id2)
);
And that works in Postgres 9.5 - Postgres 12, even in Postgres 9.3.
(I had been under the wrong impression an actual constraint would be required.)
Answer
Your observation from querying the information schema holds:
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
We get a row, but the three fields unique_constraint_catalog, unique_constraint_schema and unique_constraint_name are NULL.
The explanation seems simple. Those columns describe, as the manual puts it:
... the unique or primary key constraint that the foreign key constraint references
But there is no UNIQUE constraint, just a UNIQUE index. A UNIQUE constraint is implemented using a UNIQUE index in Postgres. Constraints are defined by the SQL standard, indexes are implementation details. There are differences like the one you discovered. Related:
How does PostgreSQL enforce the UNIQUE constraint / what type of index does it use?
The same test with an actual UNIQUE constraint shows data as expected:
db<>fiddle here
So this seems to make sense. Especially since the information schema is also defined by the SQL standards committee and indexes are not standardized, only constraints. (No index information in information schema views.)
All clear? Not quite.
However
There is another information schema view key_column_usage. Its last column is described as:
position_in_unique_constraint ... For a foreign-key constraint, ordinal position of the referenced column within its unique constraint (count starts at 1); otherwise null
Bold emphasis mine. Here, the ordinal position of the column in the index is listed anyway:
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
See:
db<>fiddle here
Seems inconsistent.
What's worse, the manual claims that an actual PRIMARY KEY or UNIQUE constraint would be required for the creation of a FOREIGN KEY constraint:
A foreign key must reference columns that either are a primary key or
form a unique constraint. This means that the referenced columns
always have an index (the one underlying the primary key or unique
constraint); so checks on whether a referencing row has a match will
be efficient.
Seems to be a documentation bug? If nobody can point out where I am going wrong here, I'll file a bug report.
Related:
Postgres unique constraint vs index
Solution
I'm using the referential_constraints with some joins to get information about the columns referenced by my foreign keys, but this way I'm missing all those where the unique constraint is set with an index.
In Postgres, the system catalog is the actual source of truth. See:
Information schema vs. system catalogs
So you could use something like this (like I also added in the fiddle above):
SELECT c.conname
, c.conrelid::regclass AS fk_table, k1.fk_columns
, c.confrelid::regclass AS ref_table, k2.ref_key_columns
FROM pg_catalog.pg_constraint c
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT a.attname
FROM pg_catalog.pg_attribute a
, unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
WHERE a.attrelid = c.conrelid
AND a.attnum = k.attnum
ORDER BY k.ord
) AS fk_columns
) k1 ON true
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT a.attname
FROM pg_catalog.pg_attribute a
, unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord)
WHERE a.attrelid = c.confrelid
AND a.attnum = k.attnum
ORDER BY k.ord
) AS ref_key_columns
) k2 ON true
WHERE conname = 'test_def_abc_fkey';
Returns:
conname | fk_table | fk_columns | ref_table | ref_key_columns
:---------------- | :------- | :--------------- | :-------- | :--------------
test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Related:
Find the referenced table name using table, field and schema name
Find referenced field(s) of foreign key constraint
How can I find tables which reference a particular row via a foreign key?

Check constraint references to unique column in the same table

I have a table:
ID Name ParentID
== ==== ========
1 A Null
2 B 1
3 C 2
so A is parent of B, and B is parent of C.
I need to create a constraint for column(ParentID) which does not accept a number is not exist in column (ID).
How I would do that?
You need to add Foreign Key.
ALTER TABLE table1
ADD CONSTRAINT fk_parent_id
FOREIGN KEY (parent_id) REFERENCES table1(id);
You can also create a foreign key using SSMS design as shown below. Expand table and right click on Keys - New Foreign key
Now click on the browse button of relationship and specify the colum nane of primary and foreign key table as shown below.
This is one of the way and you might select the preferred way either using query or design for creating the foreign key relationships between tables in Sql Server.

Primary key is not deleted when I deleted table inside SSMS- SQL Server

I have a table and I need to insert a huge number of records, so I create my table without primary key to make the insert faster. when I finished insert, I create primary key for that table using this command:
ALTER TABLE MyTable ADD CONSTRAINT PK_MyTable PRIMARY KEY (MyTableId)
The problem is if I delete the table inside SQL Server management studio then the next time when I want to create this primary key, it says :
The CREATE UNIQUE INDEX statement terminated because
a duplicate key was found for the object name
I need to let SQL knows that this primary key is connected to that table and must automatically be deleted when the table is being deleted.
I guess this is not a primary key problem. It is a problem with your data. You are not allowed to create a primary key because you have a duplicate value in your primary key column.
You could run a query to confirm that you have a duplicate.
SELECT
MyTableId,
COUNT(*)
FROM
MyTable
GROUP BY
MyTableId
HAVING
COUNT(*) > 1
The Best Answer to dropping the table containing Primary and foreign constraints is :
Step 1 : Drop the Primary key of the table.
Step 2 : Now it will prompt whether to delete all the foreign references or not.
Step 3 : Delete the table.

circular relationship

I have a question that circulates a lot in my head, I'd like to find a response that can unlock me ... in the field of database (DBMS and Modeling MPD).
Is it possible to find a circular relationship between two (or more)tables
such as:
Create Table TA ( TA_ID INTEGER not null, A SMALLINT, AA NUMERIC(5,0),TB_ID INTEGER, constraint PK_TA primary key (TA_ID) );
Create Table TB (TB_ID INTEGER not null, B SMALLINT, BB FLOAT, TA_ID INTEGER, constraint PK_TB primary key (TB_ID) );
alter TABLE TB add constraint Fk_TB_TA foreign key (TA_ID) references TA (TA_ID);
alter TABLE TA add constraint Fk_TA_TB foreign key (TB_ID) references TB (TB_ID);
If you're looking for a set of tables that refer to each other through FKs, then you could try this code.
SELECT *
FROM
sys.foreign_keys fk
WHERE
EXISTS
(SELECT * FROM sys.foreign_keys fk2 WHERE fk2.referenced_object_id = fk.parent_object_id AND fk2.parent_object_id = fk.referenced_object_id)
Ok, is it possible? With the NOT NULL constraints on both - NO. If you allow NULLS in one, then YES.
Is it a good idea, I can't think of a reason why you'd do this but sometimes problems in the real world are complicated and I generally don't say never.
A quick search pulls up this question that shows that this IS happening in the real world, check this out: How to do an INSERT into tables with circular relationships (SQL SERVER)

SQL Server 2008: The columns in table do not match an existing primary key or unique constraint

I need to make some changes to a SQL Server 2008 database.
This requires the creation of a new table, and inserting a foreign key in the new table that references the Primary key of an already existing table. So I want to set up a relationship between my new tblTwo, which references the primary key of tblOne.
However when I tried to do this (through SQL Server Management Studio) I got the following error:
The columns in table 'tblOne' do not
match an existing primary key or
UNIQUE constraint
I'm not really sure what this means, and I was wondering if there was any way around it?
It means that the primary key in tblOne hasn't been properly declared - you need to go to tblOne and add the PRIMARY KEY constraint back onto it.
If you're sure that tblOne does have a PRIMARY KEY constraint, then maybe there are multiple tblOne tables in your DB, belonging to different schemas, and your references clause in your FK constraint is picking the wrong one.
If there's a composite key (which your comment would indicate), then you have to include both columns in your foreign key reference also. Note that a table can't have multiple primary keys - but if it has a composite key, you'll see a key symbol next to each column that is part of the primary key.
If you have a composite key the order is important when creating a FK, and sometimes the order is not how it is displayed.
What I do is go to the Keys section of the table1 and select script primary key as create to clipboard and then create FK using the order as shown in script
I've had this situation that led me to this topic. Same error but another cause. Maybe it will help someone.
Table1
ColA (PK)
ColB (PK)
ColC
Table2
ID (PK)
ColA
COLB
When trying to create foreign key in Table2 I've choose values from combobox in reverse order
Table1.ColB = Table2.ColB
Table1.ColA = Table2.ColA
This was throwing me an error like in topic name. Creating FK keeping order of columns in Primary key table as they are, made error disappear.
Stupid, but.. :)
If you still get that error after you have followed all advice from the above answers and everything looks right.
One way to fix it is by Removing your Primary keys for both tables, Save, Refresh, and add them again.
Then try to add your relationship again.
This Error happened with me When I tried to add foreign key constraint starting from PrimaryKey Table
Simpy go to other table and and create this foreign key constraint from there (foreign key Table)
This issue caught me out, I was adding the relationship on the wrong table. So if you're trying to add a relationship in table A to table B, try adding the relationship in table B to table A.
That looks like you are trying to create a foreign key in tblTwo that does not match (or participate) with any primary key or unique index in tblOne.
Check this link on MSDN regarding it. Here you have another link with a practical case.
EDIT:
Answwering to your comment, I understand you mean there are 2 fields in the primary key (which makes it a composite). In SQL it is not possible to have 2 primary keys on the same table.
IMHO, a foreign key field should always refer to a single register in the referenced table (i.e. the whole primary key in your case). That means you need to put both fields of the tblOne primary key in tblTwo before creating the foreign key.
Anyway, I have investigated a bit over the Internet and it seems SQL Server 2008 (as some prior versions and other RDBMS) gives you the possibility to reference only part of the primary key as long as this part is a candidate key (Not Null and Unique) and you create an unique constraint on it.
I am not sure you can use that in your case, but check this link for more information on it.
I have found that the column names must match.
Example:
So if tblOne has id called categoryId a reference in tblTwo must also be called categoryId.
_tblname, primary key name, foreign key_
tblOne, "categoryId", none
tblTwo, "exampleId", "categoryId"
I noticed this when trying to create foreign key between 2 tables that both had the column name "id" as primary key.
If nothing helps, then this could be the reason:
Considering this case:
Table A:
Column 1 (Primary Key)
Column 2 (Primary Key)
Column 3
Column 4
Table B:
Column a (Primary Key)
Column b
Column c
when you are defining a dependency B to A, then you are forced to respect the order in which the primaries are defined.
That's mean your dependency should look like this:
Table A Table B
Column 1 Column b
Column 2 Column c
AND NOT:
Table A Table B
Column 2 Column c
Column 1 Column b
then this will lead to the error you are encountering.
I've found another way to get this error. This can also happen if you are trying to make a recursive foreign key (a foreign key to the primary key in the same table) in design view in SQL Management Studio. If you haven't yet saved the table with the primary key it will return this message. Simply save the table then it will allow you to create the foreign key.
If you have data in your tables this could be the issue.
In my case I had some data in the Account table that I loaded at 3 pm, and some data in Contact table that I loaded at 3:10 pm, so Contact table had some values that weren't in my Account table yet.
I ended up deleting these values from the contact table and then managed to add a key without any problems.
Kindly also see that there are no existing data inside the table where the primary key is defined while setting the foreign key with another table column.
this was the cause of the error in my case.
I had to take backup empty the table set the relationship and then upload the data back.
sharing my experience
Was using ms sql smss