Find missing foreign key constraint on SQL Server database - sql

Sometimes a badly designed Entity Framework with code-first implementation creates tables without foreign key constraints.
To check the columns created without those constraints, I had to create a specific script.
The columns that should be a relationship Id are named as "BookingId".
The SQL Script:
SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS Where COLUMN_NAME like '%id' AND COLUMN_NAME <> 'Id' AND DATA_TYPE = 'int'
AND TABLE_NAME + COLUMN_NAME NOT IN (SELECT OBJECT_NAME(fk.parent_object_id) + cpa.name
FROM sys.foreign_keys fk
INNER JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
INNER JOIN sys.columns cpa ON fkc.parent_object_id = cpa.object_id AND fkc.parent_column_id = cpa.column_id
INNER JOIN sys.columns cref ON fkc.referenced_object_id = cref.object_id AND fkc.referenced_column_id = cref.column_id)
order by TABLE_NAME, COLUMN_NAME

This is better:
with fcc as
(
select
sch1.name as parent_schema_name,
object_name(fkc.parent_object_id) as parent_table_name,
object_name(fkc.constraint_object_id) as constraint_name,
sch2.name as referenced_schema,
object_name(fkc.referenced_object_id) as referenced_table_name,
substring(
( select ','
+ rtrim(col_name(fc.parent_object_id,parent_column_id)) as [data()]
from sys.foreign_key_columns as fc with (nolock)
inner join sys.foreign_keys as fk with (nolock) on fc.constraint_object_id = fk.[object_id]
and fc.constraint_object_id = fkc.constraint_object_id
order by fc.constraint_column_id
for xml path('')
), 2, 8000) as parent_columns,
substring(
( select ','
+ rtrim(col_name(fc.referenced_object_id,referenced_column_id)) as [data()]
from sys.foreign_key_columns as fc with (nolock)
inner join sys.foreign_keys as fk with (nolock) on fc.constraint_object_id = fk.[object_id]
and fc.constraint_object_id = fkc.constraint_object_id
order by constraint_column_id
for xml path('')
), 2, 8000) as referenced_columns
from sys.foreign_key_columns as fkc with (nolock)
inner join sys.objects as obj1 with (nolock) on fkc.parent_object_id = obj1.[object_id]
inner join sys.tables as tbl1 with (nolock) on tbl1.[object_id] = obj1.[object_id]
inner join sys.schemas as sch1 with (nolock) on sch1.[schema_id] = tbl1.[schema_id]
inner join sys.objects as obj2 with (nolock) on fkc.referenced_object_id = obj2.[object_id]
inner join sys.tables as tbl2 with (nolock) on tbl2.[object_id] = obj2.[object_id]
inner join sys.schemas as sch2 with (nolock) on sch2.[schema_id] = tbl2.[schema_id]
where obj1.type = 'U'
and
obj2.type = 'U'
group by obj1.[schema_id],
obj2.[schema_id],
fkc.parent_object_id,
constraint_object_id,
referenced_object_id,
sch1.name,
sch2.name
),
idxcols as
(
select
s.name as schemaname,
object_name(t.[object_id]) as objectname,
substring(
(
select ','
+ rtrim(ac.name)
from sys.tables as st
inner join sys.indexes as ix on st.[object_id] = ix.[object_id]
inner join sys.index_columns as ic on ix.[object_id] = ic.[object_id] and ix.[index_id] = ic.[index_id]
inner join sys.all_columns as ac on st.[object_id] = ac.[object_id] and ic.[column_id] = ac.[column_id]
where i.[object_id] = ix.[object_id]
and
i.index_id = ix.index_id
and
ic.is_included_column = 0
order by ac.column_id
for xml path('')
), 2, 8000 ) as keycols
from sys.indexes as i
inner join sys.tables as t on t.[object_id] = i.[object_id]
inner join sys.schemas as s on s.[schema_id] = t.[schema_id]
where i.[type] in (1,2,5,6)
and
i.is_unique_constraint = 0
and
t.is_ms_shipped = 0
)
select fcc.constraint_name,
fcc.parent_schema_name +'.' + fcc.parent_table_name as parent_table,
fcc.referenced_schema + '.' + fcc.referenced_table_name as reference_table,
fcc.parent_columns,
fcc.referenced_columns,
N'CREATE NONCLUSTERED INDEX idx_' +
fcc.referenced_table_name +
'_' +
fcc.constraint_name +
N' ON ' +
fcc.parent_schema_name +
'.' +
fcc.parent_table_name +
N'(' +
fcc.referenced_columns +
N');' as ddl_create
from fcc
where not exists ( SELECT 1 FROM idxcols
WHERE fcc.parent_schema_name = idxcols.schemaName
AND fcc.parent_table_name = idxcols.objectName
AND REPLACE(fcc.parent_columns,'' ,'') = idxcols.KeyCols)

