How can you retrieve relationsships from a MSSQL database - sql

I'm getting data from my MS-SQL 2016 Database. To determine the type of input fields, I need to know if there are any relations set up for any of my retrieved columns. I need this information to switch between input-fields and dropdown-menus.
I've already looked up in microsofts documentation (https://learn.microsoft.com/de-de/sql/relational-databases/system-catalog-views/sys-sql-dependencies-transact-sql?view=sql-server-2017) but couldn't find any sys-table containing the information I need. Am I even looking at the right place?

This may help.
;WITH Relationship
AS(
SELECT
ROW_NUMBER() OVER(ORDER BY fk.name) as Id,
CAST(fk.name as NVARCHAR(250)) as RelationName,
CAST(tr.name as NVARCHAR(250)) as ParentTable,
CAST((tr.name+'.'+cr.name) as NVARCHAR(250)) as ParentColumn,
CAST(tp.name as NVARCHAR(250)) as ReferencedTable,
CAST((tp.name+'.'+cp.name) as NVARCHAR(250)) as ReferencedColumn
FROM
sys.foreign_keys fk
INNER JOIN
sys.tables tp ON fk.parent_object_id = tp.object_id
INNER JOIN
sys.tables tr ON fk.referenced_object_id = tr.object_id
INNER JOIN
sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
INNER JOIN
sys.columns cp ON fkc.parent_column_id = cp.column_id AND fkc.parent_object_id = cp.object_id
INNER JOIN
sys.columns cr ON fkc.referenced_column_id = cr.column_id AND fkc.referenced_object_id = cr.object_id
--ORDER BY
-- tp.name, cp.column_id
)
SELECT * FROM Relationship
--Where ParentTable = 'Product' AND
--ReferencedTable='BillOfMaterials'

Use following two queries. Replace #schemaName, #tableName and #columnName as shown at the begging of the snippet.
DECLARE #schemaName AS SYSNAME= 'put here your schema name';
DECLARE #tableName AS SYSNAME= 'put here your table name';
DECLARE #columnName AS SYSNAME= 'put here your column name';
--The first one
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
WHERE SCHEMA_NAME(o.SCHEMA_ID) = #schemaName
AND OBJECT_NAME(f.referenced_object_id) = #tableName
AND COL_NAME(fc.parent_object_id, fc.parent_column_id) = #columnName
ORDER BY SCHEMA_NAME(f.SCHEMA_ID);
--The second one
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
WHERE OBJECT_NAME(F.PARENT_object_id) = #tableName
AND SCHEMA_NAME(F.SCHEMA_ID) = #schemaName
AND COL_NAME(fc.parent_object_id, fc.parent_column_id) = #columnName
ORDER BY SCHEMA_NAME(O.SCHEMA_ID),
OBJECT_NAME(f.referenced_object_id);

Related

SQL Server Drop constraint by type or keys

