I have a table with a foreign key. How can I tell what table the FK is a primary key in? There's about 200 tables and I don't know how to find where that info is coming from/connected to.
Use this..
SELECT fk.name,
Object_name(fk.parent_object_id) [Parent table],
c1.name [Parent column]
FROM sys.foreign_keys fk
INNER JOIN sys.foreign_key_columns fkc
ON fkc.constraint_object_id = fk.object_id
INNER JOIN sys.columns c1
ON fkc.parent_column_id = c1.column_id
AND fkc.parent_object_id = c1.object_id
INNER JOIN sys.columns c2
ON fkc.referenced_column_id = c2.column_id
AND fkc.referenced_object_id = c2.object_id
WHERE Object_name(fk.referenced_object_id) = 'Tablename' -- Replace with your tablename
AND c2.name = 'Columname' -- Replace with your columname
Or simply use
sp_help Tablename or [Alt]+F1
This should help. Just run it in the DB you wish to query:
SELECT f.NAME AS ForeignKey
,SCHEMA_NAME(f.SCHEMA_ID) SchemaName
,OBJECT_NAME(f.parent_object_id) AS TableName
,COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName
,SCHEMA_NAME(o.SCHEMA_ID) ReferenceSchemaName
,OBJECT_NAME(f.referenced_object_id) AS ReferenceTableName
,COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id
INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id
GO
Source: http://blog.sqlauthority.com/2009/02/26/sql-server-2008-find-relationship-of-foreign-key-and-primary-key-using-t-sql-find-tables-with-foreign-key-constraint-in-database/
Basically, the first column is the FK, followed by the FK schema and object. Following those are the PK column name, its schema and object.
Either of the answers by NoDisplayName or Kris G. should work, but if you want something easier to remember while you're in SSMS, just right click the Foreign Key and choose Script As>Create To>New Window.
You will then get a script that can be used to (re-)create the FK, and you will be able to see what column it references in what table by reading the script.
Related
I'm trying to determine the name of the foreign key on a table but I'm getting wrong values. If I use this example SQL
CREATE TABLE Address
(
id INT NOT NULL PRIMARY KEY,
street VARCHAR NOT NULL
);
CREATE TABLE Person
(
id INT NOT NULL PRIMARY KEY,
orgId INT NOT NULL REFERENCES dbo.Organization (id)
);
SELECT tbl.name TableName, col.name ColumnName, fk.name ForeignKey
FROM sys.tables tbl
JOIN sys.columns col ON tbl.object_id = col.object_id
LEFT OUTER JOIN sys.foreign_keys fk ON tbl.object_id = fk.parent_object_id
WHERE tbl.name = 'Person'
it's telling me the ForeignKey name is the same thing for both the id and the orgId columns of the Person table. Clearly I'm missing an extra join condition, but I can't for the life of me figure out what it is.
your query is missing some part,to see which columns have FK you can use sys.foreign_key_columns view.
here is what you need:
SELECT
tbl.name TableName
, col.name ColumnName
, fk2.name ForeignKey
FROM
sys.tables tbl
JOIN sys.columns col
ON tbl.object_id = col.object_id
LEFT OUTER JOIN sys.foreign_key_columns AS fk
ON col.object_id = fk.parent_object_id
AND fk.parent_column_id = col.column_id
LEFT OUTER JOIN sys.foreign_keys AS fk2
ON fk2.object_id = fk.constraint_object_id
WHERE
tbl.name = 'Person';
I am having a problem to list all the foreign keys in a database and show the related tables & the fields from each one.
I have tried this query:
SELECT OBJECT_NAME(parent_object_id)
,OBJECT_NAME(referenced_object_id)
,OBJECT_NAME(object_id)
,*
FROM sys.foreign_keys
But this returns just the parent table and field. I need more information. Can anybody help me here?
You can try the below query from the reference also the reference.
-- using sys tables to enumerate foreign keys
-- returns 45 constraint rows
SELECT
f.name constraint_name
,OBJECT_NAME(f.parent_object_id) referencing_table_name
,COL_NAME(fc.parent_object_id, fc.parent_column_id) referencing_column_name
,OBJECT_NAME (f.referenced_object_id) referenced_table_name
,COL_NAME(fc.referenced_object_id, fc.referenced_column_id) referenced_column_name
,delete_referential_action_desc
,update_referential_action_desc
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.object_id = fc.constraint_object_id
ORDER BY f.name
-- using INFORMATION_SCHEMA to enumerate foreign keys
-- returns 45 constraint rows
SELECT
C.CONSTRAINT_NAME [constraint_name]
,C.TABLE_NAME [referencing_table_name]
,KCU.COLUMN_NAME [referencing_column_name]
,C2.TABLE_NAME [referenced_table_name]
,KCU2.COLUMN_NAME [referenced_column_name]
,RC.DELETE_RULE delete_referential_action_desc
,RC.UPDATE_RULE update_referential_action_desc
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU
ON C.CONSTRAINT_SCHEMA = KCU.CONSTRAINT_SCHEMA
AND C.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC
ON C.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
AND C.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C2
ON RC.UNIQUE_CONSTRAINT_SCHEMA = C2.CONSTRAINT_SCHEMA
AND RC.UNIQUE_CONSTRAINT_NAME = C2.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2
ON C2.CONSTRAINT_SCHEMA = KCU2.CONSTRAINT_SCHEMA
AND C2.CONSTRAINT_NAME = KCU2.CONSTRAINT_NAME
AND KCU.ORDINAL_POSITION = KCU2.ORDINAL_POSITION
WHERE C.CONSTRAINT_TYPE = 'FOREIGN KEY'
ORDER BY C.CONSTRAINT_NAME
To answer your (underlying) question, you can find everything you need in the following system tables:
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
INFORMATION_SCHEMA.TABLE_CONSTRAINTS
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
Good luck!
I use Entity Framework to generate my tables from my model, and every now and again I get a problem with multiple cascade paths. e.g:
Introducing FOREIGN KEY constraint
'FK_dbo.SurveyorSurveys_dbo.Surveys_Survey_ID' on table
'SurveyorSurveys' may cause cycles or multiple cascade paths.
I find it quite time consuming working out where the cascade paths are to this new table, so that I can remove one of the cascade deletes. I think it would be really useful if I could run a query on the system tables that showed me the full paths that were involved. Has anyone worked out how to do that?
For example I have this sql:
SELECT
ro.name referenced_object,
po.name parent_object,
fk.name foreign_key
FROM sys.foreign_keys fk
INNER JOIN sys.all_objects po
ON fk.parent_object_id = po.object_id
INNER JOIN sys.all_objects ro
ON fk.referenced_object_id = ro.object_id
WHERE delete_referential_action_desc = 'CASCADE'
and (po.name = 'Surveys' or po.name = 'Surveyors'')
ORDER BY ro.name
But this only takes me up one level in the hierarchy, it might be better to remove a cascade delete at a higher level, so I end up adjusting and re-running the sql until I work out the full path
This is typically something to do with a recursive query.
First a few words to clarify the column names in sys.all_objects:
parent_object_id refers to the object owning the foreign key, so it's not the parent in the relationship, it's the child.
referenced_object_id is the parent in the relationship.
Knowing this, we can write a recursive query that collects trees of foreign key relationships by connecting the child in the previous level with the parent in the subsequent level:
WITH [Cascades] AS(
SELECT
fk.referenced_object_id AS [RootId],
fk.parent_object_id AS [ChildId],
fk.referenced_object_id AS [ParentId],
fk.name foreign_key,
1 AS [Level]
FROM sys.foreign_keys fk
WHERE delete_referential_action_desc = 'CASCADE'
UNION ALL
SELECT [Cascades].[RootId],
fk.parent_object_id,
fk.referenced_object_id,
fk.name foreign_key,
[Cascades].[Level] + 1
FROM sys.foreign_keys fk
INNER JOIN [Cascades] ON [Cascades].[ChildId] = fk.referenced_object_id
WHERE delete_referential_action_desc = 'CASCADE'
)
SELECT [root].Name AS [Root],
po.Name AS [Parent],
co.Name AS [Child],
foreign_key,
cs.[Level]
FROM [Cascades] cs
INNER JOIN sys.all_objects [root] ON cs.[RootId] = [root].object_id
INNER JOIN sys.all_objects po ON cs.ParentId = po.object_id
INNER JOIN sys.all_objects co ON cs.ChildId = co.object_id
WHERE [root].name = 'Surveys'
ORDER BY [Root], [Parent], [Level], [Child]
If I execute the query in a simple tree-level hierarchy, the output is:
Root Parent Child foreign_key Level
-----------------------------------
A A B1 FK_B1_A 1
A A B2 FK_B2_A 1
A B1 C FK_C_B1 2
Alternative sql based on Gert's excellent answer. This one lets me specify the leaf and shows the full cascade path on each row
WITH Cascades
AS (SELECT
fk.parent_object_id,
fk.referenced_object_id,
fk.name foreign_keys,
CAST(ro.name + ' -> ' + po.name AS nvarchar(256)) path,
1 AS level
FROM sys.foreign_keys fk
INNER JOIN sys.all_objects po
ON fk.parent_object_id = po.object_id
INNER JOIN sys.all_objects ro
ON fk.referenced_object_id = ro.object_id
WHERE delete_referential_action_desc = 'CASCADE'
-- specifying leaf instead of root:
AND po.name IN ('Surveys', 'Surveyors', 'surveyorsurveys')
UNION ALL SELECT
fk.parent_object_id,
fk.referenced_object_id,
CAST(fk.name + ' -> ' + Cascades.foreign_keys as nvarchar(128)),
CAST(ro.name + ' -> ' + cascades.path AS nvarchar(256)),
cascades.level + 1
FROM sys.foreign_keys fk
INNER JOIN sys.all_objects po
ON fk.parent_object_id = po.object_id
INNER JOIN sys.all_objects ro
ON fk.referenced_object_id = ro.object_id
INNER JOIN cascades
ON cascades.referenced_object_id = fk.parent_object_id
WHERE delete_referential_action_desc = 'CASCADE')
SELECT
path,
foreign_keys,
level
FROM Cascades
ORDER BY path
How can I have a list of all columns in other tables/schemas that refer to a certain column A as foreign key ?
Something like this?
SELECT
fk.Name,
'Referenced table' = refTbl.Name,
'Parent table' = parentTbl.Name,
'Parent column' = c.name
FROM
-- FK constraint
sys.foreign_keys fk
INNER JOIN
-- Referenced table (where the PK resides)
sys.tables refTbl ON fk.referenced_object_id = refTbl.object_id
INNER JOIN
-- Parent table (which has the foreign key column)
sys.tables parentTbl ON fk.parent_object_id = parentTbl .object_id
INNER JOIN
-- link to the columns involved in the FK contraint
sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
INNER JOIN
-- column in the parent table that's part of the FK constraint
sys.columns c ON c.object_id = parentTbl.object_id AND c.column_id = fkc.parent_column_id
WHERE
refTbl.name = 'YourTableNameHere'
ORDER BY
fk.Name, parentTbl.name
i need list of tableName , columnName ,constraintsType and cascade type in sql server 2008 so i tried below query but cascade type is null
SELECT TB.name AS "TableName",CL.name AS
"ColumnName",KC.type,FK.delete_referential_action,FK.update_referential_action
FROM SYS.key_constraints KC JOIN SYS.tables TB ON
KC.parent_object_id=TB.object_id JOIN SYS.columns CL ON
KC.parent_object_id=CL.object_id LEFT JOIN SYS.foreign_keys FK ON FK.name = KC.name
I believe this is what you are looking for
SELECT
o1.name AS FK_table,
c1.name AS FK_column,
fk.name AS FK_name,
fk.type as FK_TYPE,
pk.name AS PK_name,
pk.type as PK_TYPE,
fk.delete_referential_action_desc AS Delete_Action,
fk.update_referential_action_desc AS Update_Action
FROM sys.objects o1
INNER JOIN sys.foreign_keys fk
ON o1.object_id = fk.parent_object_id
INNER JOIN sys.foreign_key_columns fkc
ON fk.object_id = fkc.constraint_object_id
INNER JOIN sys.columns c1
ON fkc.parent_object_id = c1.object_id
AND fkc.parent_column_id = c1.column_id
INNER JOIN sys.key_constraints pk
ON fk.referenced_object_id = pk.parent_object_id
AND fk.key_index_id = pk.unique_index_id
ORDER BY o1.name, fkc.constraint_column_id
I didn't try out your query as I don't a sql server in front of me but I believe you are missing a DMV and that is why your left join is returning nulls.