Related

SQL Server Drop constraint by type or keys

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

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

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

How can you retrieve relationsships from a MSSQL database

I'm getting data from my MS-SQL 2016 Database. To determine the type of input fields, I need to know if there are any relations set up for any of my retrieved columns. I need this information to switch between input-fields and dropdown-menus.
I've already looked up in microsofts documentation (https://learn.microsoft.com/de-de/sql/relational-databases/system-catalog-views/sys-sql-dependencies-transact-sql?view=sql-server-2017) but couldn't find any sys-table containing the information I need. Am I even looking at the right place?
This may help.
;WITH Relationship
AS(
SELECT
ROW_NUMBER() OVER(ORDER BY fk.name) as Id,
CAST(fk.name as NVARCHAR(250)) as RelationName,
CAST(tr.name as NVARCHAR(250)) as ParentTable,
CAST((tr.name+'.'+cr.name) as NVARCHAR(250)) as ParentColumn,
CAST(tp.name as NVARCHAR(250)) as ReferencedTable,
CAST((tp.name+'.'+cp.name) as NVARCHAR(250)) as ReferencedColumn
FROM
sys.foreign_keys fk
INNER JOIN
sys.tables tp ON fk.parent_object_id = tp.object_id
INNER JOIN
sys.tables tr ON fk.referenced_object_id = tr.object_id
INNER JOIN
sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
INNER JOIN
sys.columns cp ON fkc.parent_column_id = cp.column_id AND fkc.parent_object_id = cp.object_id
INNER JOIN
sys.columns cr ON fkc.referenced_column_id = cr.column_id AND fkc.referenced_object_id = cr.object_id
--ORDER BY
-- tp.name, cp.column_id
)
SELECT * FROM Relationship
--Where ParentTable = 'Product' AND
--ReferencedTable='BillOfMaterials'
Use following two queries. Replace #schemaName, #tableName and #columnName as shown at the begging of the snippet.
DECLARE #schemaName AS SYSNAME= 'put here your schema name';
DECLARE #tableName AS SYSNAME= 'put here your table name';
DECLARE #columnName AS SYSNAME= 'put here your column name';
--The first one
SELECT f.name AS ForeignKey,
SCHEMA_NAME(f.SCHEMA_ID) SchemaName,
OBJECT_NAME(f.parent_object_id) AS TableName,
COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
SCHEMA_NAME(o.SCHEMA_ID) ReferenceSchemaName,
OBJECT_NAME(f.referenced_object_id) AS ReferenceTableName,
COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id
INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id
WHERE SCHEMA_NAME(o.SCHEMA_ID) = #schemaName
AND OBJECT_NAME(f.referenced_object_id) = #tableName
AND COL_NAME(fc.parent_object_id, fc.parent_column_id) = #columnName
ORDER BY SCHEMA_NAME(f.SCHEMA_ID);
--The second one
SELECT f.name AS ForeignKey,
SCHEMA_NAME(f.SCHEMA_ID) SchemaName,
OBJECT_NAME(f.parent_object_id) AS TableName,
COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
SCHEMA_NAME(o.SCHEMA_ID) ReferenceSchemaName,
OBJECT_NAME(f.referenced_object_id) AS ReferenceTableName,
COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id
INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id
WHERE OBJECT_NAME(F.PARENT_object_id) = #tableName
AND SCHEMA_NAME(F.SCHEMA_ID) = #schemaName
AND COL_NAME(fc.parent_object_id, fc.parent_column_id) = #columnName
ORDER BY SCHEMA_NAME(O.SCHEMA_ID),
OBJECT_NAME(f.referenced_object_id);

SQL Server 2005+ - Get All Default and Check Constraints

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

Generate CREATE scripts for a list of indexes

