How do I determine the column position in a compound key - sql

I need to identify all the primary keys in a db. The following code appears to do the job quite well:
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
The problem I have is that some of the keys are compound keys. This query identifies which keys are compound (multiple rows for a particular indexName in the sys.indexes table) but it does not show me the order. I need to know this because:
PRIMARY KEY CLUSTERED
(
[bl_id] ASC,
[fl_id] ASC,
[rm_id] ASC
)
is not the same as:
PRIMARY KEY CLUSTERED
(
[rm_id] ASC
[fl_id] ASC,
[bl_id] ASC,
)

key_ordinal seems to do the trick:
SELECT i.name AS IndexName,
OBJECT_NAME (ic.OBJECT_ID) AS TableName,
COL_NAME (ic.OBJECT_ID, ic.column_id) AS ColumnName,
ic.Key_ordinal as ColumnOrder
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
ORDER BY ic.OBJECT_ID, ic.Key_ordinal

Related

'ProductNumber'

I have a few questions I don't have any experience in a SQL, so my questions will looks funny to some experts here (-:
I want to run some checks in my production SQL.
I have a few databases and I want to check some things.
first, I want to check the index so I found this Query on this great website:
SELECT
t.name TableName,
col.name ColumnName,
ind.name IndexName
FROM
sys.indexes ind
INNER JOIN`enter code here`
sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id
INNER JOIN
sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id
INNER JOIN
sys.tables t ON ind.object_id = t.object_id
WHERE
(ind.is_primary_key = 0
AND t.is_ms_shipped = 0)
ORDER BY
t.name, col.name, ind.name
I don't know how to find t.name or col.name
I have found this Query that can find all the miss details
select * from information_schema.columns where column_name = 'ProductNumber'
But I dont know how to find the 'ProductNumber'
Last one, if I want to change the Snapshot Mode to ON it will ask to restart the server or it will have any impact on some running session or transaction and make any data corruption?
Use col.name like '%ProductNumber%' in where condition
SELECT
t.name TableName,
col.name ColumnName,
ind.name IndexName
FROM
sys.indexes ind
INNER JOIN`enter code here`
sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id
INNER JOIN
sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id
INNER JOIN
sys.tables t ON ind.object_id = t.object_id
WHERE
ind.is_primary_key = 0
AND t.is_ms_shipped = 0 and col.name like '%ProductNumber%'
ORDER BY
t.name, col.name, ind.name

How do I list the indexes of a table with its corresponding column?

Say I have table A. How do I lookup the indexes of column A.
Then what is the syntax for referring to that index in a SELECT statement query?
Thank you
A SELECT statement does not refer to an index (unless you explicitly give an optimization hint, which is unusual). That is, the index is hidden, just part of the database. It is used by the optimizer, when the optimizer calculates that the best query plan would use the index.
So, it is sort of "set-it-and-forget-it".
You can look up what indexes are available using the system tables/views. I would recommend starting with INFORMATION_SCHEMA.INDEXES.
You can find information in system tables sys.indexes, sys.index_columns and sys.columns.
If you want to find specific index on table A that uses column A you can use below query
select distinct i.name, STUFF((SELECT ', ' + col.name
FROM sys.indexes ind_col
INNER JOIN sys.index_columns ind_col_detail
ON ind_col.object_id = ind_col_detail.object_id
AND ind_col.index_id = ind_col_detail.index_id
INNER JOIN sys.columns col
ON i.object_id = col.object_id
AND ind_col_detail.column_id = col.column_id
WHERE i.object_id = ind_col.object_id
AND i.index_id = ind_col.index_id
AND ind_col_detail.is_included_column = 0
ORDER BY ind_col_detail.key_ordinal
FOR XML PATH('')), 1, 2, '') AS key_column_list ,
STUFF((SELECT ', ' + col.name
FROM sys.indexes ind_col
INNER JOIN sys.index_columns ind_col_detail
ON ind_col.object_id = ind_col_detail.object_id
AND ind_col.index_id = ind_col_detail.index_id
INNER JOIN sys.columns col
ON i.object_id = col.object_id
AND ind_col_detail.column_id = col.column_id
WHERE i.object_id = ind_col.object_id
AND i.index_id = ind_col.index_id
AND ind_col_detail.is_included_column = 1
ORDER BY ind_col_detail.key_ordinal
FOR XML PATH('')), 1, 2, '') AS included_column_list
from sys.indexes i
inner join sys.index_columns ic
on i.index_id = ic.index_id
and i.object_id = ic.object_id
and OBJECT_NAME(i.object_id) = 'Table A'
inner join sys.columns c
on c.column_id = ic.column_id
and c.object_id = i.object_id
and c.name = 'Column A'
The query returns an index even if the column A is included column. More details about included column is here
In general SQL server optimizer calculates the best plan for your query and decides if an index will be or not used while a query is executed.
But there is an option to force SQL server optimizer to use specific index using table hint INDEX.
Microsoft documentation about table hints is here
And an example how hint can be used by Pinal Dave is here