I need to drop a constraint from a table as I intend to drop a column for which this constraint is linked too.
The problem I currently have is that when this constraint was created, on different machines the name of the constraint differs so using the standard alter table drop constraint wouldn't work as I need a generic query.
I've run SP_Help against the table and can see we have a constraint_type and constraint_key listed which will host the same fixed value. Is there a way to delete a constraint-based on this?
Use the following command to see the constraints on the table, and select the proper constraint name to drop. Modify as needed. The code was taken from: https://dataedo.com/kb/query/sql-server/list-all-table-constraints:
select table_view,
object_type,
constraint_type,
constraint_name,
details
from (
select schema_name(t.schema_id) + '.' + t.[name] as table_view,
case when t.[type] = 'U' then 'Table'
when t.[type] = 'V' then 'View'
end as [object_type],
case when c.[type] = 'PK' then 'Primary key'
when c.[type] = 'UQ' then 'Unique constraint'
when i.[type] = 1 then 'Unique clustered index'
when i.type = 2 then 'Unique index'
end as constraint_type,
isnull(c.[name], i.[name]) as constraint_name,
substring(column_names, 1, len(column_names)-1) as [details]
from sys.objects t
left outer join sys.indexes i
on t.object_id = i.object_id
left outer join sys.key_constraints c
on i.object_id = c.parent_object_id
and i.index_id = c.unique_index_id
cross apply (select col.[name] + ', '
from sys.index_columns ic
inner join sys.columns col
on ic.object_id = col.object_id
and ic.column_id = col.column_id
where ic.object_id = t.object_id
and ic.index_id = i.index_id
order by col.column_id
for xml path ('') ) D (column_names)
where is_unique = 1
and t.is_ms_shipped <> 1
union all
select schema_name(fk_tab.schema_id) + '.' + fk_tab.name as foreign_table,
'Table',
'Foreign key',
fk.name as fk_constraint_name,
schema_name(pk_tab.schema_id) + '.' + pk_tab.name
from sys.foreign_keys fk
inner join sys.tables fk_tab
on fk_tab.object_id = fk.parent_object_id
inner join sys.tables pk_tab
on pk_tab.object_id = fk.referenced_object_id
inner join sys.foreign_key_columns fk_cols
on fk_cols.constraint_object_id = fk.object_id
union all
select schema_name(t.schema_id) + '.' + t.[name],
'Table',
'Check constraint',
con.[name] as constraint_name,
con.[definition]
from sys.check_constraints con
left outer join sys.objects t
on con.parent_object_id = t.object_id
left outer join sys.all_columns col
on con.parent_column_id = col.column_id
and con.parent_object_id = col.object_id
union all
select schema_name(t.schema_id) + '.' + t.[name],
'Table',
'Default constraint',
con.[name],
col.[name] + ' = ' + con.[definition]
from sys.default_constraints con
left outer join sys.objects t
on con.parent_object_id = t.object_id
left outer join sys.all_columns col
on con.parent_column_id = col.column_id
and con.parent_object_id = col.object_id) a
order by table_view, constraint_type, constraint_name

Find missing foreign key constraint on SQL Server database

Sometimes a badly designed Entity Framework with code-first implementation creates tables without foreign key constraints.
To check the columns created without those constraints, I had to create a specific script.
The columns that should be a relationship Id are named as "BookingId".
The SQL Script:
SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS Where COLUMN_NAME like '%id' AND COLUMN_NAME <> 'Id' AND DATA_TYPE = 'int'
AND TABLE_NAME + COLUMN_NAME NOT IN (SELECT OBJECT_NAME(fk.parent_object_id) + cpa.name
FROM sys.foreign_keys fk
INNER JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
INNER JOIN sys.columns cpa ON fkc.parent_object_id = cpa.object_id AND fkc.parent_column_id = cpa.column_id
INNER JOIN sys.columns cref ON fkc.referenced_object_id = cref.object_id AND fkc.referenced_column_id = cref.column_id)
order by TABLE_NAME, COLUMN_NAME
This is better:
with fcc as
(
select
sch1.name as parent_schema_name,
object_name(fkc.parent_object_id) as parent_table_name,
object_name(fkc.constraint_object_id) as constraint_name,
sch2.name as referenced_schema,
object_name(fkc.referenced_object_id) as referenced_table_name,
substring(
( select ','
+ rtrim(col_name(fc.parent_object_id,parent_column_id)) as [data()]
from sys.foreign_key_columns as fc with (nolock)
inner join sys.foreign_keys as fk with (nolock) on fc.constraint_object_id = fk.[object_id]
and fc.constraint_object_id = fkc.constraint_object_id
order by fc.constraint_column_id
for xml path('')
), 2, 8000) as parent_columns,
substring(
( select ','
+ rtrim(col_name(fc.referenced_object_id,referenced_column_id)) as [data()]
from sys.foreign_key_columns as fc with (nolock)
inner join sys.foreign_keys as fk with (nolock) on fc.constraint_object_id = fk.[object_id]
and fc.constraint_object_id = fkc.constraint_object_id
order by constraint_column_id
for xml path('')
), 2, 8000) as referenced_columns
from sys.foreign_key_columns as fkc with (nolock)
inner join sys.objects as obj1 with (nolock) on fkc.parent_object_id = obj1.[object_id]
inner join sys.tables as tbl1 with (nolock) on tbl1.[object_id] = obj1.[object_id]
inner join sys.schemas as sch1 with (nolock) on sch1.[schema_id] = tbl1.[schema_id]
inner join sys.objects as obj2 with (nolock) on fkc.referenced_object_id = obj2.[object_id]
inner join sys.tables as tbl2 with (nolock) on tbl2.[object_id] = obj2.[object_id]
inner join sys.schemas as sch2 with (nolock) on sch2.[schema_id] = tbl2.[schema_id]
where obj1.type = 'U'
and
obj2.type = 'U'
group by obj1.[schema_id],
obj2.[schema_id],
fkc.parent_object_id,
constraint_object_id,
referenced_object_id,
sch1.name,
sch2.name
),
idxcols as
(
select
s.name as schemaname,
object_name(t.[object_id]) as objectname,
substring(
(
select ','
+ rtrim(ac.name)
from sys.tables as st
inner join sys.indexes as ix on st.[object_id] = ix.[object_id]
inner join sys.index_columns as ic on ix.[object_id] = ic.[object_id] and ix.[index_id] = ic.[index_id]
inner join sys.all_columns as ac on st.[object_id] = ac.[object_id] and ic.[column_id] = ac.[column_id]
where i.[object_id] = ix.[object_id]
and
i.index_id = ix.index_id
and
ic.is_included_column = 0
order by ac.column_id
for xml path('')
), 2, 8000 ) as keycols
from sys.indexes as i
inner join sys.tables as t on t.[object_id] = i.[object_id]
inner join sys.schemas as s on s.[schema_id] = t.[schema_id]
where i.[type] in (1,2,5,6)
and
i.is_unique_constraint = 0
and
t.is_ms_shipped = 0
)
select fcc.constraint_name,
fcc.parent_schema_name +'.' + fcc.parent_table_name as parent_table,
fcc.referenced_schema + '.' + fcc.referenced_table_name as reference_table,
fcc.parent_columns,
fcc.referenced_columns,
N'CREATE NONCLUSTERED INDEX idx_' +
fcc.referenced_table_name +
'_' +
fcc.constraint_name +
N' ON ' +
fcc.parent_schema_name +
'.' +
fcc.parent_table_name +
N'(' +
fcc.referenced_columns +
N');' as ddl_create
from fcc
where not exists ( SELECT 1 FROM idxcols
WHERE fcc.parent_schema_name = idxcols.schemaName
AND fcc.parent_table_name = idxcols.objectName
AND REPLACE(fcc.parent_columns,'' ,'') = idxcols.KeyCols)