As part of a collation changing exercise, I have a list of indexes (122) that needs to be dropped and then re-created. How can I re-create these indexes without having to go through the GUI and scripting it to a query window each time?
My list of indexes is obtained from this script
WITH indexCTE AS
(
SELECT Table_Name, Column_Name, Collation_Name
FROM information_schema.columns
WHERE Collation_Name IS NOT NULL AND Collation_Name = 'Modern_Spanish_CI_AS'
),
indexCTE2 AS
(
SELECT i.Name [Index Name], OBJECT_NAME(i.object_ID) [Table Name], c.Name [Column Name]
FROM sys.indexes i
INNER JOIN sys.index_columns ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id
INNER JOIN sys.columns c ON ic.column_id = c.column_id AND ic.object_id = c.OBJECT_ID
WHERE EXISTS (SELECT 1 FROM indexCTE t1 WHERE t1.Table_Name = OBJECT_NAME(i.object_ID) AND t1.Column_Name = c.Name)
) SELECT * FROM indexCTE2
As you can probably tell, I'm still a Jr. DBA so please be patient with me!
Thanks!
You're pretty close, I'd say - I tried this, can you verify if this works for you and shows you the expected 122 indices to be recreated??
UPDATE: added functionality to determine CLUSTERED vs. NONCLUSTERED index type, and to add INCLUDEd columns to the index definition.
WITH indexCTE AS
(
SELECT DISTINCT
i.index_id, i.name, i.object_id
FROM
sys.indexes i
INNER JOIN
sys.index_columns ic
ON i.index_id = ic.index_id AND i.object_id = ic.object_id
WHERE
EXISTS (SELECT * FROM sys.columns c
WHERE c.collation_name = 'Modern_Spanish_CI_AS'
AND c.column_id = ic.column_id AND c.object_id = ic.object_id)
),
indexCTE2 AS
(
SELECT
indexCTE.name 'IndexName',
OBJECT_NAME(indexCTE.object_ID) 'TableName',
CASE indexCTE.index_id
WHEN 1 THEN 'CLUSTERED'
ELSE 'NONCLUSTERED'
END AS 'IndexType',
(SELECT DISTINCT c.name + ','
FROM
sys.columns c
INNER JOIN
sys.index_columns ic
ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 0
WHERE
indexCTE.OBJECT_ID = ic.object_id
AND indexCTE.index_id = ic.index_id
FOR XML PATH('')
) ixcols,
ISNULL(
(SELECT DISTINCT c.name + ','
FROM
sys.columns c
INNER JOIN
sys.index_columns ic
ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 1
WHERE
indexCTE.OBJECT_ID = ic.object_id
AND indexCTE.index_id = ic.index_id
FOR XML PATH('')
), '') includedcols
FROM
indexCTE
)
SELECT
'CREATE ' + IndexType + ' INDEX ' + IndexName + ' ON ' + TableName +
'(' + SUBSTRING(ixcols, 1, LEN(ixcols)-1) +
CASE LEN(includedcols)
WHEN 0 THEN ')'
ELSE ') INCLUDE (' + SUBSTRING(includedcols, 1, LEN(includedcols)-1) + ')'
END
FROM
indexCTE2
ORDER BY
TableName, IndexName
Do you get the CREATE INDEX statements you're looking for??
Marc
Great script Marc.
The only thing I think it is missing is the ascending or descending order indicator on each column. I have amended your script to include a case statement for the indexed columns to add in ASC or DESC depending on the is_descending_key column of the sys.index_columns view.
WITH indexCTE AS
(
SELECT DISTINCT
i.index_id, i.name, i.object_id
FROM
sys.indexes i
INNER JOIN
sys.index_columns ic
ON i.index_id = ic.index_id AND i.object_id = ic.object_id
WHERE
EXISTS (SELECT * FROM sys.columns c
WHERE
c.collation_name = 'Modern_Spanish_CI_AS'
AND c.column_id = ic.column_id AND c.object_id = ic.object_id)
),
indexCTE2 AS
(
SELECT
indexCTE.name 'IndexName',
OBJECT_NAME(indexCTE.object_ID) 'TableName',
CASE indexCTE.index_id
WHEN 1 THEN 'CLUSTERED'
ELSE 'NONCLUSTERED'
END AS 'IndexType',
(SELECT CASE WHEN ic.is_descending_key = 1 THEN c.name + ' DESC ,'
ELSE c.name + ' ASC ,'
END
FROM
sys.columns c
INNER JOIN
sys.index_columns ic
ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 0
WHERE
indexCTE.OBJECT_ID = ic.object_id
AND indexCTE.index_id = ic.index_id
FOR XML PATH('')
) ixcols,
ISNULL(
(SELECT DISTINCT c.name + ','
FROM
sys.columns c
INNER JOIN
sys.index_columns ic
ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 1
WHERE
indexCTE.OBJECT_ID = ic.object_id
AND indexCTE.index_id = ic.index_id
FOR XML PATH('')
), '') includedcols
FROM
indexCTE
)
SELECT
'CREATE ' + IndexType + ' INDEX ' + IndexName + ' ON ' + TableName +
'(' + SUBSTRING(ixcols, 1, LEN(ixcols)-1) +
CASE LEN(includedcols)
WHEN 0 THEN ')'
ELSE ') INCLUDE (' + SUBSTRING(includedcols, 1, LEN(includedcols)-1) + ')'
END
FROM
indexCTE2
ORDER BY
TableName, IndexName
DECLARE #T_IndexInfo TABLE
(
IndID NVARCHAR(128),
ObjectID NVARCHAR(128),
ColID NVARCHAR(128),
IndexName NVARCHAR(128),
TableName NVARCHAR(128),
ColumnName NVARCHAR(128),
KeyNo NVARCHAR(128),
ColType NVARCHAR(128)
)
INSERT INTO #T_IndexInfo
SELECT I.IndID,
SO.ID AS 'ObjectID',
SK.ColID,
I.Name AS 'IndexName',
SO.Name AS 'TableName',
SC.Name AS 'ColumnName',
Sk.KeyNo,
CASE WHEN Sk.KeyNo = 0 THEN 'Include'
ELSE 'Normal'
END AS 'ColType'
FROM sys.sysindexes I
INNER JOIN sys.sysobjects SO ON SO.ID = I.ID
AND SO.xtype = 'U'
INNER JOIN sys.sysindexkeys SK ON SK.IndID = I.IndID
AND SO.ID = SK.ID
INNER JOIN sys.syscolumns SC ON SC.ID = SO.ID
AND SC.ColID = SK.ColID
WHERE I.IndID > 0
AND I.IndID < 255
AND ( I.Status & 64 ) = 0
-- AND ( I.status & 2048 ) <> 2048 /******** comment this if PK's also need to be recreated *****/
ORDER BY SO.Name,
I.Name
DECLARE #T_Final TABLE
(
TableName NVARCHAR(128),
IndexName NVARCHAR(128),
NormalColumns NVARCHAR(MAX),
IncludedColumns NVARCHAR(MAX)
)
INSERT INTO #T_Final
SELECT DISTINCT
TableName,
IndexName,
STUFF(( SELECT ',[' + ColumnName + ']'
FROM #T_IndexInfo
WHERE IndID = I.IndID
AND ObjectID = I.ObjectID
AND ColType = 'Normal'
ORDER BY KeyNo
FOR
XML PATH('')
), 1, 1, '') AS 'NormalColumns',
STUFF(( SELECT ',[' + ColumnName + ']'
FROM #T_IndexInfo
WHERE IndID = I.IndID
AND ObjectID = I.ObjectID
AND ColType = 'Include'
FOR
XML PATH('')
), 1, 1, '') AS 'IncludedColumns'
FROM #T_IndexInfo I;
WITH indexCTE AS
(
SELECT Table_Name, Column_Name --, Collation_Name
FROM information_schema.columns
WHERE Collation_Name IS NOT NULL AND Collation_Name = 'Modern_Spanish_CI_AS'
),
indexCTE2 AS
(
SELECT i.Name [Index Name], OBJECT_NAME(i.object_ID) [Table Name], c.Name [Column Name]
FROM sys.indexes i
INNER JOIN sys.index_columns ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id
INNER JOIN sys.columns c ON ic.column_id = c.column_id AND ic.object_id = c.OBJECT_ID
WHERE EXISTS (SELECT 1 FROM indexCTE t1 WHERE t1.Table_Name = OBJECT_NAME(i.object_ID) AND t1.Column_Name = c.Name)
)
SELECT IndexName, TableName, NormalColumns, IncludedColumns
INTO #temp1
FROM #T_Final z INNER JOIN indexCTE2 x ON z.IndexName = x.[Index Name]
-- To generate CREATE INDEX SCRIPT
SELECT 'CREATE INDEX [' + IndexName + '] ON [' + TableName + '].('
+ NormalColumns + ')' + CASE WHEN IncludedColumns IS NULL THEN ''
ELSE ' INCLUDE (' + IncludedColumns + ')'
END AS 'CreateScript'
FROM #temp1
-- To generate DROP INDEX SCRIPT
SELECT 'DROP INDEX [' + TableName + '].[' + IndexName + ']' AS 'DropScript'
FROM #temp1
DROP TABLE #temp1
There's a relative complete solution at TechNet.
Adjust the query to your desire:
sys.tables to sys.views
remove default values in select
remove/add some where conditions
This is a bit off topic, but thought I would suggest this anyways:
If you don't want to keep executing your scripts in sql server management studio you can create a runmyscripts.bat file including something like:
#echo off
echo Execute Scripts...
sqlcmd -i C:\Scripts\myscript1.sql
sqlcmd -i C:\Scripts\myscript2.sql
echo Scripts Complete.
echo Press any button to exit.
pause