Drop index in SQL Server - sql-server

Can I drop all indexes of a schema in SQL Server according a condition?
I explain: I want drop all the indexes that contains a columns there types float, in schema XX.
I did this script below but I'm not sure of the line of the type of columns:
If Exists (Select *
From sys.indexes
Where name = 'indexName'
And Object_Id = Object_Id('schema xx.TABLE_NAME')
And Object_Id =Object_Id ('nchar', 'nvarchar'))
Drop Index indexNameOn dbo.Table_Name;
Thank you

This query, will help you to find all indexes where used columns with float datatype.
SELECT i.[name] as IndexName,
o.[name] as TableName
FROM sys.indexes i
INNER JOIN sys.objects o
ON i.[object_id] = o.[object_id] AND o.[type] = 'U' --USER_TABLE
INNER JOIN sys.index_columns ic
ON i.[object_id] = ic.[object_id]
INNER JOIN sys.columns c
ON c.column_id = ic.column_id AND c.[object_id] = ic.[object_id]
INNER JOIN sys.types t
ON c.system_type_id = t.system_type_id AND t.[name] = 'float'
On MSDN you can find all info about this tables. To DROP all automatically and search in all DB's you need to use dynamic SQL.
This query works in current DB only, we need to search in each not-system DB.
DECLARE #query nvarchar(max) = N''
-- Create a table to store a results of a search
IF OBJECT_ID(N'tempdb..##search_index') IS NOT NULL DROP TABLE ##search_index
CREATE TABLE ##search_index (
[db_name] sysname,
[index_name] sysname,
[schema_name] sysname,
[table_name] sysname
)
-- here we get all DBs except system (master, tempdb etc.)
;WITH cte AS (
SELECT CONCAT(N'USE ',QUOTENAME([name]),';') as db,
[name] as [db_name]
FROM sys.databases -- take all DBs
WHERE database_id > 4 -- not system
)
-- prepare a query for each DB
SELECT #query = #query + db + CHAR(13) +
N'INSERT INTO ##search_index
SELECT '''+ [db_name] + ''' as DB,
i.[name] as IndexName,
sch.[name] as SchemaName,
o.[name] as TableName
FROM sys.indexes i
INNER JOIN sys.objects o
ON i.[object_id] = o.[object_id] AND o.[type] = ''U'' -- USER_TABLE
INNER JOIN sys.schemas sch
ON o.[schema_id] = sch.[schema_id]
INNER JOIN sys.index_columns ic
ON i.[object_id] = ic.[object_id]
INNER JOIN sys.columns c
ON c.column_id = ic.column_id AND c.[object_id] = ic.[object_id]
INNER JOIN sys.types t
ON c.system_type_id = t.system_type_id AND t.[name] = ''float'';' + CHAR(13) + CHAR(13)
FROM cte
PRINT #query
-- execute query
EXEC(#query)
-- take a look at the results
SELECT *
FROM ##search_index
With the PRINT you can see what query was generated. The sample is here:
USE [Test];
INSERT INTO ##search_index
SELECT 'Test' as DB,
i.[name] as IndexName,
sch.[name] as SchemaName,
o.[name] as TableName
FROM sys.indexes i
INNER JOIN sys.objects o
ON i.[object_id] = o.[object_id] AND o.[type] = 'U' -- USER_TABLE
INNER JOIN sys.schemas sch
ON o.[schema_id] = sch.[schema_id]
INNER JOIN sys.index_columns ic
ON i.[object_id] = ic.[object_id]
INNER JOIN sys.columns c
ON c.column_id = ic.column_id AND c.[object_id] = ic.[object_id]
INNER JOIN sys.types t
ON c.system_type_id = t.system_type_id AND t.[name] = 'float';
USE [Another One];
INSERT INTO ##search_index
SELECT 'Another One' as DB,
...
The output is like:
db_name index_name schema_name table_name
Test PK_Period dbo Periods
Another Test PK_Test dbo Test
Then you need to check, if you want|need to delete this indexes. If you are sure about this you can use this:
DECLARE #query_to_drop nvarchar(max) = N''
SELECT #query_to_drop = #query_to_drop + N'USE ' + QUOTENAME([db_name]) +'; DROP INDEX ' + QUOTENAME([index_name]) + ' ON ' + QUOTENAME([schema_name]) +'.'+ QUOTENAME([table_name]) +';'+ CHAR(13)
FROM ##search_index
EXEC(#query_to_drop)
That will give you query like:
USE [Test]; DROP INDEX [PK_Period] ON [dbo].[Periods];
USE [Another Test]; DROP INDEX [PK_Test] ON [dbo].[Test];

Related

sp_execute SQL giving different results to raw query

I have found a few similar questions to this but all the solutions seem to relate to passing date parameters to sp_executesql which is not what I am doing...
I have a .NET application which connects to a SQL database using the SqlConnection and SqlCommand classes. When I run the application and monitor the database queries using SQL Server Profiler, I can see that the .NET app is generating the following code:
exec sp_executesql N'IF object_id(''tempdb..#ParmsInProc'') IS NOT NULL DROP TABLE #ParmsInProc
SELECT o.name AS ProcName, o.object_id, p.name AS ParamName, p.system_type_id, p.user_type_id
INTO #ParmsInProc
FROM sys.objects o
JOIN sys.parameters p
ON o.object_id = p.object_id
JOIN sys.types t
ON t.system_type_id = p.system_type_id AND t.user_type_id = p.user_type_id
WHERE type_desc = ''SQL_STORED_PROCEDURE'' AND o.name = ''#sp''
SELECT *
FROM #ParmsInProc p
LEFT JOIN (
SELECT *
FROM #ParmsInProc
WHERE system_type_id = 56 AND user_type_id = 56
) ints
ON p.system_type_id = ints.system_type_id AND p.user_type_id = ints.user_type_id',N'#sp nvarchar(14)',#sp=N'sp_myProcedure'
If I run that code in SSMS, I get no results. However, if I copy out the query and replace the parameter placeholder with the actual value, I get
IF object_id('tempdb..#ParmsInProc') IS NOT NULL DROP TABLE #ParmsInProc
SELECT o.name AS ProcName, o.object_id, p.name AS ParamName, p.system_type_id, p.user_type_id
INTO #ParmsInProc
FROM sys.objects o
JOIN sys.parameters p
ON o.object_id = p.object_id
JOIN sys.types t
ON t.system_type_id = p.system_type_id AND t.user_type_id = p.user_type_id
WHERE type_desc = 'SQL_STORED_PROCEDURE' AND o.name = 'sp_myProcedure'
SELECT *
FROM #ParmsInProc p
LEFT JOIN (
SELECT *
FROM #ParmsInProc
WHERE system_type_id = 56 AND user_type_id = 56
) ints
ON p.system_type_id = ints.system_type_id AND p.user_type_id = ints.user_type_id
and if I run that, I get one result (which is the outcome I expect)
What could be causing this?
If you try to "debug" your initial query, you will see that #sp is being passed as a procedure name, instead of the actual value for your parameter.
You can see this by writing the following:
declare #spname nvarchar(100) = 'my_storedproc';
declare #sql nvarchar(max) = ' IF object_id(''tempdb..#ParmsInProc'') IS NOT NULL DROP TABLE #ParmsInProc
SELECT o.name AS ProcName, o.object_id, p.name AS ParamName, p.system_type_id, p.user_type_id
INTO #ParmsInProc
FROM sys.objects o
JOIN sys.parameters p
ON o.object_id = p.object_id
JOIN sys.types t
ON t.system_type_id = p.system_type_id AND t.user_type_id = p.user_type_id
WHERE type_desc = ''SQL_STORED_PROCEDURE'' AND o.name = ''#sp'';
SELECT *
FROM #ParmsInProc p
LEFT JOIN (
SELECT *
FROM #ParmsInProc
WHERE system_type_id = 56 AND user_type_id = 56
) ints
ON p.system_type_id = ints.system_type_id AND p.user_type_id = ints.user_type_id;'
print #sql
The following is being generated:
What you need to do is to just pass it as a parameter, no need for quotes.
I modified a little your query just to be able to print it, by storing the sql query into a variable but you can of course execute it as you had it, inline:
declare #spname nvarchar(100) = 'my_storedproc';
declare #sql nvarchar(max) = ' IF object_id(''tempdb..#ParmsInProc'') IS NOT NULL DROP TABLE #ParmsInProc
SELECT o.name AS ProcName, o.object_id, p.name AS ParamName, p.system_type_id, p.user_type_id
INTO #ParmsInProc
FROM sys.objects o
JOIN sys.parameters p
ON o.object_id = p.object_id
JOIN sys.types t
ON t.system_type_id = p.system_type_id AND t.user_type_id = p.user_type_id
WHERE type_desc = ''SQL_STORED_PROCEDURE'' AND o.name = #sp;
SELECT *
FROM #ParmsInProc p
LEFT JOIN (
SELECT *
FROM #ParmsInProc
WHERE system_type_id = 56 AND user_type_id = 56
) ints
ON p.system_type_id = ints.system_type_id AND p.user_type_id = ints.user_type_id;'
print #sql
exec sp_executesql #sql, N'#sp nvarchar(100)', #sp = #spname
This will execute successfully and you get to see the printed sql query under the Messages tab :)

Count all rows from all tables in two databases on different servers

I would like my query to return the table name, and rowcount for all of the tables on our two reporting servers. They both have the same tables. Also, I already added the linked server the other day between these two.
Query so far for one server, not sure how to add a third column connected with our other server though:
SELECT
t.NAME AS TableName,
p.[Rows]
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units a ON p.partition_id = a.container_id
WHERE
t.NAME NOT LIKE 'dt%' AND
i.OBJECT_ID > 255 AND
i.index_id <= 1
GROUP BY
t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
ORDER BY
object_name(i.object_id)
Desired output:
TableName DB1_rows DB2_Rows
----------+-----------+-----------
Account | 20,000 | 19,388
Contacts | 1,234 | 1,390
Bla | 2,330 | 2,430
This would be a great use for Common Table Expressions (CTE's) as you can run multiple queries, then join those query results together and analyze/manipulate them in different ways:
/* Use the WITH keyword to start your first expression */
WITH SERVER_A AS (
SELECT
t.NAME AS TableName,
p.[Rows] AS NumRows
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units a ON p.partition_id = a.container_id
WHERE
t.NAME NOT LIKE 'dt%' AND
i.OBJECT_ID > 255 AND
i.index_id <= 1
GROUP BY
t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
),
/* Then chain additional expressions (this time adding the linked server into the table name) */
SERVER_B AS (
SELECT
t.NAME AS TableName,
p.[Rows] AS NumRows
FROM
LINKED_SERVER_NAME.sys.tables t
INNER JOIN
LINKED_SERVER_NAME.sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
LINKED_SERVER_NAME.sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN
LINKED_SERVER_NAME.sys.allocation_units a ON p.partition_id = a.container_id
WHERE
t.NAME NOT LIKE 'dt%' AND
i.OBJECT_ID > 255 AND
i.index_id <= 1
GROUP BY
t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
)
/* Then join the two together on a common column */
SELECT
A.TableName,
A.NumRows AS DB1_Rows,
B.NumRows AS DB2_Rows
FROM SERVER_A A
LEFT JOIN SERVER_B B ON
A.TableName = B.TableName
ORDER BY
A.TableName ASC
You could also accomplish this with APPLY statements or correlated sub-queries, but the advantage to using a CTE is that you're not running the sub-query for every single row that the parent query returns. Using a CTE you can run a query and then simply treat that query result as if it were a another table.
Obviously you'll want to test this. I don't have access to a SQL Server at the moment, so there may be a typo here or there.
DECLARE #RESULT TABLE (TableName VARCHAR(MAX), DB1_rows INT, DB2_Rows INT)
DECLARE #TABLENAME VARCHAR(MAX), #SQL VARCHAR(MAX)
DECLARE cCursor CURSOR FOR
SELECT name FROM sys.tables
OPEN cCursor
FETCH NEXT FROM cCursor INTO #TABLENAME
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = 'SELECT ''' + #TABLENAME + ''' , COUNT(*) FROM ' + #TABLENAME
DECLARE #FirstColumn VARCHAR(MAX) = (SELECT TOP 1 c.name FROM sys.columns c JOIN sys.tables t ON t.object_id = c.object_id WHERE t.name = #TABLENAME ORDER BY column_id)
SET #SQL = 'SELECT ''' + #TABLENAME + ''' , SUM(CASE WHEN A.' + #FirstColumn + ' IS NOT NULL THEN 1 ELSE 0 END), SUM(CASE WHEN B.' + #FirstColumn + ' IS NOT NULL THEN 1 ELSE 0 END) '
+'FROM LIVE.dbo.' + #TABLENAME + ' AS A FULL JOIN TEST.dbo.' + #TABLENAME + ' AS B on 1=0'
INSERT INTO #RESULT EXEC (#SQL)
FETCH NEXT FROM cCursor INTO #TABLENAME
END
CLOSE cCURSOR
DEALLOCATE cCURSOR
SELECT * FROM #RESULT
Just change the LIVE and TEST and the 'dbo' schema name on the second line of the 'SET #SQL' statement to the names of the 2 databases.
EDIT: Also you can add one of the database names.schema names to the 'SELECT name FROM sys.tables' statement at the top, plus any table name filtering you wanted to do.
If you are able to get the result from one server, then you can get the same from other server if the linked server is setup.
You can do it by using the 4 part name. For example:
Select ...
From ServerName.DBName.schema.TableName
...

SQL Server guessing missing foreign keys

I try to guess missing foreign keys using the following SQL code
DECLARE #ColumnList AS TABLE
(
TableName varchar(255) NOT NULL,
ColumnName varchar(255) NOT NULL,
PKTableName varchar(255),
PKColumnName varchar(255),
HasForeignKey bit NOT NULL
)
-- Find all column names that occur more than once.
-- Exclude archive and staging tables.
INSERT INTO #ColumnList
(TableName,
ColumnName,
PKTableName,
PKColumnName,
HasForeignKey)
SELECT t.NAME AS TableName,
c.NAME AS ColumnName,
NULL AS PKTableName,
NULL AS PKColumnName,
CASE
WHEN f1.parent_object_id IS NOT NULL THEN 1
WHEN f2.referenced_object_id IS NOT NULL THEN 1
ELSE 0
END AS HasForeignKey
FROM sys.tables AS t
JOIN sys.columns AS c
ON c.object_id = t.object_id
JOIN sys.types AS y
ON c.system_type_id = y.system_type_id
LEFT JOIN sys.foreign_key_columns AS f1
ON f1.parent_object_id = t.object_id AND f1.parent_column_id = c.column_id
LEFT JOIN sys.foreign_key_columns AS f2
ON f2.referenced_object_id = t.object_id AND f2.referenced_column_id = c.column_id
WHERE t.is_ms_shipped = 0 AND y.NAME IN ('bigint', 'int', 'smallint', 'tinyint', 'uniqueidentifier');
SELECT TableName,
ColumnName,
PKTableName,
PKColumnName
FROM #ColumnList
WHERE HasForeignKey = 0
AND ColumnName IN (SELECT ColumnName
FROM #ColumnList
GROUP BY ColumnName
HAVING Count(*) > 1)
ORDER BY ColumnName,
TableName;
That works fine and displays many candidates. I do not know, however, how to display the table name and the column name of the possible primary key. Any help will be appreciated.
Try this
DECLARE #ColumnList AS TABLE
(
TableName varchar(255) NOT NULL,
ColumnName varchar(255) NOT NULL,
PKTableName varchar(255),
PKColumnName varchar(255),
HasForeignKey bit NOT NULL
)
-- Find all column names that occur more than once.
-- Exclude archive and staging tables.
INSERT INTO #ColumnList
(TableName,
ColumnName,
PKTableName,
PKColumnName,
HasForeignKey)
SELECT t.NAME AS TableName,
c.NAME AS ColumnName,
t2.NAME AS PKTableName,
c2.NAME AS PKColumnName,
CASE
WHEN f1.parent_object_id IS NOT NULL THEN 1
WHEN f2.referenced_object_id IS NOT NULL THEN 1
ELSE 0
END AS HasForeignKey
FROM sys.tables AS t
JOIN sys.columns AS c
ON c.object_id = t.object_id
JOIN sys.types AS y
ON c.system_type_id = y.system_type_id
LEFT JOIN sys.columns c2
ON (c.Name = c2.Name)
JOIN sys.tables t2
ON (c2.object_id = t2.object_id AND t.object_id <> t2.object_id)
LEFT JOIN sys.foreign_key_columns AS f1
ON f1.parent_object_id = t.object_id AND f1.parent_column_id = c.column_id
LEFT JOIN sys.foreign_key_columns AS f2
ON f2.referenced_object_id = t.object_id AND f2.referenced_column_id = c.column_id
WHERE t.is_ms_shipped = 0 AND y.NAME IN ('bigint', 'int', 'smallint', 'tinyint', 'uniqueidentifier');
SELECT TableName,
ColumnName,
PKTableName,
PKColumnName
FROM #ColumnList
WHERE HasForeignKey = 0
AND ColumnName IN (SELECT ColumnName
FROM #ColumnList
GROUP BY ColumnName
HAVING Count(*) > 1)
ORDER BY ColumnName,
TableName;
I would try doing a LEFT OUTER JOIN to primary keys based on the column name:
LEFT OUTER JOIN
(
INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CCU ON
CCU.CONSTRAINT_CATALOG = TC.CONSTRAINT_CATALOG AND
CCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA AND
CCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME AND
CCU.TABLE_CATALOG = TC.TABLE_CATALOG AND
CCU.TABLE_SCHEMA = TC.TABLE_SCHEMA AND
CCU.TABLE_NAME = TC.TABLE_NAME
) ON
CCU.COLUMN_NAME = C.ColumnName AND -- Use the #ColumnList.ColumnName here
TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
This breaks down a bit with composite PKs. It also won't work if the names don't match - for example, some people will use "id" for the PK of "Person", but in the FK it would be "person_id".

Get a List of all Primary Keys in a Database

Is this the best way to - Get a List of all Primary Keys in a Database - or is there something better?
SELECT
KCU.TABLE_NAME AS Table_Name,
KCU.CONSTRAINT_NAME AS Constraint_Name,
KCU.COLUMN_NAME AS COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU
ON KCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA
AND KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
AND KCU.TABLE_SCHEMA = TC.TABLE_SCHEMA
AND KCU.TABLE_NAME = TC.TABLE_NAME
WHERE
TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
ORDER BY
KCU.TABLE_SCHEMA, KCU.TABLE_NAME, KCU.CONSTRAINT_NAME
USE databasename;
GO
SELECT i.name AS IndexName, OBJECT_NAME(ic.OBJECT_ID) AS TableName,
COL_NAME(ic.OBJECT_ID,ic.column_id) AS ColumnName
FROM sys.indexes AS i
INNER JOIN sys.index_columns AS ic
ON i.OBJECT_ID = ic.OBJECT_ID
AND i.index_id = ic.index_id
WHERE i.is_primary_key = 1
This query will extract the all primary key constraints from the database...
u just need to execute this query and type the database name in first line
The following syntax give you all constraints in database in use.
select * from sys.key_constraints;
If you want the data type information as well:
SELECT
so.name 'Table Name',
c.name 'Column Name',
t.Name 'Data type',
c.max_length 'Max Length',
c.precision ,
c.scale ,
c.is_nullable,
ISNULL(i.is_primary_key, 0) 'Primary Key'
FROM
sys.columns c
INNER JOIN
sys.types t ON c.user_type_id = t.user_type_id
LEFT OUTER JOIN
sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id
LEFT OUTER JOIN
sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
INNER JOIN
sysobjects so ON c.object_id = so.id
WHERE
i.is_primary_key = 1 and
so.xtype = 'U'
Order By 'Table Name', 'Column Name'
look on link
EXEC sp_pkeys '<tablename>'
EXEC sp_helpconstraint '<tablename>'
sp_pkeys will return a row for each
column that participates in the
primary key for . The
columns you are likely most interested
in are COLUMN_NAME and PK_NAME.
sp_helpconstraint will list all
constraints for , including
foreign keys that reference the table.
In the first recordset, there will
only be a column called Object Name
(kind of useless, since that's what
you passed in). In the second
resultset, there will be the following
columns: constraint_type,
constraint_name, and constraint_keys.
If you are doing this from java you can also use the getPrimaryKeys method in the databasemetadata object. Perhaps other languages have similar ways to do it.

Get the unique constraint columns list (in TSQL)?

I can get a list of unique constraints fairly easily with the following query:
select * from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE='UNIQUE'
But how do I get a list of the columns that each unique constraint applies to?
Ed is correct, the columns are exposed on the constraint column usage view, here is the SQL for it.
select TC.Constraint_Name, CC.Column_Name from information_schema.table_constraints TC
inner join information_schema.constraint_column_usage CC on TC.Constraint_Name = CC.Constraint_Name
where TC.constraint_type = 'Unique'
order by TC.Constraint_Name
See INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
SELECT *
FROM sys.indexes i
JOIN sys.index_columns ic
ON i.index_id = ic.index_id
AND i.object_id = ic.object_id
WHERE i.is_unique_constraint = 1;
Necromancing.
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE is incredibly slow.
Use sys.indexes, join the table, schema, object, and as an added bonus, you get not only unique constraints, but also unique indices, including filter.
-- CREATE TABLE dbo.T_User( USR_ID int NOT NULL, USR_User nvarchar(256) NULL, USR_Status int NOT NULL );
-- ALTER TABLE dbo.T_User ADD CONSTRAINT UC_T_User_USR_User UNIQUE(USR_User)
-- IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'dbo.T_User') AND name = N'IX_T_User_USR_User')
-- CREATE UNIQUE INDEX IX_T_User_USR_User ON dbo.T_User(USR_User)
-- WHERE (USR_User IS NOT NULL AND USR_Status=(1))
SELECT
sch.name
,st.name
,i.name
,i.has_filter
,i.filter_definition
,i.is_unique
,i.is_primary_key
,i.is_unique_constraint
,CASE WHEN i.is_unique_constraint = 1
THEN N'ALTER TABLE ' + QUOTENAME(sch.name) + N'.' + QUOTENAME(st.name) + N' DROP CONSTRAINT ' + QUOTENAME(i.name) + N'; '
ELSE N'DROP INDEX ' + QUOTENAME(i.name) + N' ON ' + QUOTENAME(sch.name) + '.' + QUOTENAME(st.name) + '; '
END AS sql
FROM sys.indexes AS i
INNER JOIN sys.index_columns AS ic
ON i.index_id = ic.index_id
AND i.object_id = ic.object_id
INNER JOIN sys.tables AS st
ON st.object_id = i.object_id
INNER JOIN sys.objects AS syso
ON syso.object_id = st.object_id
AND syso.is_ms_shipped = 0
INNER JOIN sys.schemas AS sch
ON sch.schema_id = st.schema_id
WHERE (1=1)
AND NOT EXISTS
(
SELECT *
FROM sys.extended_properties AS xp
WHERE xp.minor_id = 0
AND xp.major_id = st.object_id
AND xp.name = 'microsoft_database_tools_support'
)
-- AND sch.name = 'dbo'
-- AND st.name = 'T_Benutzer'
AND
(
i.is_unique_constraint = 1
OR
(i.is_unique = 1 AND i.is_primary_key = 0)
)
;
Just for reference of mySQL users,
Same thing can be achieved with below queries:
To find any unique constraint on a table
select * from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE='UNIQUE' and table_name='db_my_table'
To find unique column list with all column
select * from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where CONSTRAINT_NAME='cons_name' and TABLE_NAME='db_my_table'
to find unique column list with required view
select CONSTRAINT_NAME,COLUMN_NAME,TABLE_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where CONSTRAINT_NAME='cons_name' and TABLE_NAME='db_my_table'
Here is a better solution, which lists the constraint columns in a proper sort order, with added ASC/DESC flag. It also allows filtering by catalog, schema or table name.
SELECT sh.name AS schema_name,
i.name AS constraint_name,
t.name AS table_name,
c.name AS column_name,
ic.key_ordinal AS column_position,
ic.is_descending_key AS is_desc
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.tables AS t
ON t.object_id = i.object_id
INNER JOIN sys.columns c
ON t.object_id = c.object_id AND ic.column_id = c.column_id
INNER JOIN sys.objects AS syso
ON syso.object_id = t.object_id AND syso.is_ms_shipped = 0
INNER JOIN sys.schemas AS sh
ON sh.schema_id = t.schema_id
INNER JOIN information_schema.schemata sch
ON sch.schema_name = sh.name
WHERE i.is_unique_constraint = 1
-- AND sch.catalog_name = 'EmployeesQX'
-- AND sh.name = 'dbo'
ORDER BY sh.name, i.name, ic.key_ordinal;

Resources