Check which column is not nullable - sql-server

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.

Related

Drop index in 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];

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 info (especial pk) of all column in a table

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'

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