In SQL Server, how can I find everywhere a column is referenced? - sql-server

Within my rather large database, I would like to find out everywhere a column is referenced within the entire schema (SPs, functions, tables, triggers...). I don't want to just do a text search since this will pick up comments and also will find similarly named columns from other tables.
Does anyone know if/how I can do this? I use SQL Server 2008.

Warning: Even though this is a text-search method, the script I'm going to share has saved me lots and lots of hours. It searches inside:
scalar functions
table-valued functions
stored procedures
views
triggers
I needed to specify a collation to make it work for me.
SELECT
sys.objects.object_id,
sys.schemas.name AS [Schema],
sys.objects.name AS Object_Name,
sys.objects.type_desc AS [Type]
FROM sys.sql_modules (NOLOCK)
INNER JOIN sys.objects (NOLOCK) ON sys.sql_modules.object_id = sys.objects.object_id
INNER JOIN sys.schemas (NOLOCK) ON sys.objects.schema_id = sys.schemas.schema_id
WHERE
sys.sql_modules.definition COLLATE SQL_Latin1_General_CP1_CI_AS LIKE '%{Column Name}%' ESCAPE '\'
ORDER BY sys.objects.type_desc, sys.schemas.name, sys.objects.name
The output is like the following:
Update: If you need to search for a certain table, SP, etc. you could use a more specialized query:
DECLARE #SCHEMA_NAME VARCHAR(100) = 'dbo';
DECLARE #OBJECT_NAME VARCHAR(100) = 'MY_OBJECT';
SELECT
sys.objects.object_id,
sys.schemas.name AS [Schema],
sys.objects.name AS Object_Name,
sys.objects.type_desc AS [Type]
FROM sys.sql_modules (NOLOCK)
INNER JOIN sys.objects (NOLOCK) ON sys.sql_modules.object_id = sys.objects.object_id
INNER JOIN sys.schemas (NOLOCK) ON sys.objects.schema_id = sys.schemas.schema_id
WHERE
(
'#' + sys.sql_modules.definition + '#' COLLATE SQL_Latin1_General_CP1_CI_AS LIKE '%[^a-z_]'+#SCHEMA_NAME+'.'+#OBJECT_NAME+'[^a-z_]%' ESCAPE '\'
OR '#' + sys.sql_modules.definition + '#' COLLATE SQL_Latin1_General_CP1_CI_AS LIKE '%[^a-z_]\['+#SCHEMA_NAME+'\].'+#OBJECT_NAME+'[^a-z_]%' ESCAPE '\'
OR '#' + sys.sql_modules.definition + '#' COLLATE SQL_Latin1_General_CP1_CI_AS LIKE '%[^a-z_]'+#SCHEMA_NAME+'.\['+#OBJECT_NAME+'\][^a-z_]%' ESCAPE '\'
OR '#' + sys.sql_modules.definition + '#' COLLATE SQL_Latin1_General_CP1_CI_AS LIKE '%[^a-z_]\['+#SCHEMA_NAME+'\].\['+#OBJECT_NAME+'\][^a-z_]%' ESCAPE '\'
)
ORDER BY sys.objects.type_desc, sys.schemas.name, sys.objects.name
P.S.: Both queries search inside comments too.

i tried this query and it seems to be fine:
select
obj.type REFERENCING_OBJECT_TYPE
,SCHEMA_NAME(obj.schema_id) REFERENCING_OBJECT_SCHEMA
,obj.name REFERENCING_OBJECT_NAME
from sysdepends x
INNER JOIN sys.objects obj ON x.id = obj.object_id
where depid = object_id('yourSchema.yourTable')
and col_name(depid, depnumber) = 'yourColumn'

Best ways to do it are described in this article.
A sample:
SELECT OBJECT_NAME (referencing_id),
referenced_database_name,
referenced_schema_name, referenced_entity_name
FROM sys.sql_expression_dependencies d
WHERE OBJECT_NAME(d.referenced_id) = 'TableName'
AND OBJECT_DEFINITION (referencing_id) LIKE '%ColumnName%'
ORDER BY OBJECT_NAME(referencing_id);

Does not show if there is a reference to a temporary table
Example
create table dbo.TableName (columnName int )
go
create procedure dbo.ProcedureOne
as
update dbo.TableName set columnName = 1
go
create or alter procedure dbo.ProcedureTwo
as
create table #test (dd int)
update
t1
set
t1.columnName = 1
from
dbo.TableName t1
inner join
#test t2 on t1.columnName = t2.dd
SELECT
1 As Level
,t2.type AS ObjectType
,CAST(CONCAT(SCHEMA_NAME(t2.schema_id),'.',t2.name) AS varchar(256)) AS RefName
,CAST('' AS varchar(256)) AS RefBy
FROM
SYSDEPENDS t1
LEFT JOIN
SYS.OBJECTS t2 ON t1.id = t2.OBJECT_ID
WHERE
t1.depid = OBJECT_ID('dbo.TableName')
AND COL_NAME(t1.depid, t1.depnumber) = 'columnName'
example

