Finding targeted columns in an FK - sql-server

If I have a pair of SQL tables, one of these tables has a pk on one column and a unique index on another (maybe a guid and id or some other unique key).
The other table has an fk to the unique index, not the pk. Is there a way I can query information schema to find the column targeted by the fk?

If I get you right, you want to use metadatabase:
SELECT
K_Table = FK.TABLE_NAME,
FK_Column = CU.COLUMN_NAME,
PK_Table = PK.TABLE_NAME,
PK_Column = PT.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT i1.TABLE_NAME, i2.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT ON PT.TABLE_NAME = PK.TABLE_NAME
Source: http://blog.sqlauthority.com/2006/11/01/sql-server-query-to-display-foreign-key-relationships-and-name-of-the-constraint-for-each-table-in-database/

Try this one -
SELECT
column_name = c.name
, table_name = OBJECT_NAME(k.parent_object_id)
, referenced_column_name = rc.name
, referenced_table_name = OBJECT_NAME(k.referenced_object_id)
FROM sys.foreign_key_columns k
JOIN sys.columns c ON c.[object_id] = k.parent_object_id AND c.column_id = k.parent_column_id
JOIN sys.columns rc ON rc.[object_id] = k.referenced_object_id AND rc.column_id = k.referenced_column_id

select object_name(fk.REFERENCED_OBJECT_ID) object_name,
i.name index_name,
ic.index_column_id sequence,
c.name column_name
from sys.foreign_keys fk
join sys.indexes i on i.object_id = fk.REFERENCED_OBJECT_ID
and i.index_id = fk.KEY_INDEX_ID
join sys.index_columns ic on ic.object_id = fk.REFERENCED_OBJECT_ID
and ic.index_id = fk.KEY_INDEX_ID
join sys.columns c on c.object_id = fk.REFERENCED_OBJECT_ID
and c.column_id = ic.column_id
where fk.name = 'fk_tbl2_to_tbl1';
e.g.
Setup:
create table tbl1 (
a int constraint pk_tbl1 primary key,
b int constraint uq_tbl1 unique,
c int);
create table tbl2 (
b int constraint fk_tbl2_to_tbl1 references tbl1(b),
d int);
Results:
| OBJECT_NAME | INDEX_NAME | SEQUENCE | COLUMN_NAME |
-----------------------------------------------------
| tbl1 | uq_tbl1 | 1 | b |
SQL Fiddle Demo

