How do I get constraints on a SQL Server table column - sql

I have a column called MealType (VARCHAR) in my table with a CHECK constraint for {"Veg", "NonVeg", "Vegan"}
That'll take care of insertion.
I'd like to display these options for selection, but I couldn't figure out the SQL query to find out the constraints of a particular column in a table.
From a first glance at system tables in SQL Server, it seems like I'll need to use SQL Server's API to get the info. I was hoping for a SQL query itself to get it.

Easiest and quickest way is to use:
sp_help 'TableName'

This query should show you all the constraints on a table:
select chk.definition
from sys.check_constraints chk
inner join sys.columns col
on chk.parent_object_id = col.object_id
inner join sys.tables st
on chk.parent_object_id = st.object_id
where
st.name = 'Tablename'
and col.column_id = chk.parent_column_id
can replace the select statement with this:
select substring(chk.Definition,2,3),substring(chk.Definition,9,6),substring(chk.Definition,20,5)

SELECT obj_table.NAME AS 'table',
columns.NAME AS 'column',
obj_Constraint.NAME AS 'constraint',
obj_Constraint.type AS 'type'
FROM sys.objects obj_table
JOIN sys.objects obj_Constraint
ON obj_table.object_id = obj_Constraint.parent_object_id
JOIN sys.sysconstraints constraints
ON constraints.constid = obj_Constraint.object_id
JOIN sys.columns columns
ON columns.object_id = obj_table.object_id
AND columns.column_id = constraints.colid
WHERE obj_table.NAME='table_name'
ORDER BY 'table'

You can use
sp_helpconstraint 'tableName', 'nomsg'
to get all the constraints for the table.
"sp_help" return far more information.