How to identify Foreign Keys from sys tables in SQL Server?

I used the following query to return Primary Keys of two tables. Is there a similar way to query for the Foreign Keys? I am not familiar with creating DBs but I dont see any Foreign Keys defined in the Object Explorer in SSMS. Thanks
select schema_name(tab.schema_id) as [schema_name],
pk.[name] as pk_name,
ic.index_column_id as column_id,
col.[name] as column_name,
tab.[name] as table_name
from sys.tables tab
inner join sys.indexes pk
on tab.object_id = pk.object_id
and pk.is_primary_key = 1
inner join sys.index_columns ic
on ic.object_id = pk.object_id
and ic.index_id = pk.index_id
inner join sys.columns col
on pk.object_id = col.object_id
and col.column_id = ic.column_id
where tab.name = 'custtable' or tab.name = 'custtrans'
order by schema_name(tab.schema_id),
pk.[name],
ic.index_column_id
Here is the output, but I need this to return Foreign Keys for these two tables.
schema_name pk_name column_id column_name table_name
dbo I_077ACCOUNTIDX 1 ACCOUNTNUM CUSTTABLE
dbo I_077ACCOUNTIDX 2 DATAAREAID CUSTTABLE
dbo I_077ACCOUNTIDX 3 PARTITION CUSTTABLE
dbo I_078RECID 1 RECID CUSTTRANS
Does this work for you? (This handles multi-key references by displaying them as comma-separated lists of columns, just FYI):
SELECT fkeys.[name] AS FKName,
OBJECT_NAME(fkeys.parent_object_id) AS TableName,
(SELECT STUFF((SELECT ',' + c.[name]
FROM sys.foreign_keys fk INNER JOIN sys.tables t ON fk.parent_object_id = t.object_id
INNER JOIN sys.columns as c ON t.object_id = c.object_id
INNER JOIN sys.foreign_key_columns AS fc ON c.column_id = fc.parent_column_id
AND fc.constraint_object_id = fk.object_id
AND fc.parent_object_id = fk.parent_object_id
WHERE fk.[name] = fkeys.[name]
FOR XML PATH ('')), 1, 1, '')) AS FKFolumns,
OBJECT_NAME(fkeys.referenced_object_id) AS ReferencedTableName,
(SELECT STUFF((SELECT ',' + c.[name]
FROM sys.foreign_keys fk INNER JOIN sys.tables t ON fk.referenced_object_id = t.object_id
INNER JOIN sys.columns as c ON t.object_id = c.object_id
INNER JOIN sys.foreign_key_columns AS fc ON c.column_id = fc.referenced_column_id
AND fc.constraint_object_id = fk.object_id
AND fc.referenced_object_id = fk.referenced_object_id
WHERE fk.[name] = fkeys.[name]
FOR XML PATH ('')), 1, 1, '')) AS ReferencedFKFolumns
FROM sys.foreign_keys fkeys
ORDER BY FKName;