As Luv said this is an old question but I've found two more solutions that may be helpful.
I'm using the sys.dm_sql_referenced_entities system object that finds all referenced objects and columns in a specified object. You can use the following query:
SELECT DISTINCT
referenced_schema_name AS SchemaName,
referenced_entity_name AS TableName,
referenced_minor_name AS ColumnName
FROM sys.dm_sql_referenced_entities ('yourrefencingobject', 'OBJECT');
GO
Which gives the following result:
Downside of this object is that you'll need to specify a referencing object.
Or do a search like:
SELECT DISTINCT object_name(id)
FROM AdventureWorks2012.dbo.syscomments (nolock)
WHERE text like '%BusinessEntityID%'
Which gives the following result:
I've also find the following SP that you could use in this article, but haven't tested it properly:
> DECLARE #string varchar(1000), #ShowReferences char(1)
>
> SET #string = 'Person.Person.BusinessEntityID' --> searchstring
>
> SET #ShowReferences = 'N'
> /****************************************************************************/ /*
> */ /* TITLE: sp_FindReferences */ /* */ /* DATE: 18 February, 2004 */ /* */ /* AUTHOR: WILLIAM MCEVOY */ /* */ /****************************************************************************/ /*
> */ /* DESCRIPTION: SEARCH SYSCOMMENTS FOR INPUT STRING, OUTPUT NAME OF OBJECT */ /*
> */ /****************************************************************************/ set nocount on
>
> declare #errnum int ,
> #errors char(1) ,
> #rowcnt int ,
> #output varchar(255)
>
> select #errnum = 0 ,
> #errors = 'N' ,
> #rowcnt = 0 ,
> #output = ''
>
> /****************************************************************************/ /* INPUT DATA VALIDATION
> */ /****************************************************************************/
>
>
> /****************************************************************************/ /* M A I N P R O C E S S I N G
> */ /****************************************************************************/
>
> -- Create temp table to hold results DECLARE #Results table ( Name varchar(55), Type varchar(12), DateCreated datetime,
> ProcLine varchar(4000) )
>
>
> IF (#ShowReferences = 'N') BEGIN insert into #Results select
> distinct
> 'Name' = convert(varchar(55),SO.name),
> 'Type' = SO.type,
> crdate,
> ''
> from sysobjects SO
> join syscomments SC on SC.id = SO.id where SC.text like '%' + #string + '%' union select distinct
> 'Name' = convert(varchar(55),SO.name),
> 'Type' = SO.type,
> crdate,
> ''
> from sysobjects SO where SO.name like '%' + #string + '%' union select distinct
> 'Name' = convert(varchar(55),SO.name),
> 'Type' = SO.type,
> crdate,
> ''
> from sysobjects SO
> join syscolumns SC on SC.id = SO.ID where SC.name like '%' + #string + '%' order by 2,1 END ELSE BEGIN insert into #Results
> select
> 'Name' = convert(varchar(55),SO.name),
> 'Type' = SO.type,
> crdate,
> 'Proc Line' = text
> from sysobjects SO
> join syscomments SC on SC.id = SO.id where SC.text like '%' + #string + '%' union select
> 'Name' = convert(varchar(55),SO.name),
> 'Type' = SO.type,
> crdate,
> 'Proc Line' = ''
> from sysobjects SO where SO.name like '%' + #string + '%' union select
> 'Name' = convert(varchar(55),SO.name),
> 'Type' = SO.type,
> crdate,
> 'Proc Line' = ''
> from sysobjects SO
> join syscolumns SC on SC.id = SO.ID where SC.name like '%' + #string + '%' order by 2,1 END
>
> IF (#ShowReferences = 'N') BEGIN select Name,
> 'Type' = Case (Type)
> when 'P' then 'Procedure'
> when 'TR' then 'Trigger'
> when 'X' then 'Xtended Proc'
> when 'U' then 'Table'
> when 'C' then 'Check Constraint'
> when 'D' then 'Default'
> when 'F' then 'Foreign Key'
> when 'K' then 'Primary Key'
> when 'V' then 'View'
> else Type
> end,
> DateCreated
> from #Results
> order by 2,1 END ELSE BEGIN select Name,
> 'Type' = Case (Type)
> when 'P' then 'Procedure'
> when 'TR' then 'Trigger'
> when 'X' then 'Xtended Proc'
> when 'U' then 'Table'
> when 'C' then 'Check Constraint'
> when 'D' then 'Default'
> when 'F' then 'Foreign Key'
> when 'K' then 'Primary Key'
> when 'V' then 'View'
> else Type
> end,
> DateCreated,
> ProcLine
> from #Results
> order by 2,1 END
Hope this helps

I would like to avoid using sys.sql_dependencies because this feature will be removed in a future version of Microsoft SQL Server.
I also cannot use OBJECT_DEFINITION function because all my objects are encrypted.
So I came up with the following query which seems pretty simple and works for me so well that I even wrapped it to the function:
-- =============================================
-- Description: Gets all the stored procedures, functions and triggers referencing the specified column.
-- Example: SELECT * FROM dbo.UFN_GET_SP_FN_TR_REFERENCING_COLUMN(N'dbo', N'MY_TABLE', N'MY_COLUMN');
-- =============================================
CREATE FUNCTION dbo.UFN_GET_SP_FN_TR_REFERENCING_COLUMN
(
#SchemaName sysname,
#TableName sysname,
#ColumnName sysname
)
RETURNS TABLE
AS
RETURN
SELECT R.referencing_schema_name + N'.' + R.referencing_entity_name AS referencing_entity_name
FROM sys.dm_sql_referencing_entities(#SchemaName + N'.' + #TableName, 'OBJECT') AS R
INNER JOIN sys.objects AS O
ON R.referencing_id = O.object_id
WHERE O.[type] IN ('FN'/*SQL scalar function*/, 'IF'/*SQL inline table-valued function*/, 'TF'/*SQL table-valued-function*/, 'P'/*SQL Stored Procedure*/, 'TR' /*SQL DML trigger*/)
AND EXISTS(SELECT 1 FROM sys.dm_sql_referenced_entities (R.referencing_schema_name + N'.' + R.referencing_entity_name, 'OBJECT') AS RE WHERE RE.referenced_entity_name = #TableName AND RE.referenced_minor_name = #ColumnName);
GO

Hello Although this is an old post I was able to combine few tips from above got something like this below which was help full for me. The reason had I create this one is the column I was in lot of tables so it did not provide me clear output.
SELECT
SCHEMA_NAME(schema_id)+'.'+[name] as objectname
,type_desc
,referenced_schema_name AS SchemaName
,referenced_entity_name AS TableName
,referenced_minor_name AS ColumnName
FROM [sys].[all_objects] ob cross apply sys.dm_sql_referenced_entities ( SCHEMA_NAME(schema_id)+'.'+[name], 'OBJECT') e
where is_ms_shipped = 0 and type_desc in ('AGGREGATE_FUNCTION'
,'SQL_SCALAR_FUNCTION'
,'SQL_INLINE_TABLE_VALUED_FUNCTION'
,'SQL_STORED_PROCEDURE'
,'SQL_TABLE_VALUED_FUNCTION'
,'SQL_TRIGGER'
,'VIEW')
and name !='sp_upgraddiagrams'
and referenced_entity_name = 'table name'
and referenced_minor_name = 'columnname'

Here's a slight tweak on #alex's TV-UDF to include views also:
/*
Source: https://stackoverflow.com/a/47775531/852956
Gets all the stored procedures, functions and triggers referencing the specified column.
SELECT * FROM Utility.ft_SelectSprocFuncAndTrigrRefs(N'BrakeRotor', N'BrakeRotors', N'BrakeRotorNumber');
*/
CREATE FUNCTION Utility.ft_SelectSprocFuncAndTrigrRefs
(
#SchemaName sysname,
#TableName sysname,
#ColumnName sysname
)
RETURNS TABLE
AS
RETURN
SELECT QUOTENAME(R.referencing_schema_name) + N'.' + QUOTENAME(R.referencing_entity_name) AS ReferencingEntityName
FROM sys.dm_sql_referencing_entities(#SchemaName + N'.' + #TableName, 'OBJECT') AS R
INNER JOIN sys.objects AS O
ON R.referencing_id = O.object_id
WHERE O.[type] IN (
'FN'/*SQL scalar function*/,
'IF'/*SQL inline table-valued function*/,
'TF'/*SQL table-valued-function*/,
'P'/*SQL Stored Procedure*/,
'TR' /*SQL DML trigger*/
)
AND EXISTS(
SELECT 1
FROM sys.dm_sql_referenced_entities (R.referencing_schema_name + N'.' + R.referencing_entity_name, 'OBJECT') AS RE
WHERE RE.referenced_entity_name = #TableName AND RE.referenced_minor_name = #ColumnName)
UNION SELECT QUOTENAME(VIEW_SCHEMA) + N'.' + QUOTENAME(VIEW_NAME) AS ReferencingEntityName
FROM INFORMATION_SCHEMA.VIEW_COLUMN_USAGE
WHERE TABLE_SCHEMA = #SchemaName
AND TABLE_NAME = #TableName
AND column_name = #ColumnName
GO

Had to do this today and came up with the following:
declare #obj sysname = 'schema.table';
select p.referencing_entity_name, c.*
from sys.dm_sql_referencing_entities(#obj, 'object') as p
cross apply sys.dm_sql_referenced_entities(
concat(p.referencing_schema_name, '.', p.referencing_entity_name),
'object'
) as c
where c.referenced_id = object_id(#obj)
and referenced_minor_name in ('yourColumn');

Related

Inserting records from a table to another using dynamic SQL with conditions to convert data type

I have two tables whose structures as follows:
table_A
CREATE TABLE table_A
(
col_a varchar(100),
col_b bigint,
col_c datetime
)
table_b
--Note that columns are same--
CREATE TABLE table_B
(
col_a varchar(10),
col_b varchar(10),
col_c varchar(20)
)
Now I want to INSERT data into table_A from table_B with proper data type conversion.
Below is the SQL string:
INSERT INTO table_A(col_a,col_b,col_c)
SELECT CONVERT(varchar,col_a),CONVERT(INT,col_b),CONVERT(datetime,col_c) FROM table_B
So far so good.
Now I want generate the SQL dynamically with the help of INFORMATION_SCHEMA.COLUMNS.
For this I have followed the below steps:
Step 1:
Join the Information Schema for the above two tables viz table_A and table_B and store them in a #TempTable. Lets assume that #TempTable has an ID column that is IDENTITY(1,1) but that doesn't follow any sequence like 1,2,3...(Typically this happens in Synapse SQL)
INSERT INTO #TempTable
SELECT S.COLUMN_NAME AS Src_Col,
S.DATA_TYPE AS Src_dtype,
D.COLUMN_NAME AS Dest_Col,
D.DATA_TYPE AS Dest_dtype,
CASE WHEN S.DATA_TYPE NOT LIKE D.DATA_TYPE THEN
'CONVERT('+ '''' + D.DATA_TYPE + '''' + ',' + '''' + S.DATA_TYPE + '''' + ')'
ELSE S.DATA_TYPE AS Modified_Col
FROM INFORMATION_SCHEMA S
JOIN INFORMATION_SCHEMA.COLUMNS D
ON S.COLUMN_NAME = D.COLUMN_NAME AND S.TABLE_NAME = REPLACE(D.TABLE_NAME,'_B','_A')
Step 2:
Iterate over #TempTable to fetch the Modified_Col values
SET #Max_ID = (SELECT MAX(ID) FROM #TempTable);
SET #Min_ID = (SELECT MIN(ID) FROM #TempTable);
SET #ColToInsert = '';
SET #Dest_Col = '';
WHILE #Min_ID <= #Max_ID
BEGIN
SET #ColToInsert = (SELECT #ColToInsert + Modified_Col FROM #TempTable T WHERE T.ID = #Min_ID);
SET #Dest_Col = (SELECT #Dest_Col + Dest_Col FROM #TempTable T WHERE T.ID = #Min_ID);
SET #Min_ID = #Min_ID + 1;
END
Step 3:
Use that #ColToInsert in the below Dynamic SQL
SET #DySQL = 'INSERT INTO Table_A(' + #Dest_Col + ') SELECT ' + #ColToInsert + ' FROM table_B';
exec (#DySQL);
Now at this step 3 I am not getting the expected result. No data is getting inserted into table_A. I can understand that in the CASE statement I have to make some fixes so that convert... portion becomes a string. And I am not able to do so.
Any clue would be appreciated.
I don't understand why you need the temp table at all. You just need to aggregate using STRING_AGG.
You also need to quote the objects and columns using QUOTENAME, and you should use sys.columns etc rather than INFORMATION_SCHEMA, which is for compatibility only.
DECLARE #tableA sysname = 't';
DECLARE #tableB sysname = 's';
DECLARE #sql nvarchar(max) = (
SELECT CONCAT(
'INSERT INTO ',
QUOTENAME(#tableA),
'(',
STRING_AGG(CAST(QUOTENAME(cA.name) AS nvarchar(max)), ', '),
')
SELECT ',
STRING_AGG(
CASE WHEN cA.user_type_id <> cB.user_type_id THEN
CONCAT(
'CONVERT(',
typ.name,
CASE
WHEN typ.name IN ('varchar','nvarchar','char','nchar','varbinary','binary')
THEN CONCAT('(', CASE WHEN cA.max_length = -1 THEN 'max' END, NULLIF(cA.max_length, -1), ')')
WHEN typ.name IN ('datetime2','datetimeoffset','time','float','real')
THEN CONCAT('(', cA.scale, ')')
WHEN typ.name IN ('float','real')
THEN CONCAT('(', cA.precision, ')')
WHEN typ.name IN ('decimal','numeric')
THEN CONCAT('(', cA.precision, ',', cA.scale, ')')
END,
', ',
CAST(QUOTENAME(cB.name) AS nvarchar(max)),
')'
)
ELSE
CAST(QUOTENAME(cB.name) AS nvarchar(max))
END
, ', '),
'
FROM ',
QUOTENAME(#tableB)
)
FROM sys.columns cA
JOIN sys.tables tA ON ta.object_id = cA.object_id AND tA.name = #tableA
JOIN sys.types typ ON typ.user_type_id = cA.user_type_id
JOIN sys.columns cB ON cB.name = cA.name
JOIN sys.tables tB ON tB.object_id = cB.object_id AND tB.name = #tableB
);
PRINT #sql; -- your friend
EXEC sp_executesql #sql;
db<>fiddle

List all tables used in a SQL statement

Currently i have to create a list of all tables & schemes used in several (terribly) long SQL statements.
Of course i could go manually through the SQL statements and write down every table used in a JOIN, Subselect and so on.
But i'd be curious if there is any easier way to do it. maybe with a "simple" SQL statement, but i have no clue how to do it.
Why am i asking? I'd have to do this for about 50 SQL-Unload-Statements, where all of them use between 30 and 70 tables. I guess you can imagine this quite boring work
Thanks in advance for any input & hints!
Have a read here: How can i get the list of tables in the stored procedure
;WITH stored_procedures AS (
SELECT
o.name AS proc_name, oo.name AS table_name,
ROW_NUMBER() OVER(partition by o.name,oo.name ORDER BY o.name,oo.name) AS row
FROM sysdepends d
INNER JOIN sysobjects o ON o.id=d.id
INNER JOIN sysobjects oo ON oo.id=d.depid
WHERE o.xtype = 'P')
SELECT proc_name, table_name FROM stored_procedures
WHERE row = 1
ORDER BY proc_name,table_name
All credit to the OP of the code above in the thread above.
I will post this answer & mark it as solved, as it was the best and easiest way to solve my issue.
Hint was in a comment by #whereisSQL (thanks a lot!)
Seems like it was already asked in this thread, but i didn't find it:
https://dba.stackexchange.com/questions/121346/need-to-get-identify-all-tables-and-columns-in-a-sql-query/121355#121355
There is an online "get table column" tool to list the tables of a SQL statement here:
http://107.170.101.241:8080/getTableColumn/
It lists all tables and additionally columns used in the statement! Perfect solution in my case.
This may help. Using DMVs
IF EXISTS (
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[sp_dependsobj]')
AND type IN (
N'P'
,N'PC'
)
)
DROP PROCEDURE [dbo].[sp_dependsobj]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_dependsobj] (#Objname NVARCHAR(2000))
AS
BEGIN
SET NOCOUNT ON
DECLARE #ObjID INTEGER
DECLARE #ObjType VARCHAR(100)
DECLARE #RowCount INTEGER = 0
SELECT #ObjID = OBJECT_ID(#Objname)
SELECT #ObjType = TYPE
FROM sys.objects
WHERE object_id = #ObjID
DECLARE #RefObjects AS TABLE (
[Object_name] SYSNAME
,[Type] VARCHAR(255)
,referenced_entity_name SYSNAME
,Column_name SYSNAME NULL
,referenced_entity_type VARCHAR(255)
)
DECLARE #FoundIn AS TABLE (
[Object_name] SYSNAME
,[Found In] SYSNAME
,[Type] VARCHAR(255)
)
DECLARE #SQLStr VARCHAR(MAX)
SET #SQLStr = '
WITH CTE_Objects
AS
(
SELECT o.NAME referencing_entity_name
,o.type_desc referencing_object_type
,sed.referenced_entity_name
,refobj.referenced_minor_name
,obj.type_desc
,obj.object_id
FROM sys.sql_expression_dependencies sed
INNER JOIN sys.objects o ON sed.referencing_id = o.[object_id]
INNER JOIN sys.objects obj ON sed.referenced_entity_name = obj.name
INNER JOIN sys.dm_sql_referenced_entities(''dbo.' + #Objname + ''', ''OBJECT'') refobj ON
refobj.referenced_id = sed.referenced_id
WHERE o.NAME = ''' + #Objname + '''
UNION
SELECT ''' + #Objname + ''', (SELECT type_desc from sys.objects where name = ''' + #Objname + '''), referenced_entity_name, NULL, obj.type_desc
,obj.object_id
FROM sys.dm_sql_referenced_entities (''dbo.' + '' + #Objname +
''', ''OBJECT'') refObj INNER JOIN sys.objects obj
ON refObj.referenced_entity_name = obj.name
)
SELECT CTE.referencing_entity_name Object_name, CTE.referencing_object_type Type, CTE.referenced_entity_name, CTE.referenced_minor_name Column_name, CTE.type_desc referenced_entity_type
FROM CTE_Objects CTE LEFT JOIN sys.columns cl ON
cte.object_id = cl.object_id AND cte.referenced_minor_name = cl.name
Order by cte.referencing_entity_name, CASE WHEN cte.referencing_entity_name IS NULL THEN 0 ELSE cl.column_id END
'
INSERT INTO #RefObjects (
[Object_name]
,[Type]
,referenced_entity_name
,Column_name
,referenced_entity_type
)
EXEC (#SQLStr)
SET #RowCount = ##ROWCOUNT
IF #RowCount > 0
BEGIN
SELECT *
FROM #RefObjects
END
SET #SQLStr = '
SELECT DISTINCT [Object Name] = o.NAME
,[Found In] = sp.NAME
,sp.type_desc Type
FROM sys.objects o
INNER JOIN sys.sql_expression_dependencies sd ON o.object_id = sd.referenced_id
INNER JOIN sys.objects sp ON sd.referencing_id = sp.object_id
WHERE o.NAME = ''' + #Objname + '''
UNION
SELECT ''' + #Objname + ''', referencing_entity_name, (SELECT type_desc from sys.objects where name = referencing_entity_name)
FROM sys.dm_sql_referencing_entities (''dbo.' + '' + #Objname + ''', ''OBJECT'');
'
INSERT INTO #FoundIn (
[Object_name]
,[Found In]
,[Type]
)
EXEC (#SQLStr)
SET #RowCount = ##ROWCOUNT
IF #RowCount > 0
BEGIN
SELECT *
FROM #FoundIn
END
IF NOT EXISTS (
SELECT 1
FROM #RefObjects
)
AND NOT EXISTS (
SELECT 1
FROM #FoundIn
)
BEGIN
PRINT 'Object does not reference any object, and no objects reference it.'
END
SET NOCOUNT OFF
END
GO
The question is old, but here is a regex for those that want the tables used in SQL statement (From/join).
I created it specially for my case, but it may be adapt and useful for others:
(from|join)[ ]{1,}[^.\n\ ]+?(?=(.))[.].*?(?=( |\n))

Generate **bare** CREATE TABLE and CREATE PROC statemnts in SQL Server

The deployment procedures in my company require that SQL scripts for creation of procedures and tables, etc. be bare.
Generating create scripts in SQL Server Management Studio gives you significantly more than a bare script, which is unfortunate in this case. For example, for a test table this is what SSMS generated for me:
USE [DemoDB]
GO
/****** Object: Table [dbo].[example] Script Date: 08/07/2012 15:46:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[example](
[fake_row] [int] NULL
) ON [PRIMARY]
GO
So, what I'd like to know is:
Can I somehow run a query on SQL Server in SSMS that would give me a script that was literally just the following?
create table example (
fake_row int
)
You can create your own "create table" statements, using information_schema (Aaron . . . I know, INFORMATION_SCHEMA ;).
I have written some code for this purpose, but it doesn't use INFORMATION_SCHEMA. I know, if uses older system tables that are probably scheduled to be removed. It also adds in some additional information (which you can remove, since you don't need it). Just put the list of tables in the #INCLUSIONLIST and run this in the database where the tables reside.
SET #INCLUSIONLIST = '|table1|table2|';
SELECT (CASE WHEN rownum = 1 THEN 'CREATE TABLE ['+a.t_name+'] ('
WHEN c.column_id IS NOT NULL
THEN ' ['+c.c_name+'] ' +
(CASE WHEN CHARINDEX('CHAR', datatype) > 0 THEN datatype+'('+(case when length < 0 then 'max' else cast(length as varchar) end)+')'
WHEN CHARINDEX('BINARY', datatype) > 0 THEN datatype+'('+cast(length as varchar)+')'
WHEN datatype = 'float' AND precision <> 24 THEN datatype+'('+cast(precision as varchar)+')'
WHEN datatype IN ('numeric', 'decimal') AND scale = 0 THEN datatype+'('+cast(precision as varchar)+')'
WHEN datatype IN ('numeric', 'decimal') AND scale > 0 THEN datatype+'('+cast(precision as varchar)+','+cast(scale as varchar)+')'
ELSE datatype END)+' '+
(CASE WHEN c.identity_seed IS NOT NULL
THEN 'IDENTITY(' + CAST(identity_seed AS VARCHAR) + ',' + CAST(identity_increment AS VARCHAR) + ') '
ELSE '' END) +
(CASE WHEN c.is_nullable = 0 THEN 'NOT NULL ' ELSE '' END) +
(CASE WHEN c.default_definition IS NOT NULL
THEN 'DEFAULT '+default_definition ELSE '' END) +
(CASE WHEN max_column_id = column_id AND pk.pk_name IS NULL THEN '' ELSE ',' END)
WHEN rownum = max_column_id + 2 and pk.pk_name IS NOT NULL
THEN ' PRIMARY KEY ('+pk.pk_columns+')'
WHEN rownum = max_column_id + 3 THEN ') /* CREATE TABLE '+a.t_name+' */'
WHEN rownum = max_column_id + 4 THEN 'GO'
WHEN rownum = max_column_id + 5 THEN ''
END)
FROM (SELECT t.t_name, rownum, max_column_id
FROM (SELECT t.name as t_name, MAX(c.column_id) as max_column_id
FROM sys.columns c join
(SELECT * FROM sys.tables WHERE CHARINDEX('|'+name+'|', #INCLUSIONLIST) > 0 ) t
ON c.object_id = t.object_id
GROUP BY t.name) t join
(SELECT ROW_NUMBER() OVER (ORDER BY object_id) as rownum FROM sys.columns c) ctr
ON ctr.rownum <= t.max_column_id + 5
) a LEFT OUTER JOIN
(SELECT t.name as t_name, c.column_id, c.name AS c_name, u.name as datatype,
ISNULL(baset.name, N'') AS systemtype,
CAST(CASE WHEN baset.name IN (N'nchar', N'nvarchar') AND c.max_length <> -1
THEN c.max_length/2 ELSE c.max_length END AS INT) AS length,
c.precision AS precision,
c.scale as scale,
c.is_nullable,
dc.definition as default_definition,
idc.seed_value as identity_seed, idc.increment_value as identity_increment
FROM sys.tables t JOIN
sys.all_columns AS c
ON c.object_id = t.object_id LEFT OUTER JOIN
sys.types u
ON u.user_type_id = c.user_type_id LEFT OUTER JOIN
sys.types baset
ON baset.user_type_id = c.system_type_id AND
baset.user_type_id = baset.system_type_id LEFT OUTER JOIN
sys.default_constraints dc
ON c.object_id = dc.parent_object_id AND
c.column_id = dc.parent_column_id LEFT OUTER JOIN
sys.identity_columns idc
ON c.object_id = idc.object_id AND
c.column_id = idc.column_id
) c
ON a.t_name = c.t_name AND
c.column_id + 1 = a.rownum LEFT OUTER JOIN
(SELECT t.name as t_name, kc.name as pk_name,
(MAX(CASE WHEN index_column_id = 1 THEN '['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 2 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 3 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 4 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 5 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 6 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 7 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 8 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 9 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 10 THEN ','+'['+c.name+']' ELSE '' END)
) as pk_columns
FROM sys.indexes i JOIN
sys.key_constraints kc
ON i.name = kc.name AND
kc.type = 'PK' JOIN
sys.tables t
ON i.object_id = t.object_id JOIN
sys.index_columns ic
ON i.object_id = ic.object_id AND
i.index_id = ic.index_id JOIN
sys.columns c
ON ic.index_column_id = c.column_id AND
ic.object_id = c.object_id
GROUP BY t.name, kc.name
) pk
ON pk.t_name = a.t_name
ORDER BY a.t_name, rownum
Apologies for the self-answer, marking other good answers +1.
It turns out you can get pretty much all of the way there with utility in SSMS.
Right click on the database in the object explorer
Click "Tasks"
Click "Generate Scripts"
Select "Script Specific Objects" and choose tables, or whatever else
Select "Save To File" & "Single File Per Object" (or just spool to query window)
Click "Advanced" and you can enable/disable the generation of virtually every part of the statements you're generating including constraints, use statements, etc.
If further removal is required (e.g. removing GO), it's minimal
Optionally, you can control the general scripting behavior of SSMS like so: Options for scripting SQL Server database objects.
I would create stored procs that read from the INFORMATION_SCHEMA views.
Getting the stored proc text is just:
DECLARE #SQL VARCHAR(8000)
SET #SQL=' '
select #SQL = #SQL + ROUTINE_DEFINITION
from INFORMATION_SCHEMA.ROUTINES
where ROUTINE_TYPE='PROCEDURE'
AND SPECIFIC_NAME = 'updateComments'
PRINT #SQL
The one to script the table would looks something like:
DECLARE #tableName VARCHAR(50)
SET #tableName = 'Location'
-- Need to know how many columns
DECLARE #NumColumns int
SELECT #NumColumns = MAX(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName
DECLARE #SQL VARCHAR(8000)
SET #SQL=' '
DECLARE #Results TABLE
(LineNumber int,
Line VARCHAR(1000))
INSERT INTO #Results
SELECT 0 AS ORDINAL_POSITION,
'CREATE TABLE '+TABLE_SCHEMA+'.'+#tableName+' (' AS Line
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #tableName
UNION ALL
SELECT ORDINAL_POSITION,
'['+COLUMN_NAME+'] '+ DATA_TYPE +
CASE WHEN DATA_TYPE = 'varchar' OR DATA_TYPE = 'char'
THEN '('+ CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) +')'
ELSE '' END +
CASE WHEN IS_NULLABLE = 'NO'
THEN ' NULL '
ELSE ' NOT NULL' END +
CASE WHEN ORDINAL_POSITION < #NumColumns
THEN ', '
ELSE ' ' END
AS LINE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName
UNION ALL
SELECT 999, ' )'
SELECT Line
FROM #Results
ORDER BY LineNumber
SELECT #SQL = #SQL + Line
FROM #Results
ORDER BY LineNumber
SELECT #SQL
PRINT #SQL
This creates the simple table script that you want, but it is not complete - doesn't do numeric precision, primary key, etc. But this is enough to get you started.
I would just make each one of these into a stored proc that takes the object name as a parameter.

How do I list (or export) the code for all triggers in a database?

I'm changing from local time to UTC-time in our database.
There are alot of triggers that copies information to history tables that currently uses GETDATE().
I would like to find every trigger that uses GETDATE() (instead of GETUTCDATE()) in the database, is there any way to do this automatic?
I've listed them by select * from sys.triggers but I also need to see the actual code to be able to find the use of GETDATE().
Your could try the following:
SELECT o.[name],
c.[text]
FROM sys.objects AS o
INNER JOIN sys.syscomments AS c
ON o.object_id = c.id
WHERE o.[type] = 'TR'
Here's the script I used to export triggers:
DECLARE #t VARCHAR (MAX)
SET #t = ''
SELECT #t = #t + 'IF EXISTS (SELECT 1 FROM sys.triggers WHERE object_id = OBJECT_ID(N''' + s.name + '.' + o.name +'''))
DROP TRIGGER ' + s.name + '.' + o.name + '
GO
' + OBJECT_DEFINITION (OBJECT_ID( s.name + '.' + o.name )) +'
GO
'
FROM sys.objects o
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sys.objects o2 ON o.parent_object_id = o2.object_id
WHERE o. [type] = 'TR'
AND (
OBJECTPROPERTY ( o.object_id , 'ExecIsInsertTrigger' ) = 1
OR
OBJECTPROPERTY ( o.object_id , 'ExecIsUpdateTrigger' ) = 1
OR
OBJECTPROPERTY ( o.object_id , 'ExecIsDeleteTrigger' ) = 1
)
SELECT #t AS [processing-instruction(x)] FOR XML PATH ('')
More details here if it doesn't make sense to anyone:
http://paulfentonsql.co.uk/2015/09/01/generate-createdrop-statements-for-all-triggers-of-a-given-type/
If you want to export all triggers from the database... here's some code:
DECLARE #vchServerName VARCHAR(500)
DECLARE #vchDBName VARCHAR(500)
DECLARE #intLoop INTEGER
DECLARE #intTotalRows INTEGER
DECLARE #intId INTEGER
DECLARE #vchName VARCHAR(500)
DECLARE #vchSQL VARCHAR(4000)
-- supress count (just so log looks nicer!)
SET NOCOUNT ON
-- get current DB and server
SET #vchDBName = DB_NAME()
SET #vchServerName = ##servername
-- get list of XXX
SELECT ROW_NUMBER() OVER (ORDER BY o.object_id ) fldRowNum
,o.object_id fldId
,s.name + '.' + o.name fldName
INTO #tblFound
FROM sys.objects o
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE [type] = 'TR'
SET #intTotalRows = ##ROWCOUNT
SET #intLoop = 1
-- loop thru list
WHILE #intLoop <= #intTotalRows
BEGIN
SELECT #intID = fldId
,#vchName = fldName
FROM #tblFound
WHERE fldRowNum = #intLoop
PRINT 'Exporting ' + #vchName + '...'
-- NOTE: I'm using a version of bcp that doens't have -D parameter so I need to use DB name here
SET #vchSQL = 'SELECT c.[text] FROM ' + #vchDBName + '.sys.syscomments AS c WHERE c.id = ' + CONVERT(VARCHAR,#intID)
SET #vchSQL = 'bcp "' + #vchSQL + '" queryout "c:\temp\' + #vchName + '.sql" -c -t -T -S ' + #vchServerName
EXEC master..XP_CMDSHELL #vchSQL
SET #intLoop = #intLoop + 1
END
DROP TABLE #tblFound
PRINT 'Done'

How do you determine what SQL Tables have an identity column programmatically

I want to create a list of columns in SQL Server 2005 that have identity columns and their corresponding table in T-SQL.
Results would be something like:
TableName, ColumnName
Another potential way to do this for SQL Server, which has less reliance on the system tables (which are subject to change, version to version) is to use the
INFORMATION_SCHEMA views:
select COLUMN_NAME, TABLE_NAME
from INFORMATION_SCHEMA.COLUMNS
where COLUMNPROPERTY(object_id(TABLE_SCHEMA+'.'+TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
order by TABLE_NAME
sys.columns.is_identity = 1
e.g.,
select o.name, c.name
from sys.objects o inner join sys.columns c on o.object_id = c.object_id
where c.is_identity = 1
Another way (for 2000 / 2005/2012/2014):
IF ((SELECT OBJECTPROPERTY( OBJECT_ID(N'table_name_here'), 'TableHasIdentity')) = 1)
PRINT 'Yes'
ELSE
PRINT 'No'
NOTE: table_name_here should be schema.table, unless the schema is dbo.
In SQL 2005:
select object_name(object_id), name
from sys.columns
where is_identity = 1
This query seems to do the trick:
SELECT
sys.objects.name AS table_name,
sys.columns.name AS column_name
FROM sys.columns JOIN sys.objects
ON sys.columns.object_id=sys.objects.object_id
WHERE
sys.columns.is_identity=1
AND
sys.objects.type in (N'U')
List of tables without Identity column based on Guillermo answer:
SELECT DISTINCT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (TABLE_SCHEMA = 'dbo') AND (OBJECTPROPERTY(OBJECT_ID(TABLE_NAME), 'TableHasIdentity') = 0)
ORDER BY TABLE_NAME
here's a working version for MSSQL 2000. I've modified the 2005 code found here: http://sqlfool.com/2011/01/identity-columns-are-you-nearing-the-limits/
/* Define how close we are to the value limit
before we start throwing up the red flag.
The higher the value, the closer to the limit. */
DECLARE #threshold DECIMAL(3,2);
SET #threshold = .85;
/* Create a temp table */
CREATE TABLE #identityStatus
(
database_name VARCHAR(128)
, table_name VARCHAR(128)
, column_name VARCHAR(128)
, data_type VARCHAR(128)
, last_value BIGINT
, max_value BIGINT
);
DECLARE #dbname sysname;
DECLARE #sql nvarchar(4000);
-- Use an cursor to iterate through the databases since in 2000 there's no sp_MSForEachDB command...
DECLARE c cursor FAST_FORWARD FOR
SELECT
name
FROM
master.dbo.sysdatabases
WHERE
name NOT IN('master', 'model', 'msdb', 'tempdb');
OPEN c;
FETCH NEXT FROM c INTO #dbname;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = N'Use [' + #dbname + '];
Insert Into #identityStatus
Select ''' + #dbname + ''' As [database_name]
, Object_Name(id.id) As [table_name]
, id.name As [column_name]
, t.name As [data_type]
, IDENT_CURRENT(Object_Name(id.id)) As [last_value]
, Case
When t.name = ''tinyint'' Then 255
When t.name = ''smallint'' Then 32767
When t.name = ''int'' Then 2147483647
When t.name = ''bigint'' Then 9223372036854775807
End As [max_value]
From
syscolumns As id
Join systypes As t On id.xtype = t.xtype
Where
id.colstat&1 = 1 -- this identifies the identity columns (as far as I know)
';
EXECUTE sp_executesql #sql;
FETCH NEXT FROM c INTO #dbname;
END
CLOSE c;
DEALLOCATE c;
/* Retrieve our results and format it all prettily */
SELECT database_name
, table_name
, column_name
, data_type
, last_value
, CASE
WHEN last_value < 0 THEN 100
ELSE (1 - CAST(last_value AS FLOAT(4)) / max_value) * 100
END AS [percentLeft]
, CASE
WHEN CAST(last_value AS FLOAT(4)) / max_value >= #threshold
THEN 'warning: approaching max limit'
ELSE 'okay'
END AS [id_status]
FROM #identityStatus
ORDER BY percentLeft;
/* Clean up after ourselves */
DROP TABLE #identityStatus;
The following query work for me:
select TABLE_NAME tabla,COLUMN_NAME columna
from INFORMATION_SCHEMA.COLUMNS
where COLUMNPROPERTY(object_id(TABLE_SCHEMA+'.'+TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
order by TABLE_NAME
I think this works for SQL 2000:
SELECT
CASE WHEN C.autoval IS NOT NULL THEN
'Identity'
ELSE
'Not Identity'
AND
FROM
sysobjects O
INNER JOIN
syscolumns C
ON
O.id = C.id
WHERE
O.NAME = #TableName
AND
C.NAME = #ColumnName
This worked for me using Sql Server 2008:
USE <database_name>;
GO
SELECT SCHEMA_NAME(schema_id) AS schema_name
, t.name AS table_name
, c.name AS column_name
FROM sys.tables AS t
JOIN sys.identity_columns c ON t.object_id = c.object_id
ORDER BY schema_name, table_name;
GO
Use this :
DECLARE #Table_Name VARCHAR(100)
DECLARE #Column_Name VARCHAR(100)
SET #Table_Name = ''
SET #Column_Name = ''
SELECT RowNumber = ROW_NUMBER() OVER ( PARTITION BY T.[Name] ORDER BY T.[Name], C.column_id ) ,
SCHEMA_NAME(T.schema_id) AS SchemaName ,
T.[Name] AS Table_Name ,
C.[Name] AS Field_Name ,
sysType.name ,
C.max_length ,
C.is_nullable ,
C.is_identity ,
C.scale ,
C.precision
FROM Sys.Tables AS T
LEFT JOIN Sys.Columns AS C ON ( T.[Object_Id] = C.[Object_Id] )
LEFT JOIN sys.types AS sysType ON ( C.user_type_id = sysType.user_type_id )
WHERE ( Type = 'U' )
AND ( C.Name LIKE '%' + #Column_Name + '%' )
AND ( T.Name LIKE '%' + #Table_Name + '%' )
ORDER BY T.[Name] ,
C.column_id
This worked for SQL Server 2005, 2008, and 2012.
I found that the sys.identity_columns did not contain all my tables with identity columns.
SELECT a.name AS TableName, b.name AS IdentityColumn
FROM sys.sysobjects a
JOIN sys.syscolumns b
ON a.id = b.id
WHERE is_identity = 1
ORDER BY name;
Looking at the documentation page the status column can also be utilized. Also you can add the four part identifier and it will work across different servers.
SELECT a.name AS TableName, b.name AS IdentityColumn
FROM [YOUR_SERVER_NAME].[YOUR_DB_NAME].sys.sysobjects a
JOIN [YOUR_SERVER_NAME].[YOUR_DB_NAME].sys.syscolumns b
ON a.id = b.id
WHERE is_identity = 1
ORDER BY name;
Source:
https://msdn.microsoft.com/en-us/library/ms186816.aspx
By some reason sql server save some identity columns in different tables, the code that work for me, is the following:
select TABLE_NAME tabla,COLUMN_NAME columna
from INFORMATION_SCHEMA.COLUMNS
where COLUMNPROPERTY(object_id(TABLE_SCHEMA+'.'+TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
union all
select o.name tabla, c.name columna
from sys.objects o
inner join sys.columns c on o.object_id = c.object_id
where c.is_identity = 1
Get all columns with Identity. Modern version for MSSQL 2017+. Locks down to specific database:
SELECT
[COLUMN_NAME]
, [TABLE_NAME]
, [TABLE_CATALOG]
FROM
[INFORMATION_SCHEMA].[COLUMNS]
WHERE
COLUMNPROPERTY(OBJECT_ID(CONCAT_WS('.' ,[TABLE_CATALOG] ,[TABLE_SCHEMA] ,[TABLE_NAME])) ,[COLUMN_NAME] ,'IsIdentity') = 1
ORDER BY
[TABLE_NAME]

Resources