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".
Related
I would like to drop a constraint on column in more than one database. I do not know exact name of the constraint on a column.
Is it possible to Drop a constraint without knowing its name.
Ex:
ALTER TABLE TempTable DROP CONSTRAINT IF EXISTS ON Columnname
you can retrieve constraint information from a table like this
select t.Name as TableName,
ccd.Name as ColumnName_default_constraint,
dc.Name as default_constraint,
ccc.Name as ColumnName_check_constraint,
cc.Name as check_constraint
from sys.tables t
inner join sys.default_constraints dc on t.object_id = dc.parent_object_id
inner join sys.check_constraints cc on t.object_id = cc.parent_object_id
inner join sys.columns ccd on dc.parent_object_id = ccd.object_id
and ccd.column_id = dc.parent_column_id
inner join sys.columns ccc on cc.parent_object_id = ccc.object_id
and ccc.column_id = cc.parent_column_id
where t.Name = 'your table name'
order by t.Name
from this you can build scripts like this
select 'alter table ' + t.Name +' drop constraint ' + dc.Name,
'alter table ' + t.Name +' drop constraint ' + cc.Name
from sys.tables t
inner join sys.default_constraints dc on t.object_id = dc.parent_object_id
inner join sys.check_constraints cc on t.object_id = cc.parent_object_id
where t.Name = 'your table name'
order by t.Name
I would like to know if there is a script you can run to see which columns are not nullable that is not an identity column on the whole database?
I googled for results but the only results I found was answers to check which data is null.
You can do that as
USE YourDatabase
GO
SELECT T.name TableName,
C.name ColumnName
FROM Sys.Tables T INNER JOIN Sys.Columns C ON T.object_id = C.object_id
WHERE C.is_nullable = 0
AND
C.is_identity = 0;
Or this one
SELECT T.Name TableName,
STUFF(
(
SELECT ',' + C.Name
FROM Sys.Columns C
WHERE C.object_id = T.object_id
AND
C.is_nullable = 0
AND
C.is_identity = 0
FOR XML PATH('')
), 1, 1, ''
) HasThosNonNullableColumns
FROM Sys.Tables T;
Demo
So I thought of looking into sysobjects and sys.columns views, and I joined the tables accordingly:
select
o.name [Table]
,c.name [Column]
from
sys.columns c
inner join
sysobjects o on
c.object_id = o.id
where
c.is_nullable = 0
and c.is_identity = 0
order by
o.name
,c.name
This helped a lot.
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];
I try to get info of all column in a table
Example info about type, name column, especially info about primary key but it missing
I use
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='tablename'
It's not contain info about primary key. How to get that thanks
How about something like
SELECT *
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = 'TableName'
Also maybe try
SELECT i.name AS IndexName,
OBJECT_NAME(ic.OBJECT_ID) AS TableName,
COL_NAME(ic.OBJECT_ID,ic.column_id) AS ColumnName,
c.*
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 INNER JOIN
sys.columns c ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
WHERE i.is_primary_key = 1
try with sp_help [tablename] it will give you primary key details
sp_help [tablename]
sp_help
Or if you need only details about primary key column try with Mr.Astander answer
SELECT *
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = 'TableName'
You could retrieve primary key information and join it to INFORMATION_SCHEMA.COLUMNS and get primary key information with other columns. Please see the below query.
SELECT c.*,
CASE WHEN keys.COLUMN_NAME IS NULL
THEN 0
ELSE 1
END AS is_primary
FROM
INFORMATION_SCHEMA.COLUMNS c
LEFT OUTER JOIN (
SELECT col.COLUMN_NAME,col.TABLE_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tab
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
ON Col.Constraint_Name = tab.Constraint_Name
AND Col.Table_Name = tab.Table_Name
WHERE Constraint_Type = 'PRIMARY KEY') keys
ON c.COLUMN_NAME=keys.COLUMN_NAME AND c.TABLE_NAME=keys.TABLE_NAME
ORDER BY c.TABLE_NAME
Try:
SELECT TC.TABLE_NAME, CU.CONSTRAINT_NAME, C.DATA_TYPE
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU
ON TC.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.COLUMNS C
ON CU.TABLE_NAME = C.TABLE_NAME AND CU.TABLE_SCHEMA = C.TABLE_SCHEMA AND C.COLUMN_NAME = CU.COLUMN_NAME
WHERE TC.TABLE_NAME = 'tablename' AND CONSTRAINT_TYPE = 'PRIMARY KEY'
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;