Retrieving Primary Key, Identity column, and specific name column from Database tables

I need to get primary key (if present), identity (if present), and column named 'ID' (if present) from every table in selected database. I got SQL query to do the work, but query returns records where Primary Key sometimes has both "No" and "Yes" values. Thus, resulting in multiple rows of data, so I used word DISTINCT to remove duplicates. I am assuming this is due to Indexes defined on some columns.
How would it be possible to fix this?
SQL query used:
SELECT DISTINCT
object_name(i.object_id) [Table],
c.name [Column],
IIF(i.is_primary_key = 1, 'Yes', 'No') [PK],
IIF(c.is_identity = 1, 'Yes', 'No') [Identity],
IIF(UPPER(c.name) = 'ID', 'Yes', 'No') [Named ID]
FROM sys.indexes i
INNER JOIN sys.columns c ON c.object_id = i.object_id
INNER JOIN sys.identity_columns idc ON idc.object_id = c.object_id AND idc.column_id = c.column_id
WHERE
i.is_primary_key = 1 OR c.is_identity = 1 OR c.name = 'ID'
ORDER BY [Table];
You can do the following query, however you could get results where multiple columns form the primary key like the following:
because of something like:
ALTER TABLE [derived].[LocationParameterMedium]
ADD CONSTRAINT [PK_LocationParameterMedium] PRIMARY KEY CLUSTERED ([CycleID] ASC, [LocationID] ASC, [ParameterID] ASC, [MediumID] ASC)
GO
Which can be fixed by rolling up the columns into a single column, the following link explains how to roll-up columns into a single column
Query:
SELECT
OBJECT_SCHEMA_NAME(t.object_id) AS [Schema], -- Incase there is mulple schemas and same table name
t.name AS [Table],
c.name AS [Column],
IIF((SELECT 1
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE keyCU
WHERE keyCU.COLUMN_NAME = c.name
AND keyCU.TABLE_SCHEMA = OBJECT_SCHEMA_NAME(t.object_id)
AND keyCU.TABLE_NAME = t.name
AND OBJECTPROPERTY(OBJECT_ID(keyCU.CONSTRAINT_SCHEMA + '.' + QUOTENAME(keyCU.CONSTRAINT_NAME)), 'IsPrimaryKey') = 1) = 1, 'Yes', 'No') [PK],
IIF(c.is_identity = 1, 'Yes', 'No') [Identity],
IIF(c.name = 'ID', 'Yes', 'No') [Named ID]
FROM sys.tables AS t
LEFT JOIN sys.columns AS c
ON t.object_id = c.object_id
AND (c.is_identity = 1
OR c.name = 'ID'
OR EXISTS ( SELECT 1
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE keyCU
WHERE keyCU.COLUMN_NAME = c.name
AND keyCU.TABLE_SCHEMA = OBJECT_SCHEMA_NAME(t.object_id)
AND keyCU.TABLE_NAME = t.name
AND OBJECTPROPERTY(OBJECT_ID(keyCU.CONSTRAINT_SCHEMA + '.' + QUOTENAME(keyCU.CONSTRAINT_NAME)), 'IsPrimaryKey') = 1
)
)
---- To exclude tables where there is no PK, identity, or column name = 'ID'
--WHERE c.name IS NOT NULL
You are using sys.indexes. A table can have multiple indexes and a column can be used multiple indexes. What your query is telling you is that the column is used in the PK index and also in another index (which is not the PK index).
Also your query is excluding all columns that are not in an index.
Start with sys.columns and use outer joins instead. Object id is the id of the table, not of the column, so you need index_columns aswell.
SELECT DISTINCT
object_name(c.object_id) [Table],
c.name [Column],
i.is_primary_key,
case i.is_primary_key when 1 then 'Yes' else 'No'end [PK],
case c.is_identity when 1 then 'Yes' else 'No'end [Identity],
case c.name when 'ID' then 'Yes' else 'No'end [Named ID]
FROM sys.columns c
left join sys.index_columns ic on c.column_id = ic.column_id and c.object_id = ic.object_id
left JOIN sys.indexes i ON i.index_id = ic.index_id and c.object_id = i.object_id and i.is_primary_key= 1
left JOIN sys.identity_columns idc ON idc.object_id = c.object_id AND idc.column_id = c.column_id
WHERE i.is_primary_key = 1 OR c.is_identity = 1 OR c.name = 'ID'
ORDER BY [Table];
For anyone needing something similar in the future, I adopted version of Peter's answer (including advice from Sean Lange to use sys.tables):
SELECT
t.name AS [Table],
c.name AS [Column],
CASE i.is_primary_key WHEN 1 THEN 'Yes' ELSE 'No' END [PK],
CASE idc.is_identity WHEN 1 THEN 'Yes' ELSE 'No' END [Identity],
CASE c.name WHEN 'ID' THEN 'Yes' ELSE 'No' END [Named ID]
FROM
sys.tables t
LEFT JOIN sys.columns c ON c.object_id = t.object_id
LEFT JOIN sys.identity_columns idc ON idc.object_id = t.object_id AND idc.column_id = c.column_id AND idc.is_identity = 1
LEFT JOIN sys.index_columns ic ON ic.object_id = t.object_id AND ic.column_id = c.column_id
LEFT JOIN sys.indexes i ON i.object_id = t.object_id AND i.index_id = ic.index_id AND i.is_primary_key = 1
WHERE t.type = 'U' AND (idc.is_identity = 1 OR i.is_primary_key = 1 OR c.name = 'ID')
ORDER BY t.name, c.name;

