Is There a Query for Indexes? - sybase

I want know what are the indexes of a table. I am using ASE ISQL and I can know the indexes by right click on the table and selecting DDL, however, there is a developer in another machine that his not familiar to sybase, and I want to know the indexes of his database (his using ASE).
Is there a query for that ?

There are a number of different ways to view the indexes in your database.
sp_helpindex can be used to show the indexes associated with a particular table.
sp_helpindex TABLE_NAME
sp_help can be used to list all the properties of a table, including the associated indexes.
sp_help TABLE_NAME
To get the list of all indexes and their associated tables you can use the following query
use DATABASE_NAME
go
select sysobjects.name as TABLE_NAME, sysindexes.name as INDEX_NAME
from sysobjects,sysindexes where
sysobjects.type = 'U' and
sysobjects.id = sysindexes.id and
sysindexes.indid between 1 and 254
order by sysobjects.name,sysindexes.indid
go

This code will generate the code indexes:
use [database]
go
declare #objectName sysname
declare #username sysname
declare #fullname sysname
declare #id int
select
#id = o.id,
#objectName = o.name,
#username = u.name,
#fullname = u.name + '.' + o.name
from
dbo.sysobjects o,
dbo.sysusers u
where
o.name = 'Table'
and o.Type in ( 'U', 'S' )
and u.uid = o.uid
and u.name = 'Owner'
select
[index] = 1000 * i.indid,
text =
'create' +
case i.status & 2
when 2 then ' unique '
else ' '
end +
case ( i.status & 16 ) + ( i.status2 & 512 )
when 0 then
'nonclustered'
else
'clustered'
end +
' index [' + i.name + '] on ' + #fullname + ' ('
from
dbo.sysindexes i
where
i.indid > 0
and i.indid < 255
and i.id = #id
and i.status2 & 2 != 2
union all
select
[index] = 1000 * i.indid + c.colid,
text =
' ' + index_col ( #fullname, i.indid, c.colid ) +
case
when c.colid < i.keycnt - case when i.indid = 1 then 0 else 1 end then
', '
end
from
dbo.sysindexes i,
dbo.syscolumns c
where
i.indid > 0
and i.indid < 255
and i.id = #id
and i.status2 & 2 != 2
and c.id = #id
and c.colid <= i.keycnt - case when i.indid = 1 then 0 else 1 end
union all
select
[index] = 1000 * i.indid + 999,
text =
' )' || char ( 13 ) || char ( 10 ) || 'go' || char ( 13 ) || char ( 10 )
from
dbo.sysindexes i
where
i.indid > 0
and i.indid < 255
and i.id = #id
and i.status2 & 2 != 2
order by
[index]
go

Related

Validate decimal and integer values by looping through list of dynamic columns

I was tasked to validate the decimal and integer values of the columns from a list of tables. I have around 10-12 tables having different column names.
I created a lookup table which has the table name and the column names of decimal and integer as shown below. for example 'Pricedetails' and 'Itemdetails' tables have many columns of which only the ones mentioned in the Lookup table are required.
lkpTable
TableName
requiredcolumns
Pricedetails
sellingPrice,RetailPrice,Wholesaleprice
Itemdetails
ItemID,Itemprice
Pricedetails
Priceid
Mafdate
MafName
sellingPrice
RetailPrice
Wholesaleprice
01
2020-01-01
Americas
25.00
43.33
33.66
02
2020-01-01
Americas
43.45
22.55
11.11
03
2021-01-01
Asia
-23.00
-34.00
23.00
Itemdetails
ItemID
ItemPrice
Itemlocation
ItemManuf
01
45.11
Americas
SA
02
25.00
Americas
SA
03
35.67
Americas
SA
I have created a stored procedure with table name as input parameter, and able to pull the required column names of the tables (input parameter) from the lookup table and store that resultset into a table variable, below is the code.
declare #resultset Table
(
id INT identity(1,1),
tablename varchar(200) ,
ColumnNames varchar(max)
)
declare #tblname varchar(200),#sql varchar(max),#cols varchar(max),
INSERT INTO #resultset
select tablename,ColumnNames
from lkptable where tablename ='itemdetails'
select #cols = ColumnNames from #resultset;
select #tblname = TableName from #resultset;
----- Split the comma separated columnnames
Create table ##splitcols
(
ID int identity(1,1),
Name varchar(50)
)
Insert into ##splitcols
select value from string_split(#cols,',')
set #sql = 'select ' +#cols + ' from ' +#tblname
--print (#cols)
exec (#sql)
select * from ##splitcols
On executing the above code i get the below result sets, similarly what ever table name i provide i can get the required columns and its relevant data, now i am stuck at this point on how to validate whether the columns are decimal or int. I tried using while loop and cursor to pass the Name value from Resultset2, to the new dynamic query, somehow i don't find any way on how to validate.
ItemID
ItemPrice
01
45.11
02
25.00
03
35.67
Resultset2
ID
Name
01
ItemID
02
ItemPrice
you can validate in this way
insert into #splitcols values (1.1),(1.11)
select case when (t * 100)%10 = 0 then 1 else 0 end as valid from #splitcols
Similarly for number/integer
You can generate one giant UNION ALL query using dynamic SQL, then run it.
Each query would be of the form:
SELECT
TableName = 'SomeTable',
ColumnName,
IsInt
FROM (
SELECT
[Column1] = CASE WHEN COUNT(CASE WHEN ROUND([Column1], 0) <> [Column1] THEN 1 END) = 0 THEN 'All ints' ELSE 'Not All ints' END,
[Column2] = CASE WHEN COUNT(CASE WHEN ROUND([Column2], 0) <> [Column2] THEN 1 END) = 0 THEN 'All ints' ELSE 'Not All ints' END
FROM SomeTable
) t
UNPIVOT (
ColumnName FOR IsInt IN (
[Column1], [Column2]
)
) u
The script is as follows
DECLARE #sql nvarchar(max);
SELECT #sql = STRING_AGG('
SELECT
TableName = ' + QUOTENAME(t.name, '''') + ',
ColumnName,
IsInt
FROM (
SELECT ' + c.BeforePivotCoumns + '
FROM ' + QUOTENAME(t.name) + '
) t
UNPIVOT (
ColumnName FOR IsInt IN (
' + c.UnpivotColumns + '
)
) u
', '
UNION ALL '
)
FROM sys.tables t
JOIN lkpTable lkp ON lkp.TableName = t.name
CROSS APPLY (
SELECT
BeforePivotCoumns = STRING_AGG(CAST('
' + QUOTENAME(c.name) + ' = CASE WHEN COUNT(CASE WHEN ROUND(' + QUOTENAME(c.name) + ', 0) <> ' + QUOTENAME(c.name) + ' THEN 1 END) = 0 THEN ''All ints'' ELSE ''Not All ints'' END'
AS nvarchar(max)), ','),
UnpivotColumns = STRING_AGG(QUOTENAME(c.name), ', ')
FROM sys.columns c
JOIN STRING_SPLIT(lkp.requiredcolumns, ',') req ON req.value = c.name
WHERE c.object_id = t.object_id
) c;
PRINT #sql;
EXEC sp_executesql #sql;
db<>fiddle
If you are on an older version of SQL Server then you can't use STRING_AGG and instead you need to hack it with FOR XML and STUFF.
DECLARE #unionall nvarchar(100) = '
UNION ALL ';
DECLARE #sql nvarchar(max);
SET #sql = STUFF(
(SELECT #unionall + '
SELECT
TableName = ' + QUOTENAME(t.name, '''') + ',
ColumnName,
IsInt
FROM (
SELECT ' + STUFF(c1.BeforePivotCoumns.value('text()[1]','nvarchar(max)'), 1, 1, '') + '
FROM ' + QUOTENAME(t.name) + '
) t
UNPIVOT (
ColumnName FOR IsInt IN (
' + STUFF(c2.UnpivotColumns.value('text()[1]','nvarchar(max)'), 1, 1, '') + '
)
) u'
FROM sys.tables t
JOIN (
SELECT DISTINCT
lkp.TableName
FROM lkpTable lkp
) lkp ON lkp.TableName = t.name
CROSS APPLY (
SELECT
',
' + QUOTENAME(c.name) + ' = CASE WHEN COUNT(CASE WHEN ROUND(' + QUOTENAME(c.name) + ', 0) <> ' + QUOTENAME(c.name) + ' THEN 1 END) = 0 THEN ''All ints'' ELSE ''Not All ints'' END'
FROM lkpTable lkp2
CROSS APPLY STRING_SPLIT(lkp2.requiredcolumns, ',') req
JOIN sys.columns c ON req.value = c.name
WHERE c.object_id = t.object_id
AND lkp2.TableName = lkp.TableName
FOR XML PATH(''), TYPE
) c1(BeforePivotCoumns)
CROSS APPLY (
SELECT
', ' + QUOTENAME(c.name)
FROM lkpTable lkp2
CROSS APPLY STRING_SPLIT(lkp2.requiredcolumns, ',') req
JOIN sys.columns c ON req.value = c.name
WHERE c.object_id = t.object_id
AND lkp2.TableName = lkp.TableName
FOR XML PATH(''), TYPE
) c2(UnpivotColumns)
FOR XML PATH(''), TYPE
).value('text()[1]','nvarchar(max)'), 1, LEN(#unionall), '');
PRINT #sql;
EXEC sp_executesql #sql;
db<>fiddle

How to combine rows dynamically

I have a table with many columns (even number of columns). Now I need to combine the second column and third column, the forth and fifth column, sixth and seventh column....etc. How to achieve this?
I tried static one, but what about dynamic one. Assume that there are 100 or more columns.
create table tb11 ( [id] int,[A] varchar(20),[B] varchar(20),
[C] varchar(20),[D] varchar(20))
insert into tb11 values
(1,'a','b','c','d'),
(2,'e','f','g','h'),
(3,'i','j','k','l')
select * from tb11
/*
id A B C D
---- --- ---- --- ----
1 a b c d
2 e f g h
3 i j k l
*/
select id,
[A] + [B] as '1' ,
[C] + [D] as '2'
from tb11
/*output with 3 columns
id 1 2
---- ----- ------
1 ab cd
2 ef gh
3 ij kl
*/
Try this
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = (
SELECT '
' +
STUFF((
SELECT ', ' + c.name + ' + ' + c2.name + ' AS [' + c.name + c2.name +']'
FROM sys.columns c
INNER JOIN sys.columns c2 ON c2.object_id = c.object_id
AND c2.column_id = c.column_id + 1
WHERE c.[object_id] = o.[object_id]
AND c.column_id > 1
AND c.column_id % 2 = 0
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, 'SELECT id, ') + '
FROM [' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + ']' -- select *
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.is_ms_shipped = 0
AND [name] = 'tb11'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #SQL
EXEC sys.sp_executesql #SQL
You may use schema of tables to get the list of columns and create dynamic columns name from them.
Similarly by using that schema only create you table script for new structure.
Try this:
GO
;with cte as (
select ORDINAL_POSITION as slno, COLUMN_NAME from information_schema.columns where table_name = 'tb11'
)
select * into #tab_col from cte
declare #max int
set #max = (select Count(*) -1 from #tab_col)
declare #loop int
set #loop = 0
create table newtab (
id int )
declare #columns nvarchar(max) = ''
declare #values nvarchar(max) = ''
while(#Loop <= (#Max/2))
Begin
declare #Col1 varchar(100)
declare #Col2 varchar(100)
set #Col1 = (select Column_name from #tab_col where slno = #Loop+2)
set #Col2 = (select Column_name from #tab_col where slno = #Loop+3)
declare #alter nvarchar(max)
set #alter = ' Alter table newtab add [' + cast(((#Loop/2)+1) as varchar(100)) + '] nvarchar(max) '
set #columns = #columns + ',[' + (select cast(((#Loop/2)+1) as varchar(100))) + ']'
set #values = #values + ',''' + #Col1 + #Col2 + ''''
exec sp_executesql #alter
set #loop = #loop + 2
End
set #values =( select substring( #values, 2, len(#values)))
select #values
set #columns =( select substring( #columns, 2, len(#columns)))
select #columns
declare #altertab nvarchar(max)
set #altertab = ' insert into newtab ( id, ' + #columns + ' ) values ( 1, ' + #values + ' )'
exec sp_executesql #altertab
drop table newtab
Drop table #tab_col
GO
This will not exactly give you your answer but you'll get some idea.

get count of columns that have a -1, 0, 1, 2 values for a single row

Using SQL Server, I need to get a column count that has -1, 0, 1, 2 for its values for each row. There are different number of columns per table (one table has 55 fields)
-1 value = no answer or unknown (unknown_count)
0 value = ok (ok_count)
1 value = bad (bad_count)
2 value = not applicable (na_count)
row 1 looks like this
rowid name field_1 field_2 field_3 field_4
1 line_1 -1 1 2 1
2 line_2 2 1 -1 0
etc...
Results i would like to see
rowid na_count ok_count bad_count unknown_count
1 1 0 2 1
2 1 1 1 1
Extra credit question.... i need to get a count of all the fields that are used to build the counts (so i can give a percentile report)
You need a combination of UNPIVOT and some aggregation. Unpivot the data to a more sensible form, and then group by rowid summing up the various values:
with data AS
(
select
rowid,
field,
value
from
( SELECT rowid, field_1,field_2,field_3,field_4
FROM MyTable) p
UNPIVOT
( value FOR field IN (field_1,field_2,field_3,field_4) ) as unpvt
)
SELECT
rowid,
SUM(CASE WHEN value = 2 THEN 1 ELSE 0 END) AS na_count,
SUM(CASE WHEN value = 0 THEN 1 ELSE 0 END) AS ok_count,
SUM(CASE WHEN value = 1 THEN 1 ELSE 0 END) AS bad_count,
SUM(CASE WHEN value = -1 THEN 1 ELSE 0 END) AS unknown_count
from data
group by rowId
Live example: http://www.sqlfiddle.com/#!6/b702c/1
Building on the answer by Jamiec and some code I've used before; If you don't want to type in all the column names in the query you can use dynamic sql to build the query like this:
declare #tab nvarchar(max)
set #tab = N'your_table' -- change to your table name
declare #cols nvarchar(max)
select #cols = coalesce(#cols+N',', N'') + quotename(c.name) from syscolumns c
inner join sysobjects o on c.id = o.id and o.xtype = 'u'
where o.name = #tab
and c.name not in ('rowid', 'name') -- exclude the columns that don't hold data values
order by c.colid
declare #sql nvarchar(max)
select #sql = N'
select
rowid,
sum(case when val = 2 then 1 else 0 end) as ''na_count'',
sum(case when val = 0 then 1 else 0 end) as ''ok_count'',
sum(case when val = 1 then 1 else 0 end) as ''bad_count'',
sum(case when val = -1 then 1 else 0 end) as ''unknown_count'',
count(*) as column_count
from (select rowid, ' + #cols + N' from ' + #tab + N') as src
unpivot (val for col in (' + #cols + N')) as unpvt
group by rowid'
exec sp_executesql #sql
I think it will be more effective to sum up all the columns in a dynamical script, rather than to use unpivot. On one million rows i get 16% vs 84% relative to the batch in the execution plan (this codeĀ“s output #query vs the unpivot code).
You can use the same logic to get the percentages of each column. Please let me know if you want me to provide you with code for that as well.
--DROP TABLE TMP_Test
CREATE TABLE TMP_Test
(
rowid INT PRIMARY KEY IDENTITY(1,1)
, name varchar(10)
, field_1 INT
, field_2 INT
, field_3 INT
, field_4 INT
)
INSERT INTO TMP_Test
SELECT name = 'line_1', field_1 = -1, field_2=1, field_3=2, field_4=1
UNION ALL
SELECT name = 'line_2', field_1 = 2, field_2=1, field_3=-1, field_4= 0
/*
WHILE((SELECT COUNT(*) FROM TMP_Test) < 1000000)
BEGIN
INSERT INTO TMP_Test
SELECT name, field_1, field_2, field_3, field_4 FROM TMP_Test
END
*/
GO
DECLARE #query VARCHAR(MAX) = '';
DECLARE #schema VARCHAR(128) = 'dbo';
DECLARE #table VARCHAR(128) = 'TMP_Test';
DECLARE #na_count VARCHAR(max) = '';
DECLARE #ok_count VARCHAR(max) = '';
DECLARE #bad_count VARCHAR(max) = '';
DECLARE #unknown_count VARCHAR(max) = '';
SELECT
#na_count = #na_count + IIF(#na_count = '', '', ' + ') + 'IIF(' + COLUMN_NAME + ' = 2, 1, 0)'
, #ok_count = #ok_count + IIF(#ok_count = '', '', ' + ') + 'IIF(' + COLUMN_NAME + ' = 0, 1, 0)'
, #bad_count = #bad_count + IIF(#bad_count = '', '', ' + ') + 'IIF(' + COLUMN_NAME + ' = 1, 1, 0)'
, #unknown_count = #unknown_count + IIF(#unknown_count = '', '', ' + ') + 'IIF(' + COLUMN_NAME + ' = -1, 1, 0)'
FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_SCHEMA = #schema
AND TABLE_NAME = #table
AND COLUMN_NAME NOT IN ('rowid', 'name')
ORDER BY ORDINAL_POSITION;
SET #query = '
SELECT
rowid
, na_count = ' + #na_count + '
, ok_count = ' + #ok_count + '
, bad_count = ' + #bad_count + '
, unknown_count = ' + #unknown_count + '
FROM [' + #schema + '].[' + #table + ']';
PRINT(#query);
EXEC(#query);

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.

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

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');

Resources