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

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;

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

SQL Server query to get the list of columns in a table along with Data types, length, unique, not null, primary key, foreign key and it's reference

I need a query to to get the list of columns in a table along with Data types, length, not null, unique, primary key, foreign key and it's reference.
I use the below answer with MySQL, but I need it in SQL Server.
Showing MYSQL table columns with key types and reference
I believe you need something like this. If you want to see only tables with foreign keys you need to change LEFT JOIN to INNER JOIN.
SELECT t.object_id
, t.name TableName
, C.name ColumnName
, C.column_id ColumnSeq
, S.name DataType
, tf.name ParentTableName
, CF.name ParentColumnName
FROM sys.tables T
INNER JOIN sys.columns C ON T.object_id = C.object_id
INNER JOIN sys.types S ON C.system_type_id = S.system_type_id
LEFT JOIN sys.foreign_key_columns FSK ON FSK.parent_object_id = t.object_id AND FSK.parent_column_id = C.column_id
LEFT JOIN SYS.columns CF ON FSK.referenced_object_id = CF.object_id AND FSK.referenced_column_id = CF.column_id
LEFT JOIN SYS.tables TF ON cf.object_id = TF.object_id
I think you are looking for
SELECT C.name ColumnName,
OBJECT_NAME(C.object_id) TableName,
OBJECT_NAME(FKC.referenced_object_id) ReferencedTable,
COL_NAME(FKC.referenced_object_id, FKC.parent_column_id) ReferencedColumn,
T.name DataType,
C.max_length,
C.precision,
C.collation_name,
C.is_nullable
--...
FROM Sys.Columns C LEFT JOIN sys.foreign_key_columns FKC
ON C.object_id = FKC.parent_object_id
JOIN Sys.Types T
ON C.system_type_id = T.system_type_id
WHERE C.object_id = OBJECT_ID('YourTableNameHere');

SqlServer - Get all tables that has data ( are not empty )

The question is simple:
Is it possible to retrive all the tables that are not empty ?
I need a query to list the tables. Is there a way ?
Thanks to support
Try this Script To get all tables with non empty records
USE [Your database Name]
Go
SELECT SCHEMA_NAME(schema_id) AS [SchemaName],
[Tables].name AS [TableName]
--SUM([Partitions].[rows]) AS [TotalRowCount]
FROM sys.tables AS [Tables]
JOIN sys.partitions AS [Partitions]
ON [Tables].[object_id] = [Partitions].[object_id]
AND [Partitions].index_id IN ( 0, 1 )
-- WHERE [Tables].name = N'name of the table'
GROUP BY SCHEMA_NAME(schema_id), [Tables].name
HAVING SUM([Partitions].[rows]) >0
Slightly different than #Sreenu131 answer as it is using sys.partitions .rows property to find
p.rows > 0
SELECT
sch.name as SchemaName,
t.NAME AS TableName,
p.rows AS RowCounts
FROM
sys.tables t
INNER JOIN
sys.partitions p ON t.object_id = p.OBJECT_ID
INNER JOIN sys.schemas sch
on t.schema_id = sch.schema_id
WHERE
t.NAME NOT LIKE 'dt%'
AND t.is_ms_shipped = 0
AND p.rows > 0
GROUP BY
sch.name,t.Name, p.Rows
ORDER BY
sch.name,t.Name

Getting duplication with inner join and left join

I am trying to fetch following information for the table of the columns :
1) Primary key.
2) IsNullable
3) Is_Identity.
Query :
SELECT c.name 'Column Name',c.is_nullable,c.is_identity,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 WHERE c.object_id = OBJECT_ID('[HumanResources].[Employee]')
I am working with Adventure Works database but the problem here is I am getting OrganizationNode column 2 times and I am unable to understand the reason.
For other tables I am not getting this issue but I am only getting this problem for the table [HumanResources].[Employee].
Below is the link to download database bak file :
https://www.dropbox.com/s/nutfat17b73boav/AdvantureWorksSeScript.bak?dl=0
I have also tried distinct but because of that it shuffled up the ordering of the column as you can see in the second output. BirthDate is coming at the top instead of BusinessEntityID.
I would not like to use distinct as my below query is working fine with all other tables but I am not getting why it is giving duplicate columns in case of [HumanResources].[Employee] table or may be I have tested it with few tables and query may not work properly for few other databases.
I am not sure whether my query is correct or not to work in all the scenarios to fetch above 3 things(pk,inullable etc.) which I mention.
Try this
SELECT name,
is_identity,
is_nullable,
is_primary_key
FROM (
SELECT c.name,
c.column_id,
c.is_identity,
c.is_nullable,
ISNULL(i.is_primary_key,0) is_primary_key,
ROW_NUMBER() OVER(PARTITION BY c.name ORDER BY c.name) rn
FROM sys.columns c
JOIN sys.tables t
ON t.object_id = c.object_id
LEFT JOIN sys.index_columns ic
ON c.object_id = ic.object_id AND c.column_id = ic.column_id
LEFT JOIN sys.indexes i
ON i.object_id = ic.object_id AND i.index_id = ic.index_id
WHERE t.name = 'Employee'
)keys
WHERE rn = 1
ORDER BY column_id

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?