All columns that refer to a column as foreign key - sql-server

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

Related

Determine SQL Server foreign key name

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';

In SQL Server - How to list all foreign keys related tables and fields?

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!

Query system tables for multiple cascade paths

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 do you list the primary key of a SQL Server User Defined Table Type?

My question is simple, how do you list the primary key (column name) of a SQL Server User Defined Table Type?
ex;
CREATE TYPE [dbo].[MyTableType] AS TABLE
(
[ID] int NOT NULL, PRIMARY KEY CLUSTERED ( [ID])
)
How to get the column [ID] with a query
It seem it is only possible to find primary key for real table, not table type.
This is stored in the catalog views:
SELECT c.Name
FROM sys.table_types AS tt
INNER JOIN sys.key_constraints AS kc
ON kc.parent_object_id = tt.type_table_object_id
INNER JOIN sys.indexes AS i
ON i.object_id = kc.parent_object_id
AND i.index_id = kc.unique_index_id
INNER JOIN sys.index_columns AS ic
ON ic.object_id = kc.parent_object_id
INNER JOIN sys.columns AS c
ON c.object_id = ic.object_id
AND c.column_id = ic.column_id
WHERE tt.Name = 'YourTypeName';
A user-defined table isn't an actual table so it has an entry in sys.table_types, not in sys.tables.
The key information can be retrieved from sys.key_constraints as with other tables, if the sys.table_types.type_table_object_id and sys.key_constraints.parent_object_id fields are used, eg:
create TYPE TestTableType AS TABLE
(
ID int primary key,
Name nVARCHAR(50)
)
declare #typeID int
select #typeId=type_table_object_id
from sys.table_types
where name='TestTableType'
select #typeId
-- Returns 1134627085
select *
from sys.key_constraints
where parent_object_id=#typeID
-- Returns
-- PK__TT_TestT__3214EC27BA14A4A6 1150627142 NULL 4 1134627085 PK PRIMARY_KEY_CONSTRAINT 2016-04-25 17:36:34.890 2016-04-25 17:36:34.890 1 0 0 1 1
After that, you can get the column name in the same way as with other primary keys, by joining with sys.index_columns and sys.columns:
select col.name
from sys.key_constraints kcon
inner join sys.index_columns indcol on indcol.object_id=kcon.parent_object_id
inner join sys.columns col on col.object_id = kcon.parent_object_id
and col.column_id = indcol.column_id
where parent_object_id=#typeID
Or
select col.name
from sys.table_types tt
inner join sys.key_constraints kcon on type_table_object_id=kcon.parent_object_id
inner join sys.index_columns indcol on indcol.object_id=kcon.parent_object_id
inner join sys.columns col on col.object_id = kcon.parent_object_id and col.column_id = indcol.column_id
where tt.name='TestTableType'

How to find what table foreign key is from?

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.

Resources