SQL Server 2005+ - Get All Default and Check Constraints

I have the following query (put on my dba hat today :)) and I was wondering if anyone knows of a better way to get the Default And Check constraints without a Union All. This would sure make adding a where clause easier and more efficient.
SELECT
t.Name AS [TableName],
SCHEMA_NAME(t.schema_id) AS [SchemaName],
c.Name AS [ColumnName],
dc.Name AS ConstraintName,
'DEFAULT' AS ConstraintType,
dc.definition AS ConstraintDef
FROM sys.tables t
INNER JOIN sys.default_constraints dc ON t.object_id = dc.parent_object_id
INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id AND c.column_id = dc.parent_column_id
UNION ALL
SELECT
t.Name AS [TableName],
SCHEMA_NAME(t.schema_id) AS [SchemaName],
c.Name AS [ColumnName],
cc.Name AS ConstraintName,
'CHECK' AS ConstraintType,
cc.definition AS ConstraintDef
FROM sys.tables t
INNER JOIN sys.check_constraints cc ON t.object_id = cc.parent_object_id
INNER JOIN sys.columns c ON cc.parent_object_id = c.object_id AND c.column_id = cc.parent_column_id
Please note that this needs to work on SQL Server 2005+ as well as azure. The current script works but doesn't work efficiently when I need to add a where clause dynamically to limit the results.
You can reduce the total amount of JOINs for example like this:
with constraints as (
select parent_object_id, parent_column_id, name, definition,
'DEFAULT' [ConstraintType]
from sys.default_constraints
union all
select parent_object_id, parent_column_id, name, definition, 'CHECK'
from sys.check_constraints
)
SELECT
t.Name AS [TableName],
SCHEMA_NAME(t.schema_id) AS [SchemaName],
c.Name AS [ColumnName],
dc.Name AS ConstraintName,
dc.ConstraintType,
dc.definition AS ConstraintDef
FROM sys.tables t
INNER JOIN constraints dc ON t.object_id = dc.parent_object_id
INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id
AND c.column_id = dc.parent_column_id
or you can use another approach (using sys.sysconstraints and sys.objects)
SELECT
t.Name AS [TableName],
SCHEMA_NAME(t.schema_id) AS [SchemaName],
c.Name AS [ColumnName],
dc.Name AS ConstraintName,
dc.ConstraintType,
dc.definition AS ConstraintDef
FROM sys.tables t
INNER JOIN (
SELECT object_definition(o.object_id) [definition], OBJECT_NAME(o.OBJECT_ID) [Name],
o.parent_object_id, o.type_desc [ConstraintType], c.colid [parent_column_id]
FROM sys.objects o
join sys.sysconstraints c on o.object_id = c.constid
WHERE type_desc in ('DEFAULT_CONSTRAINT', 'CHECK_CONSTRAINT')
) dc ON t.object_id = dc.parent_object_id
INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id
AND c.column_id = dc.parent_column_id

getschema("foreignkeys") against SqlClient doesn't yield enough information