--FIND COLUMNS THAT ARE PRIMARY KEY AS WELL AS FOREIGN KEY - SQL SERVER 2008
SELECT
CU.TABLE_NAME, CU.COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
WHERE CU.CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY') AND
COLUMN_NAME IN (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = CU.TABLE_NAME AND
COLUMN_NAME = CU.COLUMN_NAME AND
CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'))
Source: here

Related

Optimize long query to find database schema with foreign keys and tables

I am writing a query to get all the tables in the db with their properties but also foreign keys and table that each reference to. I have a following query but it is taking 60 min to complete. Not sure what am I doing wrong?
SELECT
ist.table_name,
isc.column_name,
data_type,
character_maximum_length,
Columnproperty(Object_id(isc.table_name),
isc.column_name, 'IsIdentity') AS identityFlag,
is_nullable,
character_maximum_length,
numeric_scale,
(SELECT 1
FROM information_schema.table_constraints AS C
JOIN information_schema.key_column_usage AS K ON C.table_name = K.table_name
AND C.constraint_catalog = K.constraint_catalog
AND C.constraint_schema = K.constraint_schema
AND C.constraint_name = K.constraint_name
WHERE C.constraint_type = 'PRIMARY KEY'
AND C.table_name = isc.table_name
AND K.column_name = isc.column_name) AS primarykey,
(SELECT TOP 1 1
FROM information_schema.table_constraints AS C
JOIN information_schema.key_column_usage AS K ON C.table_name = K.table_name
AND C.constraint_catalog = K.constraint_catalog
AND C.constraint_schema = K.constraint_schema
AND C.constraint_name = K.constraint_name
WHERE C.constraint_type = 'FOREIGN KEY'
AND C.table_name = isc.table_name
AND K.column_name = isc.column_name) AS foreignKey,
a.parenttablename AS foreignTableName,
a.colname AS foreignColumnName
FROM
information_schema.tables ist
INNER JOIN
information_schema.columns isc ON ist.table_name = isc.table_name
LEFT OUTER JOIN
(SELECT
t.NAME AS parentTableName,
Object_name(f.parent_object_id) TableName,
Col_name(fc.parent_object_id, fc.parent_column_id) ColName
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.tables t ON t.object_id = fc.referenced_object_id) a ON a.tablename = ist.table_name
AND a.colname = isc.column_name
It is taking time to find the foreign table names. What is the best way to get db table schema
Firstly, you should stick to the sys schema, as these catalog views are more efficient, and INFORMATION_SCHEMA is only for compatibility
You are over-complicating it. You don't need to query the foreign key twice, you can just check if the LEFT JOIN succeeded by checking for NULL
SELECT
t.name AS table_name,
c.name AS column_name,
typ.name AS data_type,
c.max_length,
c.is_identity AS identityFlag,
c.is_nullable,
c.precision,
c.scale,
CASE WHEN EXISTS (SELECT 1
FROM sys.indexes AS i
JOIN sys.index_columns AS ic
ON ic.object_id = i.object_id
AND ic.index_id = i.index_id
WHERE i.object_id = t.object_id
AND ic.column_id = c.column_id
) THEN 1 ELSE 0 END AS primarykey,
CASE WHEN t_f.name IS NOT NULL THEN 1 ELSE 0 END AS foreignKey,
t_f.name AS foreignTableName,
c_f.name AS foreignColumnName
FROM
sys.tables t
INNER JOIN
sys.columns c ON c.object_id = t.object_id
INNER JOIN
sys.types typ ON typ.user_type_id = c.user_type_id
LEFT OUTER JOIN
sys.foreign_key_columns AS fc
INNER JOIN
sys.tables t_f ON t_f.object_id = fc.referenced_object_id
INNER JOIN
sys.columns c_f ON c_f.object_id = t_f.object_id
AND c_f.column_id = fc.referenced_column_id
ON fc.parent_object_id = t.object_id
AND fc.parent_column_id = c.column_id;

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!

How to get all table reference by any table?

Let say I have table tblDept, and it has primary key deptid and this is reference by other table also. Means I know one table tblEmp where deptid is referenced from tblDept’s primary key deptid. Now
I want to know how many table uses deptid as referect key(foreign key).
Please suggest only MS sql server.
The below query will solve your purpose.
SELECT
K_Table = FK.TABLE_NAME,
FK_Column = CU.COLUMN_NAME,
PK_Table = PK.TABLE_NAME,
PK_Column = PT.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT i1.TABLE_NAME, i2.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT ON PT.TABLE_NAME = PK.TABLE_NAME
--optional where condition
where CU.COLUMN_NAME = 'KeyId'

Calculate number of primary and secondary key columns

Is there a tool or query that will give me output as the total number of primary and secondary keys in a database table?
UPDATE ANSWER
Please note that secondary key is different from foreign key.
So count of no. of primary keys is possible in 2 ways:-
SELECT *
FROM sys.indexes i
INNER JOIN sys.tables t ON i.object_id = t.object_id AND
t.type = 'U'
LEFT JOIN sys.extended_properties AS EP ON EP.major_id = T.[object_id]
where is_primary_key=1
OR
SELECT COUNT(*) AS 'PRIMARY_KEY_CONSTRAINT'
FROM sys.objects
WHERE type_desc IN ('PRIMARY_KEY_CONSTRAINT')
To count no. of secondary keys use:
SELECT *
FROM sys.indexes i
INNER JOIN sys.tables t ON i.object_id = t.object_id AND
t.type = 'U'
LEFT JOIN sys.extended_properties AS EP ON EP.major_id = T.[object_id]
where is_unique=1 and is_primary_key=0
USE database
SELECT OBJECT_NAME(OBJECT_ID) AS NameofConstraint,
SCHEMA_NAME(schema_id) AS SchemaName,
OBJECT_NAME(parent_object_id) AS TableName
FROM sys.objects
WHERE type_desc IN ('PRIMARY_KEY_CONSTRAINT')
SELECT OBJECT_NAME(OBJECT_ID) AS NameofConstraint,
SCHEMA_NAME(schema_id) AS SchemaName,
OBJECT_NAME(parent_object_id) AS TableName
FROM sys.objects
WHERE type_desc IN ('FOREIGN_KEY_CONSTRAINT')
Simple count
SELECT COUNT(*) AS 'PRIMARY_KEY_CONSTRAINT'
FROM sys.objects
WHERE type_desc IN ('PRIMARY_KEY_CONSTRAINT')
SELECT COUNT(*) AS 'FOREIGN_KEY_CONSTRAINT'
FROM sys.objects
WHERE type_desc IN ('FOREIGN_KEY_CONSTRAINT')
The tool is SQL and this is another method to get what you want. A bit more complex then #kevchadders, but this way you can also make a listing of column names, types, etc
Count Foreign keys
SELECT count(*) from
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
WHERE
Col.Constraint_Name = Tab.Constraint_Name
AND Col.Table_Name = Tab.Table_Name
AND Constraint_Type in ( 'FOREIGN KEY')
AND Col.Table_Name in (select name from sysobjects where xtype = 'U')
Count Pirmairy keys
SELECT count(*) from
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
WHERE
Col.Constraint_Name = Tab.Constraint_Name
AND Col.Table_Name = Tab.Table_Name
AND Constraint_Type in ('PRIMARY KEY')
AND Col.Table_Name in (select name from sysobjects where xtype = 'U')
For all tables, show the PK and FK
FK
SELECT *, Col.Column_Name from
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
WHERE
Col.Constraint_Name = Tab.Constraint_Name
AND Col.Table_Name = Tab.Table_Name
AND Constraint_Type in ('PRIMARY KEY', 'FOREIGN KEY')
AND Col.Table_Name in (select name from sysobjects where xtype = 'U')
You can try this
SELECT 'PRIMARY KEYS' AS KeyType, COUNT(*) AS Total
FROM sys.tables AS TB INNER JOIN
sys.key_constraints AS KC ON KC.parent_object_id = TB.object_id
GROUP BY KC.type
UNION
SELECT 'FOREIGN KEYS' AS KeyType, COUNT(*) AS Total
FROM sys.tables AS TB INNER JOIN
sys.foreign_keys AS FK ON FK.referenced_object_id = TB.object_id
GROUP BY FK.type

how to find out the column dependencies of a table

I have written a query to find out column names of tables in the database.
SELECT
t.NAME AS TABLEName,
SCHEMA_NAME(schema_id) + '.' + c.name AS ColumnName
FROM
sys.tables t
INNER JOIN sys.columns c
ON c.object_id = t.object_id
WHERE OBJECT_NAME(c.object_id) LIKE '%Message%'
ORDER BY t.NAME
So far I've got the expected result, but whatever column I am looking I want to find out the dependency of column related tables. By executing the above query I am getting table names and column names.
How can I get the column related dependent tables?
Try this:
SELECT KCU1.TABLE_CATALOG,
KCU1.TABLE_SCHEMA,
KCU1.TABLE_NAME,
KCU1.COLUMN_NAME,
KCU2.TABLE_NAME AS REFERENCED_TABLE_NAME,
KCU2.COLUMN_NAME AS REFERENCED_COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU2
ON KCU2.CONSTRAINT_CATALOG = RC.UNIQUE_CONSTRAINT_CATALOG
AND KCU2.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA
AND KCU2.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME
AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION
WHERE KCU1.TABLE_NAME LIKE '%Message%'
ORDER BY
KCU1.TABLE_NAME,
KCU1.COLUMN_NAME
This might help. You will however need to tweak it a bit to suit your specific need:
SELECT OBJECT_NAME(referenced_major_id) AS ReferingObject,
(SELECT o.type_Desc FROM sys.objects o
WHERE o.object_id = d.referenced_major_id) AS ReferingObjType,
CASE WHEN referenced_minor_id <> 0 THEN COL_NAME(referenced_major_id, referenced_minor_id)
ELSE '' END AS RefColumnName,
OBJECT_NAME(object_ID) AS ReferencedObject,
(SELECT o.type_Desc FROM sys.objects o
WHERE o.object_id = d.object_id) AS ReferedObjType
fROM sys.sql_dependencies d
If you're looking for all tables/columns that reference a column in the table whose name contains token Message, you can use this:
;WITH PT AS (
SELECT
tc1.TABLE_NAME,
tc2.COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc1
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE tc2
ON tc1.CONSTRAINT_NAME = tc2.CONSTRAINT_NAME
WHERE tc1.CONSTRAINT_TYPE = 'PRIMARY KEY')
SELECT
FK_Table = FK.TABLE_NAME,
FK_Column = CU.COLUMN_NAME,
PK_Table = PK.TABLE_NAME,
PK_Column = PT.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME
FROM
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
JOIN PT
ON PT.TABLE_NAME = PK.TABLE_NAME
WHERE PK.TABLE_NAME LIKE '%Message%'
ORDER BY
FK.TABLE_NAME,
CU.COLUMN_NAME,
PK.TABLE_NAME,
PT.COLUMN_NAME

Resources