Thanks to orgtrigger for his example!
I improved it to be able to remove unnecessary constraints (and then create their modified versions, if needed). Maybe this code will be useful for anybody.
-- removing old constraints
DECLARE #ConstraintNames TABLE (Name VARCHAR(MAX), RowNum INT)
DECLARE #TableName VARCHAR(100) = 'HubSpot'
INSERT #ConstraintNames
SELECT [constraint].name,
ROW_NUMBER() OVER (ORDER BY [constraint].[name]) AS RowNum
FROM sys.default_constraints [constraint]
INNER JOIN sys.columns col
ON [constraint].parent_object_id = col.object_id
INNER JOIN sys.tables st
ON [constraint].parent_object_id = st.object_id
WHERE
st.name = #TableName
AND col.name IN ('ForceUpdateOnImport', 'ForceUpdateOnExport')
AND col.column_id = [constraint].parent_column_id
SELECT * FROM #ConstraintNames
DECLARE #i INT = 1,
#count INT,
#constraintName VARCHAR(MAX),
#sql VARCHAR(MAX)
SELECT #count = COUNT(1) FROM #ConstraintNames
WHILE #i <= #count
BEGIN
SELECT #constraintName = cn.Name FROM #ConstraintNames cn WHERE cn.RowNum = #i
SET #sql = 'ALTER TABLE ' + #TableName + ' DROP CONSTRAINT ' + #constraintName
EXEC (#sql)
SET #i = #i + 1
END

Below is helpful for check and default constraints. I use it for implicit constraints to offer up guidance for what the name should be. If you remove everything after the where clause, it should be good for any check/default constraints.
SELECT /* obj_table.NAME AS 'table',
columns.NAME AS 'column',
obj_Constraint.NAME AS 'constraint',
obj_Constraint.type AS 'type',
sss.name as 'schema',*/
'ALTER TABLE [' + ltrim(rtrim(sss.name))+'].['+ltrim(rtrim(obj_table.name)) + '] DROP CONSTRAINT [' + obj_Constraint.NAME + '];' As 'Wrong_Implicit_Constraint',
'ALTER TABLE [' + ltrim(rtrim(sss.name))+'].['+ltrim(rtrim(obj_table.name)) + '] ADD CONSTRAINT [' + CASE obj_Constraint.type
WHEN 'D' THEN 'DF' WHEN 'F' THEN 'FK'
WHEN 'U' THEN 'UX' WHEN 'PK' THEN 'PK' WHEN 'N' THEN 'NN' WHEN 'C' THEN 'CK'
END + '_' + ltrim(rtrim(obj_table.name)) + '_' + columns.NAME + ']' +
CASE obj_Constraint.type WHEN 'D' THEN ' DEFAULT (' + dc.definition +') FOR [' + columns.NAME + ']'
WHEN 'C' THEN ' CHECK (' + cc.definition +')'
ELSE '' END +
';' As 'Right_Explicit_Constraint'
FROM sys.objects obj_table
JOIN sys.objects obj_Constraint ON obj_table.object_id = obj_Constraint.parent_object_id
JOIN sys.sysconstraints constraints ON constraints.constid = obj_Constraint.object_id
JOIN sys.columns columns ON columns.object_id = obj_table.object_id
AND columns.column_id = constraints.colid
left join sys.schemas sss on obj_Constraint.schema_id=sss.schema_id
left join sys.default_constraints dc on dc.object_id = obj_Constraint.object_id
left join sys.check_constraints cc on cc.object_id = obj_Constraint.object_id
WHERE obj_Constraint.type_desc LIKE '%CONSTRAINT'
AND RIGHT(obj_Constraint.name,10) LIKE '[_][_]________' --match double underscore + 8 chars of anything
AND RIGHT(obj_Constraint.name,8) LIKE '%[A-Z]%' --Ensure alpha in last 8
AND RIGHT(obj_Constraint.name,8) LIKE '%[0-9]%' --Ensure numeric in last 8
AND RIGHT(obj_Constraint.name,8) not LIKE '%[^0-9A-Z]%' --Ensure no special chars

Related

Return a count of all foreign keys across all tables in database without a cursor

I need to return a count of a particular foreign key across all tables in a database given a table name, column name, and an id.
So if the passed in parameters are TableName, ColumnName, RecordID, I would need to look at all tables that have that column as a foreign key and return the count of all RecordID's that match.
I can see how to do it with a cursor and dynamic sql, but I'd like to figure out something a bit more elegant as it were.
I guess I really just need someone smarter than me to tell me you can or can't do it.
EDIT
Output should be something like:
Count of ID 1 in OtherTable is 5
Count of ID 1 in OtherTable2 is 10
So you could pass in any table name and record ID and have it return counts for each referenced table
EDIT 2. I think there should be a better answer than this, but here's what I came up with. It does use dynamic sql, but no cursors at least. (It uses adventureworks)
DECLARE #RecID AS INT = 1
DECLARE #TableName AS VARCHAR(255) = 'Product'
CREATE TABLE #temp
(
tablename VARCHAR(255),
ColumnName VARCHAR(255),
sqlStatment VARCHAR(max),
IDCount INT
)
INSERT INTO #temp
(tablename,
ColumnName,
sqlStatment)
SELECT Object_schema_name(f.parent_object_id)
+ '.' + Object_name(f.parent_object_id) AS TableName,
Col_name(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
'update #Temp set IDCount = (select count(*) from '
+ Object_schema_name(f.parent_object_id)
+ '.' + Object_name(f.parent_object_id)
+ ' where '
+ Col_name(fc.parent_object_id, fc.parent_column_id)
+ ' = ' + CONVERT(VARCHAR, #RecID)
+ ') where tablename = '''
+ Object_schema_name(f.parent_object_id)
+ '.' + Object_name(f.parent_object_id) + ''';'
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
WHERE Object_name(f.referenced_object_id) = #TableName
DECLARE #sql AS VARCHAR(max) = ''
SELECT #sql = #Sql + sqlStatment
FROM #temp
EXEC (#sql)
SELECT *
FROM #temp
DROP TABLE #temp
I think this is what you want :
SELECT COUNT(*)
FROM sys.foreign_key_columns AS fk
JOIN sys.tables AS t ON fk.parent_object_id = t.object_id
JOIN sys.columns AS c ON fk.parent_object_id = c.object_id AND fk.parent_column_id = c.column_id
WHERE fk.referenced_object_id = (SELECT object_id FROM sys.tables WHERE name = 'TableThatContainsTheKey');
I hope this helps:
use yourdatabase
select count(*) from sysobjects where xtype='F'
(Edit: sorry, I meant 'F'. 'PK' is for primary keys.)

Drop default constraint in SQL Server on many columns

For SQL Server 2008 R2 I want to remove default constraints for date columns that allow null and the constraint contains 1899. And I want a script that can tested and then executed in live. I don't wan't to fiddle with this in live environment. Another reason for a script is that there is several databases with the same scheme
With help from Google I have the following script that list columns
SELECT tables.name, all_columns.name, all_columns.is_nullable, default_constraints.name, default_constraints.definition
FROM
sys.all_columns
INNER JOIN
sys.tables
ON all_columns.object_id = tables.object_id
INNER JOIN
sys.schemas
ON tables.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
and default_constraints.definition like '%1899%'
and all_columns.is_nullable = 1
order by tables.name, all_columns.name, default_constraints.name
Now this list over hundred columns. The next script do what I want for the column CargoPool.Created. But how can I iterate all rows created from my first script ?
DECLARE #tableName VARCHAR(MAX) = 'CargoPool'
DECLARE #columnName VARCHAR(MAX) = 'Created'
DECLARE #ConstraintName nvarchar(200)
SELECT #ConstraintName = Name
FROM SYS.DEFAULT_CONSTRAINTS
WHERE PARENT_OBJECT_ID = OBJECT_ID(#tableName)
AND PARENT_COLUMN_ID = (
SELECT column_id FROM sys.columns
WHERE NAME = #columnName AND object_id = OBJECT_ID(#tableName))
IF #ConstraintName IS NOT NULL
EXEC('ALTER TABLE '+#tableName+' DROP CONSTRAINT ' + #ConstraintName)
If you want to drop all the constraints from your first query, you can build up a dynamic SQL with the results of that query and then execute it:
DECLARE #sql AS NVARCHAR(MAX) = N''
SELECT #sql = #sql + N'ALTER TABLE '
+ QUOTENAME(schemas.name) + N'.' + QUOTENAME(tables.name)
+ N' DROP CONSTRAINT ' + QUOTENAME(default_constraints.name) + N'; '
FROM
sys.all_columns
INNER JOIN
sys.tables
ON all_columns.object_id = tables.object_id
INNER JOIN
sys.schemas
ON tables.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = N'dbo'
and default_constraints.definition like N'%1899%'
and all_columns.is_nullable = 1
order by tables.name, all_columns.name, default_constraints.name
exec sp_executesql #sql;

Know relationships between all the tables of database in SQL Server

I wish to all know how the tables in my database are related to each other (i.e PK/FK/UK) and hence i created a database diagram of all my tables in SQL Server. The diagram that was created was not easily readable and had to scroll (horizontally and sometimes vertically) to see the table on the other end.
In short SQL's db diagram are not UI friendly when it comes to knowing relationships between many tables.
My (simple) Question: Is there something like database diagram which can do what db diagram did but in "good" way?
Sometimes, a textual representation might also help; with this query on the system catalog views, you can get a list of all FK relationships and how the link two tables (and what columns they operate on).
SELECT
fk.name 'FK Name',
tp.name 'Parent table',
cp.name, cp.column_id,
tr.name 'Refrenced table',
cr.name, cr.column_id
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
Dump this into Excel, and you can slice and dice - based on the parent table, the referenced table or anything else.
I find visual guides helpful - but sometimes, textual documentation is just as good (or even better) - just my 2 cents.....
Just another way to retrieve the same data using INFORMATION_SCHEMA
The information schema views included in SQL Server comply with the ISO standard definition for the INFORMATION_SCHEMA.
sqlauthority way
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:
ORDER BY
1,2,3,4
WHERE PK.TABLE_NAME='something'WHERE FK.TABLE_NAME='something'
WHERE PK.TABLE_NAME IN ('one_thing', 'another')
WHERE FK.TABLE_NAME IN ('one_thing', 'another')
Or you can look at schemacrawler
This stored procedure will provide you with a hierarchical tree of relationship. Based on this article from Technet. It will also optionally provide you a query for reading or deleting all the related data.
IF OBJECT_ID('GetForeignKeyRelations','P') IS NOT NULL
DROP PROC GetForeignKeyRelations
GO
CREATE PROC GetForeignKeyRelations
#Schemaname Sysname = 'dbo'
,#Tablename Sysname
,#WhereClause NVARCHAR(2000) = ''
,#GenerateDeleteScripts bit = 0
,#GenerateSelectScripts bit = 0
AS
SET NOCOUNT ON
DECLARE #fkeytbl TABLE
(
ReferencingObjectid int NULL
,ReferencingSchemaname Sysname NULL
,ReferencingTablename Sysname NULL
,ReferencingColumnname Sysname NULL
,PrimarykeyObjectid int NULL
,PrimarykeySchemaname Sysname NULL
,PrimarykeyTablename Sysname NULL
,PrimarykeyColumnname Sysname NULL
,Hierarchy varchar(max) NULL
,level int NULL
,rnk varchar(max) NULL
,Processed bit default 0 NULL
);
WITH fkey (ReferencingObjectid,ReferencingSchemaname,ReferencingTablename,ReferencingColumnname
,PrimarykeyObjectid,PrimarykeySchemaname,PrimarykeyTablename,PrimarykeyColumnname,Hierarchy,level,rnk)
AS
(
SELECT
soc.object_id
,scc.name
,soc.name
,convert(sysname,null)
,convert(int,null)
,convert(sysname,null)
,convert(sysname,null)
,convert(sysname,null)
,CONVERT(VARCHAR(MAX), scc.name + '.' + soc.name ) as Hierarchy
,0 as level
,rnk=convert(varchar(max),soc.object_id)
FROM SYS.objects soc
JOIN sys.schemas scc
ON soc.schema_id = scc.schema_id
WHERE scc.name =#Schemaname
AND soc.name =#Tablename
UNION ALL
SELECT sop.object_id
,scp.name
,sop.name
,socp.name
,soc.object_id
,scc.name
,soc.name
,socc.name
,CONVERT(VARCHAR(MAX), f.Hierarchy + ' --> ' + scp.name + '.' + sop.name ) as Hierarchy
,f.level+1 as level
,rnk=f.rnk + '-' + convert(varchar(max),sop.object_id)
FROM SYS.foreign_key_columns sfc
JOIN Sys.Objects sop
ON sfc.parent_object_id = sop.object_id
JOIN SYS.columns socp
ON socp.object_id = sop.object_id
AND socp.column_id = sfc.parent_column_id
JOIN sys.schemas scp
ON sop.schema_id = scp.schema_id
JOIN SYS.objects soc
ON sfc.referenced_object_id = soc.object_id
JOIN SYS.columns socc
ON socc.object_id = soc.object_id
AND socc.column_id = sfc.referenced_column_id
JOIN sys.schemas scc
ON soc.schema_id = scc.schema_id
JOIN fkey f
ON f.ReferencingObjectid = sfc.referenced_object_id
WHERE ISNULL(f.PrimarykeyObjectid,0) <> f.ReferencingObjectid
)
INSERT INTO #fkeytbl
(ReferencingObjectid,ReferencingSchemaname,ReferencingTablename,ReferencingColumnname
,PrimarykeyObjectid,PrimarykeySchemaname,PrimarykeyTablename,PrimarykeyColumnname,Hierarchy,level,rnk)
SELECT ReferencingObjectid,ReferencingSchemaname,ReferencingTablename,ReferencingColumnname
,PrimarykeyObjectid,PrimarykeySchemaname,PrimarykeyTablename,PrimarykeyColumnname,Hierarchy,level,rnk
FROM fkey
SELECT F.Relationshiptree
FROM
(
SELECT DISTINCT Replicate('------',Level) + CASE LEVEL WHEN 0 THEN '' ELSE '>' END + ReferencingSchemaname + '.' + ReferencingTablename 'Relationshiptree'
,RNK
FROM #fkeytbl
) F
ORDER BY F.rnk ASC
-------------------------------------------------------------------------------------------------------------------------------
-- Generate the Delete / Select script
-------------------------------------------------------------------------------------------------------------------------------
DECLARE #Sql VARCHAR(MAX)
DECLARE #RnkSql VARCHAR(MAX)
DECLARE #Jointables TABLE
(
ID INT IDENTITY
,Object_id int
)
DECLARE #ProcessTablename SYSNAME
DECLARE #ProcessSchemaName SYSNAME
DECLARE #JoinConditionSQL VARCHAR(MAX)
DECLARE #Rnk VARCHAR(MAX)
DECLARE #OldTablename SYSNAME
IF #GenerateDeleteScripts = 1 or #GenerateSelectScripts = 1
BEGIN
WHILE EXISTS ( SELECT 1
FROM #fkeytbl
WHERE Processed = 0
AND level > 0 )
BEGIN
SELECT #ProcessTablename = ''
SELECT #Sql = ''
SELECT #JoinConditionSQL = ''
SELECT #OldTablename = ''
SELECT TOP 1 #ProcessTablename = ReferencingTablename
,#ProcessSchemaName = ReferencingSchemaname
,#Rnk = RNK
FROM #fkeytbl
WHERE Processed = 0
AND level > 0
ORDER BY level DESC
SELECT #RnkSql ='SELECT ' + REPLACE (#rnk,'-',' UNION ALL SELECT ')
DELETE FROM #Jointables
INSERT INTO #Jointables
EXEC(#RnkSql)
IF #GenerateDeleteScripts = 1
SELECT #Sql = 'DELETE [' + #ProcessSchemaName + '].[' + #ProcessTablename + ']' + CHAR(10) + ' FROM [' + #ProcessSchemaName + '].[' + #ProcessTablename + ']' + CHAR(10)
IF #GenerateSelectScripts = 1
SELECT #Sql = 'SELECT [' + #ProcessSchemaName + '].[' + #ProcessTablename + '].*' + CHAR(10) + ' FROM [' + #ProcessSchemaName + '].[' + #ProcessTablename + ']' + CHAR(10)
SELECT #JoinConditionSQL = #JoinConditionSQL
+ CASE
WHEN #OldTablename <> f.PrimarykeyTablename THEN 'JOIN [' + f.PrimarykeySchemaname + '].[' + f.PrimarykeyTablename + '] ' + CHAR(10) + ' ON '
ELSE ' AND '
END
+ ' [' + f.PrimarykeySchemaname + '].[' + f.PrimarykeyTablename + '].[' + f.PrimarykeyColumnname + '] = [' + f.ReferencingSchemaname + '].[' + f.ReferencingTablename + '].[' + f.ReferencingColumnname + ']' + CHAR(10)
, #OldTablename = CASE
WHEN #OldTablename <> f.PrimarykeyTablename THEN f.PrimarykeyTablename
ELSE #OldTablename
END
FROM #fkeytbl f
JOIN #Jointables j
ON f.Referencingobjectid = j.Object_id
WHERE charindex(f.rnk + '-',#Rnk + '-') <> 0
AND F.level > 0
ORDER BY J.ID DESC
SELECT #Sql = #Sql + #JoinConditionSQL
IF LTRIM(RTRIM(#WhereClause)) <> ''
SELECT #Sql = #Sql + ' WHERE (' + #WhereClause + ')'
PRINT #SQL
PRINT CHAR(10)
UPDATE #fkeytbl
SET Processed = 1
WHERE ReferencingTablename = #ProcessTablename
AND rnk = #Rnk
END
IF #GenerateDeleteScripts = 1
SELECT #Sql = 'DELETE FROM [' + #Schemaname + '].[' + #Tablename + ']'
IF #GenerateSelectScripts = 1
SELECT #Sql = 'SELECT * FROM [' + #Schemaname + '].[' + #Tablename + ']'
IF LTRIM(RTRIM(#WhereClause)) <> ''
SELECT #Sql = #Sql + ' WHERE ' + #WhereClause
PRINT #SQL
END
SET NOCOUNT OFF
go
Microsoft Visio is probably the best I've came across, although as far as I know it won't automatically generate based on your relationships.
EDIT: try this in Visio, could give you what you need http://office.microsoft.com/en-us/visio-help/reverse-engineering-an-existing-database-HA001182257.aspx
My solution is based on #marc_s solution, i just concatenated columns in cases that a constraint is based on more than one column:
SELECT
FK.[name] AS ForeignKeyConstraintName
,SCHEMA_NAME(FT.schema_id) + '.' + FT.[name] AS ForeignTable
,STUFF(ForeignColumns.ForeignColumns, 1, 2, '') AS ForeignColumns
,SCHEMA_NAME(RT.schema_id) + '.' + RT.[name] AS ReferencedTable
,STUFF(ReferencedColumns.ReferencedColumns, 1, 2, '') AS ReferencedColumns
FROM
sys.foreign_keys FK
INNER JOIN sys.tables FT
ON FT.object_id = FK.parent_object_id
INNER JOIN sys.tables RT
ON RT.object_id = FK.referenced_object_id
CROSS APPLY
(
SELECT
', ' + iFC.[name] AS [text()]
FROM
sys.foreign_key_columns iFKC
INNER JOIN sys.columns iFC
ON iFC.object_id = iFKC.parent_object_id
AND iFC.column_id = iFKC.parent_column_id
WHERE
iFKC.constraint_object_id = FK.object_id
ORDER BY
iFC.[name]
FOR XML PATH('')
) ForeignColumns (ForeignColumns)
CROSS APPLY
(
SELECT
', ' + iRC.[name]AS [text()]
FROM
sys.foreign_key_columns iFKC
INNER JOIN sys.columns iRC
ON iRC.object_id = iFKC.referenced_object_id
AND iRC.column_id = iFKC.referenced_column_id
WHERE
iFKC.constraint_object_id = FK.object_id
ORDER BY
iRC.[name]
FOR XML PATH('')
) ReferencedColumns (ReferencedColumns)
If you have LINQPad (it's free), this script I just wrote will list every possible path between every table in your database.
Given the following database:
...the script will produce the following output:
Or you can set the longestOnly flag at the top of the script, and it will just output the longest paths:
And here's the script:
var longestOnly = true;
var pathLists = new List<List<string>>();
foreach (var table in Mapping.GetTables()) {
var subPaths = new List<string>();
pathLists.Add(subPaths);
subPaths.Add(table.TableName);
Go(table, subPaths);
}
var pathStrings = pathLists
.Select(p => string.Join(", ", p))
.Distinct()
.OrderBy(p => p)
.ToList();
if (longestOnly) {
pathStrings.RemoveAll(z => pathStrings.Any(i => i != z && i.Contains(z)));
} else {
pathStrings.RemoveAll(z => pathStrings.Any(i => i != z && i.StartsWith(z)));
}
pathStrings.Dump();
void Go(System.Data.Linq.Mapping.MetaTable table, List<string> paths)
{
foreach (var association in table.RowType.Associations) {
var subPaths = paths.Concat(new List<string>()).ToList(); // create a copy
pathLists.Add(subPaths);
var subPathTableName = association.OtherType.Table.TableName;
if (!subPaths.Contains(subPathTableName)) {
subPaths.Add(subPathTableName);
var subPathTable = Mapping.GetTable(association.OtherMember.DeclaringType.Type);
if (subPathTable != null) {
Go(subPathTable, subPaths);
}
}
}
}
For a complex database, this can take a surprisingly long time to complete, and will return a surprisingly large list of results. I needed to write this for work, and the end result left me feeling pretty defeated. :)
I couldn't find anything else that would do this, so I'm pretty happy with it, though.
All suggestions thus far have shown relationships between entities via primary and foreign keys. Occasionally, it may be useful to also identify relationships via dependencies. I found the need for this to identify the relationships between views and tables when building network graph visualizations.
select distinct
v.name as referencer_name,
V.type_desc as referencer_type,
o.name as referenced_entity_name,
o.type_desc as referenced_entity_type
from sys.views v
join sys.sql_expression_dependencies d
on d.referencing_id = v.object_id
and d.referenced_id is not null
join sys.objects o
on o.object_id = d.referenced_id
order by referencer_name;
The above code results in the following table:
This can be further extended, using python, to generate network graphs to visually see linkages.
select * from information_schema.REFERENTIAL_CONSTRAINTS where
UNIQUE_CONSTRAINT_SCHEMA = 'SCHEMA_NAME'
This will list the constraints with SCHEMA_NAMEenter image description here

SQL Server: how to know if any row is referencing the row to delete

You cannot delete a row if any row is referencing the row to delete via a FK.
Is it possible to know if any row is referencing the row to delete before executing a DELETE statement?
This script will show all the tables that have rows that reference the row you are trying to delete:
declare #RowId int = 1
declare #TableName sysname = 'ParentTable'
declare #Command varchar(max)
select #Command = isnull(#Command + ' union all ', '') + 'select ''' + object_name(parent_object_id) +
''' where exists(select * from ' + object_name(parent_object_id) + ' where ' + col.name+ ' = ' + cast(#RowId as varchar) + ')'
from sys.foreign_key_columns fkc
join sys.columns col on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
where object_name(referenced_object_id) = #TableName
execute (#Command)
Assumption that foreign key is not composite.
Option 1 (Detection):
You perform a Select Statement to determine if any records are referencing the Record-to-be-deleted -- and, if you wish, manually delete those records that do reference it. This can also be accomplished using a trigger, although I recommend against triggers, because they tend to surprise people (and yourself) down the road.
Option 2 (Automation):
You can look into Cascading Deletes which, if configured correctly, will cause all records referencing the Record-to-be-deleted to also be deleted.
When to use Cascading Deletes (Paraphrased from text written by Joel Coehoorn)
Cascade Delete may make sense when the semantics of the relationship can involve an "is part of" description. Example: Web Order, Web Order Line Items
You should not use Cascade Delete if you are preserving history or using a soft delete where you only set a deleted bit column
Cascading can get you into trouble if you set up your foreign keys wrong.
It's not wise to use cascading before you understand it thoroughly. However, it is a useful feature and therefore worth taking the time to understand.
Here's a great discussion on Cascading Deletes on stackoverflow.
nobody has mentioned it, but just for the record I use a lot the procedure
sp_helpconstraint 'dbo.mytable'
in order to find all the constraints related to dbo.mytable, and which tables reference dbo.mytable.
I find it very useful and handy.
I improved the Alex Aza's solution.
I use softdelete, so It's necessary add a column "delete" in the condition "where" .
And more I made a function in TSQL that it discovers when the table represents the object inherited in NHibernate, and the PK is the FK from parent table.
Follow:
declare #RowId int = 4
declare #TableName sysname = 'TABLE'
declare #Command varchar(max)
select #Command = isnull(#Command + ' union all ', '') + 'select ''' + object_name(parent_object_id) +
''' where exists(select * from ' + object_name(parent_object_id) +
CASE
WHEN EXISTS(select object_name(object_id) from sys.columns col where name = 'deleted' and object_id = parent_object_id)
THEN ' where ' + col.name+ ' = ' + cast(#RowId as varchar) +' and deleted = 0 '
when dbo.ParentIdFromTable(object_name(parent_object_id)) <> ''
then ' inner join ' + dbo.ParentIdFromTable(object_name(parent_object_id)) + ' on id = ' + dbo.PrimaryKey(object_name(parent_object_id))
+' where ' + col.name+ ' = ' + cast(#RowId as varchar) +' and deleted = 0 '
else
' where ' + col.name+ ' = ' + cast(#RowId as varchar)
END
+ ')'
from sys.foreign_key_columns fkc
join sys.columns col on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
where object_name(referenced_object_id) = #TableName
PRINT #Command
execute (#Command)
Depedencies Functions:
CREATE FUNCTION dbo.ParentIdFromTable(#Table varchar(255))
RETURNS varchar(255)
AS
BEGIN
declare #tableParent varchar(255) = ''
if exists(select pk.TABLE_NAME, pk.COLUMN_NAME, col.name, object_name(referenced_object_id) Referenced, object_name(parent_object_id) as Parent
from sys.columns col
inner join sys.foreign_key_columns fkc on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on
pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = #table)
begin
while exists(select *
from sys.columns col
inner join sys.foreign_key_columns fkc on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on
pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1 AND table_name = #table)
begin
-- Descobrir o parent, column
select #tableParent = object_name(referenced_object_id)
from sys.columns col
inner join sys.foreign_key_columns fkc on
fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on
pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = #table
--print #tableParent
set #table = #tableParent
end
end
return #tableParent;
END;
GO
CREATE FUNCTION dbo.PrimaryKey(#Table varchar(255))
RETURNS varchar(255)
AS
BEGIN
declare #columnName varchar(255) = ''
-- Descobrir o parent, column
select #columnName = COLUMN_NAME
from INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = #Table
return #columnName
end;

What is the equivalent of 'describe table' in SQL Server?

I have a SQL Server database and I want to know what columns and types it has. I'd prefer to do this through a query rather than using a GUI like Enterprise Manager. Is there a way to do this?
You can use the sp_columns stored procedure:
exec sp_columns MyTable
There are a few methods to get metadata about a table:
EXEC sp_help tablename
Will return several result sets, describing the table, it's columns and constraints.
The INFORMATION_SCHEMA views will give you the information you want, though unfortunately you have to query the views and join them manually.
Just in case you don't want to use stored proc, here's a simple query version
select *
from information_schema.columns
where table_name = 'aspnet_Membership'
order by ordinal_position
You can use following: sp_help tablename
Example: sp_help Customer
OR Use Shortcut Keys
Select the desired table and press ALT+F1.
Example: Customer Press ALT+F1.
Use this Query
Select * From INFORMATION_SCHEMA.COLUMNS Where TABLE_NAME = 'TABLENAME'
In addition to the ways shown in other answers, you can use
SELECT TOP 0 * FROM table_name
This will give you the name of each column with no results in them, and completes almost instantly with minimal overhead.
Please use the following sql query; this worked for my case.
select * FROM INFORMATION_SCHEMA.Columns where table_name = 'tablename';
Just select table and press Alt+F1,
it will show all the information about table like Column name, datatype, keys etc.
The SQL Server equivalent to Oracle's describe command is the stored proc sp_help
The describe command gives you the information about the column names, types, length, etc.
In SQL Server, let's say you want to describe a table 'mytable' in schema 'myschema' in the database 'mydb', you can do following:
USE mydb;
exec sp_help 'myschema.mytable';
I wrote an sql*plus DESC(RIBE) like select (displays the column comments, too) in t-sql:
USE YourDB
GO
DECLARE #objectName NVARCHAR(128) = 'YourTable';
SELECT
a.[NAME]
,a.[TYPE]
,a.[CHARSET]
,a.[COLLATION]
,a.[NULLABLE]
,a.[DEFAULT]
,b.[COMMENTS]
-- ,a.[ORDINAL_POSITION]
FROM
(
SELECT
COLUMN_NAME AS [NAME]
,CASE DATA_TYPE
WHEN 'char' THEN DATA_TYPE + '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + ')'
WHEN 'numeric' THEN DATA_TYPE + '(' + CAST(NUMERIC_PRECISION AS VARCHAR) + ', ' + CAST(NUMERIC_SCALE AS VARCHAR) + ')'
WHEN 'nvarchar' THEN DATA_TYPE + '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + ')'
WHEN 'varbinary' THEN DATA_TYPE + '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + ')'
WHEN 'varchar' THEN DATA_TYPE + '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + ')'
ELSE DATA_TYPE
END AS [TYPE]
,CHARACTER_SET_NAME AS [CHARSET]
,COLLATION_NAME AS [COLLATION]
,IS_NULLABLE AS [NULLABLE]
,COLUMN_DEFAULT AS [DEFAULT]
,ORDINAL_POSITION
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #objectName
) a
FULL JOIN
(
SELECT
CAST(value AS NVARCHAR) AS [COMMENTS]
,CAST(objname AS NVARCHAR) AS [NAME]
FROM
::fn_listextendedproperty ('MS_Description', 'user', 'dbo', 'table', #objectName, 'column', default)
) b
ON a.NAME COLLATE YourCollation = b.NAME COLLATE YourCollation
ORDER BY
a.[ORDINAL_POSITION];
The above mentioned select can be used in a system marked stored procedure and it can be called from any database of your instance on a simple way:
USE master;
GO
IF OBJECT_ID('sp_desc', 'P') IS NOT NULL
DROP PROCEDURE sp_desc
GO
CREATE PROCEDURE sp_desc (
#tableName nvarchar(128)
) AS
BEGIN
DECLARE #dbName sysname;
DECLARE #schemaName sysname;
DECLARE #objectName sysname;
DECLARE #objectID int;
DECLARE #tmpTableName varchar(100);
DECLARE #sqlCmd nvarchar(4000);
SELECT #dbName = PARSENAME(#tableName, 3);
IF #dbName IS NULL SELECT #dbName = DB_NAME();
SELECT #schemaName = PARSENAME(#tableName, 2);
IF #schemaName IS NULL SELECT #schemaName = SCHEMA_NAME();
SELECT #objectName = PARSENAME(#tableName, 1);
IF #objectName IS NULL
BEGIN
PRINT 'Object is missing from your function call!';
RETURN;
END;
SELECT #objectID = OBJECT_ID(#dbName + '.' + #schemaName + '.' + #objectName);
IF #objectID IS NULL
BEGIN
PRINT 'Object [' + #dbName + '].[' + #schemaName + '].[' + #objectName + '] does not exist!';
RETURN;
END;
SELECT #tmpTableName = '#tmp_DESC_' + CAST(##SPID AS VARCHAR) + REPLACE(REPLACE(REPLACE(REPLACE(CAST(CONVERT(CHAR, GETDATE(), 121) AS VARCHAR), '-', ''), ' ', ''), ':', ''), '.', '');
--PRINT #tmpTableName;
SET #sqlCmd = '
USE ' + #dbName + '
CREATE TABLE ' + #tmpTableName + ' (
[NAME] nvarchar(128) NOT NULL
,[TYPE] varchar(50)
,[CHARSET] varchar(50)
,[COLLATION] varchar(50)
,[NULLABLE] varchar(3)
,[DEFAULT] nvarchar(4000)
,[COMMENTS] nvarchar(3750));
INSERT INTO ' + #tmpTableName + '
SELECT
a.[NAME]
,a.[TYPE]
,a.[CHARSET]
,a.[COLLATION]
,a.[NULLABLE]
,a.[DEFAULT]
,b.[COMMENTS]
FROM
(
SELECT
COLUMN_NAME AS [NAME]
,CASE DATA_TYPE
WHEN ''char'' THEN DATA_TYPE + ''('' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + '')''
WHEN ''numeric'' THEN DATA_TYPE + ''('' + CAST(NUMERIC_PRECISION AS VARCHAR) + '', '' + CAST(NUMERIC_SCALE AS VARCHAR) + '')''
WHEN ''nvarchar'' THEN DATA_TYPE + ''('' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + '')''
WHEN ''varbinary'' THEN DATA_TYPE + ''('' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + '')''
WHEN ''varchar'' THEN DATA_TYPE + ''('' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + '')''
ELSE DATA_TYPE
END AS [TYPE]
,CHARACTER_SET_NAME AS [CHARSET]
,COLLATION_NAME AS [COLLATION]
,IS_NULLABLE AS [NULLABLE]
,COLUMN_DEFAULT AS [DEFAULT]
,ORDINAL_POSITION
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = ''' + #objectName + '''
) a
FULL JOIN
(
SELECT
CAST(value AS NVARCHAR) AS [COMMENTS]
,CAST(objname AS NVARCHAR) AS [NAME]
FROM
::fn_listextendedproperty (''MS_Description'', ''user'', ''' + #schemaName + ''', ''table'', ''' + #objectName + ''', ''column'', default)
) b
ON a.NAME COLLATE Hungarian_CI_AS = b.NAME COLLATE Hungarian_CI_AS
ORDER BY
a.[ORDINAL_POSITION];
SELECT * FROM ' + #tmpTableName + ';'
--PRINT #sqlCmd;
EXEC sp_executesql #sqlCmd;
RETURN;
END;
GO
EXEC sys.sp_MS_marksystemobject sp_desc
GO
To execute the procedure type:
EXEC sp_desc 'YourDB.YourSchema.YourTable';
If you want to get a description an object of the current database (and schema) simple type:
EXEC sp_desc 'YourTable';
As sp_desc is a system marked procedure, you can even leave the exec command, too (not recommended anyway):
sp_desc 'YourTable';
You can use the sp_help 'TableName'
try it:
EXEC [ServerName].[DatabaseName].dbo.sp_columns 'TableName'
and you can get some table structure information, such as:
TABLE_QUALIFIER, TABLE_OWNER, TABLE_NAME, COLUMN_NAME, DATA_TYPE, TYPE_NAME...
In addition to above questions, if we have table in DB like db_name.dbo.table_name, we may use following steps
Connect with DB
USE db_name;
Use EXEC sp_help and don't forget to put table name as 'dbo.tablename' if you have dbo as schema.
exec sp_help 'dbo.table_name'
This should work!
I tried this and it's working for me
exec sp_help TABLE_NAME
First connect to your DB,
use DB_name
Then
exec sp_help 'Production.Et_Issue'
here 'production' is the schema name. If you dont have a schema,
you may simply write sp_help table_name
The problem with those answers is that you're missing the key info.
While this is a bit messy this is a quick version I came up with to make sure it contains the same info the MySQL Describe displays.
Select SC.name AS 'Field', ISC.DATA_TYPE AS 'Type', ISC.CHARACTER_MAXIMUM_LENGTH AS 'Length', SC.IS_NULLABLE AS 'Null', I.is_primary_key AS 'Key', SC.is_identity AS 'Identity'
From sys.columns AS SC
LEFT JOIN sys.index_columns AS IC
ON IC.object_id = OBJECT_ID('dbo.Expenses') AND
IC.column_id = SC.column_id
LEFT JOIN sys.indexes AS I
ON I.object_id = OBJECT_ID('dbo.Expenses') AND
IC.index_id = I.index_id
LEFT JOIN information_schema.columns ISC
ON ISC.TABLE_NAME = 'Expenses'
AND ISC.COLUMN_NAME = SC.name
WHERE SC.object_id = OBJECT_ID('dbo.Expenses')
This is the code I use within the EntityFramework Reverse POCO Generator (available here)
Table SQL:
SELECT c.TABLE_SCHEMA AS SchemaName,
c.TABLE_NAME AS TableName,
t.TABLE_TYPE AS TableType,
c.ORDINAL_POSITION AS Ordinal,
c.COLUMN_NAME AS ColumnName,
CAST(CASE WHEN IS_NULLABLE = 'YES' THEN 1
ELSE 0
END AS BIT) AS IsNullable,
DATA_TYPE AS TypeName,
ISNULL(CHARACTER_MAXIMUM_LENGTH, 0) AS [MaxLength],
CAST(ISNULL(NUMERIC_PRECISION, 0) AS INT) AS [Precision],
ISNULL(COLUMN_DEFAULT, '') AS [Default],
CAST(ISNULL(DATETIME_PRECISION, 0) AS INT) AS DateTimePrecision,
ISNULL(NUMERIC_SCALE, 0) AS Scale,
CAST(COLUMNPROPERTY(OBJECT_ID(QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME)), c.COLUMN_NAME, 'IsIdentity') AS BIT) AS IsIdentity,
CAST(CASE WHEN COLUMNPROPERTY(OBJECT_ID(QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME)), c.COLUMN_NAME, 'IsIdentity') = 1 THEN 1
WHEN COLUMNPROPERTY(OBJECT_ID(QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME)), c.COLUMN_NAME, 'IsComputed') = 1 THEN 1
WHEN DATA_TYPE = 'TIMESTAMP' THEN 1
ELSE 0
END AS BIT) AS IsStoreGenerated,
CAST(CASE WHEN pk.ORDINAL_POSITION IS NULL THEN 0
ELSE 1
END AS BIT) AS PrimaryKey,
ISNULL(pk.ORDINAL_POSITION, 0) PrimaryKeyOrdinal,
CAST(CASE WHEN fk.COLUMN_NAME IS NULL THEN 0
ELSE 1
END AS BIT) AS IsForeignKey
FROM INFORMATION_SCHEMA.COLUMNS c
LEFT OUTER JOIN (SELECT u.TABLE_SCHEMA,
u.TABLE_NAME,
u.COLUMN_NAME,
u.ORDINAL_POSITION
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE u
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
ON u.TABLE_SCHEMA = tc.CONSTRAINT_SCHEMA
AND u.TABLE_NAME = tc.TABLE_NAME
AND u.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY') pk
ON c.TABLE_SCHEMA = pk.TABLE_SCHEMA
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.COLUMN_NAME = pk.COLUMN_NAME
LEFT OUTER JOIN (SELECT DISTINCT
u.TABLE_SCHEMA,
u.TABLE_NAME,
u.COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE u
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
ON u.TABLE_SCHEMA = tc.CONSTRAINT_SCHEMA
AND u.TABLE_NAME = tc.TABLE_NAME
AND u.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
WHERE CONSTRAINT_TYPE = 'FOREIGN KEY') fk
ON c.TABLE_SCHEMA = fk.TABLE_SCHEMA
AND c.TABLE_NAME = fk.TABLE_NAME
AND c.COLUMN_NAME = fk.COLUMN_NAME
INNER JOIN INFORMATION_SCHEMA.TABLES t
ON c.TABLE_SCHEMA = t.TABLE_SCHEMA
AND c.TABLE_NAME = t.TABLE_NAME
WHERE c.TABLE_NAME NOT IN ('EdmMetadata', '__MigrationHistory')
Foreign Key SQL:
SELECT FK.name AS FK_Table,
FkCol.name AS FK_Column,
PK.name AS PK_Table,
PkCol.name AS PK_Column,
OBJECT_NAME(f.object_id) AS Constraint_Name,
SCHEMA_NAME(FK.schema_id) AS fkSchema,
SCHEMA_NAME(PK.schema_id) AS pkSchema,
PkCol.name AS primarykey,
k.constraint_column_id AS ORDINAL_POSITION
FROM sys.objects AS PK
INNER JOIN sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS k
ON k.constraint_object_id = f.object_id
INNER JOIN sys.indexes AS i
ON f.referenced_object_id = i.object_id
AND f.key_index_id = i.index_id
ON PK.object_id = f.referenced_object_id
INNER JOIN sys.objects AS FK
ON f.parent_object_id = FK.object_id
INNER JOIN sys.columns AS PkCol
ON f.referenced_object_id = PkCol.object_id
AND k.referenced_column_id = PkCol.column_id
INNER JOIN sys.columns AS FkCol
ON f.parent_object_id = FkCol.object_id
AND k.parent_column_id = FkCol.column_id
ORDER BY FK_Table, FK_Column
Extended Properties:
SELECT s.name AS [schema],
t.name AS [table],
c.name AS [column],
value AS [property]
FROM sys.extended_properties AS ep
INNER JOIN sys.tables AS t
ON ep.major_id = t.object_id
INNER JOIN sys.schemas AS s
ON s.schema_id = t.schema_id
INNER JOIN sys.columns AS c
ON ep.major_id = c.object_id
AND ep.minor_id = c.column_id
WHERE class = 1
ORDER BY t.name
I like this format:
name DataType Collation Constraints PK FK Comment
id int NOT NULL IDENTITY PK Order Line Id
pid int NOT NULL tbl_orders Order Id
itemCode varchar(10) Latin1_General_CI_AS NOT NULL Product Code
So I have used this:
DECLARE #tname varchar(100) = 'yourTableName';
SELECT col.name,
CASE typ.name
WHEN 'nvarchar' THEN 'nvarchar('+CAST((col.max_length / 2) as varchar)+')'
WHEN 'varchar' THEN 'varchar('+CAST(col.max_length as varchar)+')'
WHEN 'char' THEN 'char('+CAST(col.max_length as varchar)+')'
WHEN 'nchar' THEN 'nchar('+CAST((col.max_length / 2) as varchar)+')'
WHEN 'binary' THEN 'binary('+CAST(col.max_length as varchar)+')'
WHEN 'varbinary' THEN 'varbinary('+CAST(col.max_length as varchar)+')'
WHEN 'numeric' THEN 'numeric('+CAST(col.precision as varchar)+(CASE WHEN col.scale = 0 THEN '' ELSE ','+CAST(col.scale as varchar) END) +')'
WHEN 'decimal' THEN 'decimal('+CAST(col.precision as varchar)+(CASE WHEN col.scale = 0 THEN '' ELSE ','+CAST(col.scale as varchar) END) +')'
ELSE typ.name
END DataType,
ISNULL(col.collation_name,'') Collation,
CASE WHEN col.is_nullable = 0 THEN 'NOT NULL ' ELSE '' END + CASE WHEN col.is_identity = 1 THEN 'IDENTITY' ELSE '' END Constraints,
ISNULL((SELECT 'PK'
FROM sys.key_constraints kc INNER JOIN
sys.tables tb ON tb.object_id = kc.parent_object_id INNER JOIN
sys.indexes si ON si.name = kc.name INNER JOIN
sys.index_columns sic ON sic.index_id = si.index_id AND sic.object_id = si.object_id
WHERE kc.type = 'PK'
AND tb.name = #tname
AND sic.column_id = col.column_id),'') PK,
ISNULL((SELECT (SELECT name FROM sys.tables st WHERE st.object_id = fkc.referenced_object_id)
FROM sys.foreign_key_columns fkc INNER JOIN
sys.columns c ON c.column_id = fkc.parent_column_id AND fkc.parent_object_id = c.object_id INNER JOIN
sys.tables t ON t.object_id = c.object_id
WHERE t.name = tab.name
AND c.name = col.name),'') FK,
ISNULL((SELECT value
FROM sys.extended_properties
WHERE major_id = tab.object_id
AND minor_id = col.column_id),'') Comment
FROM sys.columns col INNER JOIN
sys.tables tab ON tab.object_id = col.object_id INNER JOIN
sys.types typ ON typ.system_type_id = col.system_type_id
WHERE tab.name = #tname
AND typ.name != 'sysname'
ORDER BY col.column_id;
use
SELECT COL_LENGTH('tablename', 'colname')
None of other solution worked for me.
SELECT C.COLUMN_NAME, C.IS_NULLABLE, C.DATA_TYPE, TC.CONSTRAINT_TYPE, C.COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS AS C
FULL JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS CC ON C.COLUMN_NAME = CC.COLUMN_NAME
FULL JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC ON CC.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
WHERE C.TABLE_NAME = '<Table Name>';
Sample Output
If you are using FirstResponderKit from Brent Ozar team, you can run this query also:
exec sp_blitzindex #tablename='MyTable'
It will return all information about table:
indexes with their usage statistics(reads, writes, locks, etc), space
used and other
missing indexes
columns
foreign keys
statistics contents
Of course it's not a system and not so universal stp like sp_help or sp_columns, but it returns all possible information about your table and I think it's worth creating it at your environment and mentioning it here.
Just double click on the table name and press Alt+F1
CREATE PROCEDURE [dbo].[describe]
(
#SearchStr nvarchar(max)
)
AS
BEGIN
SELECT
CONCAT([COLUMN_NAME],' ',[DATA_TYPE],' ',[CHARACTER_MAXIMUM_LENGTH],' ',
(SELECT CASE [IS_NULLABLE] WHEN 'NO' THEN 'NOT NULL' ELSE 'NULL' END),
(SELECT CASE WHEN [COLUMN_DEFAULT] IS NULL THEN '' ELSE CONCAT(' DEFAULT ',[COLUMN_DEFAULT]) END)
) AS DESCRIPTION
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME LIKE #SearchStr
END
The query below will provide similar output as the info() function in python, Pandas library.
USE [Database_Name]
IF OBJECT_ID('tempdo.dob.#primary_key', 'U') IS NOT NULL DROP TABLE #primary_key
SELECT
CONS_T.TABLE_CATALOG,
CONS_T.TABLE_SCHEMA,
CONS_T.TABLE_NAME,
CONS_C.COLUMN_NAME,
CONS_T.CONSTRAINT_TYPE,
CONS_T.CONSTRAINT_NAME
INTO #primary_key
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS CONS_T
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS CONS_C ON CONS_C.CONSTRAINT_NAME= CONS_T.CONSTRAINT_NAME
SELECT
SMA.name AS [Schema Name],
ST.name AS [Table Name],
SC.column_id AS [Column Order],
SC.name AS [Column Name],
PKT.CONSTRAINT_TYPE,
PKT.CONSTRAINT_NAME,
SC.system_type_id,
STP.name AS [Data Type],
SC.max_length,
SC.precision,
SC.scale,
SC.is_nullable,
SC.is_masked
FROM sys.tables AS ST
JOIN sys.schemas AS SMA ON SMA.schema_id = ST.schema_id
JOIN sys.columns AS SC ON SC.object_id = ST.object_id
JOIN sys.types AS STP ON STP.system_type_id = SC.system_type_id
LEFT JOIN #primary_key AS PKT ON PKT.TABLE_SCHEMA = SMA.name
AND PKT.TABLE_NAME = ST.name
AND PKT.COLUMN_NAME = SC.name
ORDER BY ST.name ASC, SMA.name ASC