I need two tables and two sets of fields, not the name of the foreign key and one of the table names. Does anyone know how to query SQL Server for complete foreign key information? Thanks!
This can be an involved venture. The GetSchema as well as INFORMATION_SCHEMA views are incomplete, leading to the need to query the sys views directly for authoritive info.
try running this against your db and learn what you can.
This is from a thought experiment that got out of hand ;-)
BEGIN -- Get a table full of PK and UQ columns
DECLARE #tbl_unique_key_columns TABLE ( -- contains PK and UQ indexes
table_schema NVARCHAR(128),
table_name NVARCHAR(128),
index_name NVARCHAR(128),
column_id INT,
column_name NVARCHAR(128),
is_primary_key BIT,
is_unique_constraint BIT,
is_unique BIT,
is_nullable BIT,
is_rowguidcol BIT,
is_identity BIT,
default_definition NVARCHAR(MAX),
user_type NVARCHAR(128),
table_object_id INT )
INSERT INTO #tbl_unique_key_columns ( table_schema, table_name, index_name, column_id, column_name, is_primary_key, is_unique_constraint, is_unique, is_nullable, is_rowguidcol, is_identity, default_definition, user_type, table_object_id )
-- selects PK and UQ indexes
SELECT S.name AS schema_name, T.name AS table_name, IX.name AS index_name, IC.column_id, C.name AS column_name, IX.is_primary_key, IX.is_unique_constraint, IX.is_unique, C.is_nullable, C.is_rowguidcol, C.is_identity, d.definition, tp.NAME, T.[object_id]
FROM sys.tables AS T
INNER JOIN sys.schemas AS S
ON T.schema_id = S.schema_id
INNER JOIN sys.indexes AS IX
ON T.object_id = IX.object_id
INNER JOIN sys.index_columns AS IC
ON IX.object_id = IC.object_id
AND IX.index_id = IC.index_id
INNER JOIN sys.columns AS C
ON IC.column_id = C.column_id
AND IC.object_id = C.OBJECT_ID
INNER JOIN sys.types AS tp
ON C.user_type_id = tp.user_type_id
LEFT OUTER JOIN sys.default_constraints AS d
ON T.object_id = d.parent_object_id
AND C.column_id = d.parent_column_id
WHERE ( IX.is_unique = 1 )
AND ( IX.is_unique = 1 )
ORDER BY schema_name, table_name, index_name, C.column_id
END
BEGIN -- Get a table full of FK columns
DECLARE #tbl_foreign_key_columns TABLE ( constraint_name NVARCHAR(128),
base_schema_name NVARCHAR(128),
base_table_name NVARCHAR(128),
base_column_id INT,
base_column_name NVARCHAR(128),
unique_schema_name NVARCHAR(128),
unique_table_name NVARCHAR(128),
unique_column_id INT,
unique_column_name NVARCHAR(128),
base_object_id INT,
unique_object_id INT )
INSERT INTO #tbl_foreign_key_columns ( constraint_name, base_schema_name, base_table_name, base_column_id, base_column_name, unique_schema_name, unique_table_name, unique_column_id, unique_column_name, base_object_id, unique_object_id )
SELECT FK.name AS constraint_name, S.name AS base_schema_name, T.name AS base_table_name, C.column_id AS base_column_id, C.name AS base_column_name, US.name AS unique_schema_name, UT.name AS unique_table_name, UC.column_id AS unique_column_id, UC.name AS unique_column_name, T.[object_id], UT.[object_id]
FROM sys.tables AS T
INNER JOIN sys.schemas AS S
ON T.schema_id = S.schema_id
INNER JOIN sys.foreign_keys AS FK
ON T.object_id = FK.parent_object_id
INNER JOIN sys.foreign_key_columns AS FKC
ON FK.object_id = FKC.constraint_object_id
INNER JOIN sys.columns AS C
ON FKC.parent_object_id = C.object_id
AND FKC.parent_column_id = C.column_id
INNER JOIN sys.columns AS UC
ON FKC.referenced_object_id = UC.object_id
AND FKC.referenced_column_id = UC.column_id
INNER JOIN sys.tables AS UT
ON FKC.referenced_object_id = UT.object_id
INNER JOIN sys.schemas AS US
ON UT.schema_id = US.schema_id
ORDER BY base_schema_name, base_table_name
END
SELECT * FROM #tbl_unique_key_columns
SELECT * from #tbl_foreign_key_columns