Get list of all columns with complete details (Identity, nullabel,primary key) in sql server without duplicate column

I have need to automate the process of database upgrade process.
So by getting the column structure of a table i need to create update/insert/create sql statement's .
BY problem was i am getting duplicate column name as constrains are also coming in the list which i don't need. So is there a way to restrict constraints in the result set.
I am using below query
SELECT c.NAME 'Column Name'
,t.NAME 'Data type'
,c.max_length 'Max Length'
,c.precision
,c.scale
,c.is_nullable AS 'Is Nullable'
,c.is_identity AS 'Is Identity'
,ISNULL(i.is_primary_key, 0) 'Primary Key'
,i.type_desc
FROM fblfeb12.sys.columns c
INNER JOIN fblfeb12.sys.types t ON c.system_type_id = t.system_type_id
LEFT OUTER JOIN fblfeb12.sys.index_columns ic ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
LEFT OUTER JOIN fblfeb12.sys.indexes i ON ic.object_id = i.object_id
AND ic.index_id = i.index_id
WHERE c.object_id = OBJECT_ID('table name')
Result set:
Pms_ID uniqueidentifier 16 0 0 0 0 CLUSTERED
Pms_PRODMODELID uniqueidentifie 16 0 0 1 0NONCLUSTERED
Pms_PRODMODELID uniqueidentifier 16 0 0 10NONCLUSTERED
Pms_PRODMODELID uniqueidentifier 16 0 0 10NONCLUSTERED
Pms_ATTRIBUTEID uniqueidentifier 16 0 0 10NONCLUSTERED
Pms_ATTRIBUTEID uniqueidentifier 16 0 0 0NONCLUSTERED
Pms_ATTRIBUTEID uniqueidentifier 16 0 0 1NONCLUSTERED
where PRODMODELID , ATTRIBUTEID comes 3 times.
I need only foreign key column but here I am getting index,Constraints which i don't need.
I need column name, data-type,identity,primary key, null able, foreign key.
Can you provide me any better solution,If i am doing anything wrong?
The problem is that you are including all indexes on the column. Consider this simple table:
CREATE TABLE #T (ID INT NOT NULL CONSTRAINT PK_T_ID PRIMARY KEY);
CREATE INDEX IX_T_ID ON #T (ID);
When you run an adaption of you query:
SELECT c.name, i.name, i.is_primary_key
FROM tempdb.sys.columns c
LEFT OUTER JOIN tempdb.sys.index_columns ic
ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
LEFT OUTER JOIN tempdb.sys.indexes i
ON ic.object_id = i.object_id
AND ic.index_id = i.index_id
WHERE c.object_id = OBJECT_ID('tempdb..#T');
The column name will be duplicated for each index that includes that column (either key or non key), so the result will be:
name name is_primary_key
ID PK_T_ID 1
ID IX_T_ID 0
Since you only care about the primary key, you can apply the a filter in the join to sys.indexes to only return the primary keys, to do this effectively though you need to make the join between index_columns and indexes an INNER JOIN, but maintain the OUTER JOIN from columns to index_columns which involves slightly rearranging the joins, so the above would become:
SELECT c.name, i.name, i.is_primary_key
FROM tempdb.sys.columns c
LEFT OUTER JOIN (tempdb.sys.index_columns ic
INNER JOIN tempdb.sys.indexes i
ON ic.object_id = i.object_id
AND ic.index_id = i.index_id
AND i.is_primary_key = 1) -- ONLY PRIMARY KEYS
ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
WHERE c.object_id = OBJECT_ID('tempdb..#T');
This removes the duplicate result. Finally you can query sys.foreign_key_columns to find out if the column references another table giving a final query of:
SELECT c.NAME AS [Column Name]
,t.NAME AS [Data type]
,c.max_length AS [Max Length]
,c.precision
,c.scale
,c.is_nullable AS [Is Nullable]
,c.is_identity AS [Is Identity]
,ISNULL(i.is_primary_key, 0) [Primary Key]
,i.type_desc
,OBJECT_SCHEMA_NAME(fk.object_id) + '.' + OBJECT_NAME(fk.object_id) + ' (' + fk.Name + ')' AS [Foreign Key]
FROM sys.columns c
INNER JOIN sys.types t
ON c.system_type_id = t.system_type_id
LEFT OUTER JOIN (sys.index_columns ic
INNER JOIN sys.indexes i
ON ic.object_id = i.object_id
AND i.is_primary_key = 1
AND ic.index_id = i.index_id)
ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
LEFT JOIN sys.foreign_key_columns fkc
ON fkc.parent_object_id = c.object_id
AND fkc.parent_column_id = c.column_id
LEFT JOIN sys.columns fk
ON fk.object_id = fkc.referenced_object_id
AND fk.column_id = fkc.referenced_column_id
WHERE c.object_id = OBJECT_ID('table')
ORDER BY c.Column_ID;
N.B I have changed your column aliases from single quotes to brackets as using single quotes is deprecated (not to mention easily confused with string literals)
What happens if you use the "DISTINCT"? so
SELECT distinct c.NAME...
"I need only foreign key column but here I am getting index,Constraints which i don't need."
If you need to get foreign key columns could you not use this SO post . And remove the joins to sys.index_column and sys.indexes?

Individual index size for SQL Server

I can use sp_spaceused tablename to get the total index size for that table.
But is there a way to get all indexes of that table's size individually?
table-and-index-size-in-sql-server
Following script is copied from the above answer from Rob Garisson
SELECT
i.name AS IndexName,
s.used_page_count * 8 AS IndexSizeKB
FROM sys.dm_db_partition_stats AS s
JOIN sys.indexes AS i
ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id
WHERE s.[object_id] = object_id('dbo.TableName')
ORDER BY i.name
SELECT
i.name AS IndexName,
SUM(page_count * 8) AS IndexSizeKB
FROM sys.dm_db_index_physical_stats(
db_id(), object_id('dbo.TableName'), NULL, NULL, 'DETAILED') AS s
JOIN sys.indexes AS i
ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id
GROUP BY i.name
ORDER BY i.name