SQL Server 2005+ - Get All Default and Check Constraints - sql

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

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

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;

Query to pull all unique indexes from all tables in database using sql

Query to pull all unique indexes from all tables in database using sql. The output should display schema name, table name and column name.
I tried the following query:
SELECT
t.[name] AS TableName
,i.[name] AS IndexName
,c.[name] AS ColumnName
FROM sys.schemas s
INNER JOIN sys.tables t ON t.schema_id = s.schema_id
AND s.[name] = 'dbo'
INNER JOIN sys.columns c ON c.object_id = t.object_id
INNER JOIN sys.indexes i ON i.object_id = t.object_id
AND i.index_id > 0
AND i.is_primary_key = 0
AND i.is_unique = 1
INNER JOIN sys.index_columns ic ON ic.object_id = t.object_id
AND ic.column_id = c.column_id
but it displays TableName and IndexName multiple times if they have more than one unique index column.
It want to display:
TableName IndexName ColumnName
Customers IX_customer_name FirstName, LastName
You can use the sp_MSforEachDB stored procedure:
EXECUTE master.sys.sp_MSforeachdb '
USE [?];
select db_name(), *
from sys.indexes
where is_unique = 1';
You can also exclude system databases by adding if db_id() > 4 begin end.

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

How to determine the primary key for a table in SQL Server?

What I'd like to be able to do in SQL Server 2005 somehow is with a table name as input determine all the fields that make up the primary key. sp_columns doesn't seem to have this field. Any ideas as to where to look?
I use this in a code generator I wrote to get the primary key:
SELECT i.name AS IndexName,
OBJECT_NAME(ic.OBJECT_ID) AS TableName,
COL_NAME(ic.OBJECT_ID,ic.column_id) AS ColumnName,
c.is_identity, c.user_type_id, CAST(c.max_length AS int) AS max_length,
CAST(c.precision AS int) AS precision, CAST(c.scale AS int) AS scale
FROM sys.indexes AS i
INNER JOIN sys.index_columns AS ic
INNER JOIN sys.columns AS c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
ON i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
WHERE i.is_primary_key = 1 AND ic.OBJECT_ID = OBJECT_ID('dbo.YourTableNameHere')
ORDER BY OBJECT_NAME(ic.OBJECT_ID), ic.key_ordinal
Actually, the primary key is something else than the indexes on the table. Is also something else than the clustered index. Is a constraint, so the proper place to look for it is sys.key_constraints:
select ic.key_ordinal, cl.name, ic.is_descending_key
from sys.key_constraints c
join sys.indexes i on c.parent_object_id = i.object_id
and c.unique_index_id = i.index_id
join sys.index_columns ic on ic.object_id = i.object_id
and ic.index_id = i.index_id
join sys.columns cl on cl.object_id = i.object_id
and ic.column_id = cl.column_id
where c.type = 'PK'
and 0 = ic.is_included_column
and i.object_id = object_id('<tablename>')
order by ic.key_ordinal
-- ANSI SQL compatible and works from SQL70 onwards:
select kcu.TABLE_SCHEMA, kcu.TABLE_NAME, kcu.CONSTRAINT_NAME, tc.CONSTRAINT_TYPE, kcu.COLUMN_NAME, kcu.ORDINAL_POSITION
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS as tc
join INFORMATION_SCHEMA.KEY_COLUMN_USAGE as kcu
on kcu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
and kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
and kcu.TABLE_SCHEMA = tc.TABLE_SCHEMA
and kcu.TABLE_NAME = tc.TABLE_NAME
where tc.CONSTRAINT_TYPE in ( 'PRIMARY KEY', 'UNIQUE' )
order by kcu.TABLE_SCHEMA, kcu.TABLE_NAME, tc.CONSTRAINT_TYPE, kcu.CONSTRAINT_NAME, kcu.ORDINAL_POSITION;
-- SQL Server 2005 specific:
select s.name as TABLE_SCHEMA, t.name as TABLE_NAME
, k.name as CONSTRAINT_NAME, k.type_desc as CONSTRAINT_TYPE
, c.name as COLUMN_NAME, ic.key_ordinal AS ORDINAL_POSITION
from sys.key_constraints as k
join sys.tables as t
on t.object_id = k.parent_object_id
join sys.schemas as s
on s.schema_id = t.schema_id
join sys.index_columns as ic
on ic.object_id = t.object_id
and ic.index_id = k.unique_index_id
join sys.columns as c
on c.object_id = t.object_id
and c.column_id = ic.column_id
order by TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_TYPE, CONSTRAINT_NAME, ORDINAL_POSITION;
Try This:
SELECT *
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
WHERE table_name = 'your_table_name'
AND constraint_name LIKE 'PK%'
select *
from information_schema.Table_Constraints
where Table_Name = #tableName
See this MSDN Listing for Table Constraints.
I normally find that...
sp_help <table>
gives me all I need to know about a table (including index information).
In SQL2005 this brings back a row that names the primary key and then gives a list of the column under "index_keys"
sp_help myTable
I ended up using this...
select cu.constraint_catalog,
cu.constraint_schema,
cu.table_name,
cu.constraint_name,
constraint_type,
column_name,
ordinal_position
from information_schema.key_column_usage cu
join information_schema.table_constraints as tc
on tc.constraint_catalog = cu.constraint_catalog and
tc.constraint_schema = cu.constraint_schema and
tc.constraint_name = cu.constraint_name and
tc.table_name = cu.table_name
where cu.table_name = 'table_name_goes_here'
order by constraint_name, ordinal_position