How can I drop all the default constraints constraints on a table - sql-server

How can I drop all the default constraints belonging to a particular table in SQL 2005?

One solution from a search: (Edited for Default constraints)
SET NOCOUNT ON
DECLARE #constraintname SYSNAME, #objectid int,
#sqlcmd VARCHAR(1024)
DECLARE CONSTRAINTSCURSOR CURSOR FOR
SELECT NAME, object_id
FROM SYS.OBJECTS
WHERE TYPE = 'D' AND #objectid = OBJECT_ID('Mytable')
OPEN CONSTRAINTSCURSOR
FETCH NEXT FROM CONSTRAINTSCURSOR
INTO #constraintname, #objectid
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT #sqlcmd = 'ALTER TABLE ' + OBJECT_NAME(#objectid) + ' DROP CONSTRAINT ' + #constraintname
EXEC( #sqlcmd)
FETCH NEXT FROM CONSTRAINTSCURSOR
INTO #constraintname, #objectid
END
CLOSE CONSTRAINTSCURSOR
DEALLOCATE CONSTRAINTSCURSOR

I know this is old, but I just found it when googling.
A solution that works for me in SQL 2008 (not sure about 2005) without resorting to cursors is below :
declare #sql nvarchar(max)
set #sql = ''
select #sql = #sql + 'alter table YourTable drop constraint ' + name + ';'
from sys.default_constraints
where parent_object_id = object_id('YourTable')
AND type = 'D'
exec sp_executesql #sql

Script posted by gbn does not work for me, so I'm using a modified version:
SET NOCOUNT ON
DECLARE #DfId INT, #TableId INT,
#SqlCmd VARCHAR(1024)
DECLARE DFCONSTRAINTCUR CURSOR FOR
SELECT [parent_object_id] TABLE_ID, [object_id] DF_ID
FROM SYS.OBJECTS
where parent_object_id = OBJECT_ID('<table name>')
and [TYPE] = 'D'
OPEN DFCONSTRAINTCUR
FETCH NEXT FROM DFCONSTRAINTCUR
INTO #TableId, #DfId
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT #sqlcmd = 'ALTER TABLE ' + OBJECT_NAME(#TableId) + ' DROP CONSTRAINT ' + OBJECT_NAME(#DfId)
EXEC(#sqlcmd)
FETCH NEXT FROM DFCONSTRAINTCUR
INTO #TableId, #DfId
END
CLOSE DFCONSTRAINTCUR
DEALLOCATE DFCONSTRAINTCUR

Just why do you want to do this? Dropping constraints is a pretty drastic action and affects all users not just your process. Maybe your problem can be solved some other way. If you aren't the dba of the system, you should think very hard about whether you should do this. (Of course in most systems, a dba wouldn't allow anyone else the permissions to do such a thing.)

Related

How to find the name of the database from the given table name, using stored procedure?

I am newbie here. I have many databases in my SSMS, so I need to find the database name using the given table name using stored procedures.
And I am not good at writing SP's and handling errors.
I apologize for my English.
Thank you
I tried it using cursors in stored procedure.
But I am getting errors as I am not good at handling errors.
You could create the stored procedure in the following:
CREATE PROCEDURE sp_Get_Tables
#schema VARCHAR(50) = 'dbo',
#table_name VARCHAR(100) = 'Default_Table_Name'
AS
SELECT name
FROM sys.databases
WHERE CASE WHEN state_desc = 'ONLINE' THEN OBJECT_ID(QUOTENAME(name) + '.' + #schema + '.' + #table_name, 'U') END IS NOT NULL
And execute the stored procedure you can in the following:
EXEC sp_Get_Names 'Schema', 'Table_Name'
Try This:
Create PROCEDURE Pro_FindTable
(#tableName VARCHAR(MAX))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #name VARCHAR(MAX),
#dbid INT;
DECLARE C CURSOR FAST_FORWARD FOR(
SELECT name,
database_id
FROM sys.databases);
OPEN C;
FETCH NEXT FROM C
INTO #name,
#dbid;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #query NVARCHAR(MAX)
= 'IF EXISTS(SELECT name FROM(SELECT name, COUNT(*)Over(Order By (Select Null)) as RN FROM(SELECT '''
+ #name + ''' AS name UNION ALL SELECT name FROM [' + #name
+ '].sys.tables WHERE type=''U'' AND name = ''' + #tableName
+ ''') as K)as K Where RN>1)
Select '''+ #name + '''';
EXEC (#query);
FETCH NEXT FROM C
INTO #name,
#dbid;
END;
CLOSE C;
DEALLOCATE C;
END;
And call it like this:
EXEC Pro_FindTable 'MyTable'
Result will be all databases which has a table named 'MyTable'

Trying to write some T-SQL to iterate through the DB tables

I am using SQL Server 2008 R2 on dev, and SQL Azure for test and live.
I wish to write a little procedure to reset the identity seeds since SQL Azure does not support DBCC.
I have some workaround code which works, but I do not want to write it out for each table, so was trying to write a routine that iterates through the DB tables.
Tables:
SELECT * FROM information_schema.tables
Code:
delete from TABLE_NAME where Id>150000
GO
SET IDENTITY_INSERT [TABLE_NAME] ON
GO
INSERT INTO [TABLE_NAME](Id) VALUES(150000)
GO
delete from TABLE_NAME where Id=150000
GO
SET IDENTITY_INSERT [TABLE_NAME] OFF
GO
I guess I need to wrap this in a loop. Sorry my T-SQL is not that strong, hence the request for help.
Also it would be helpful to omit all tables with TABLE_NAME starting with aspnet_ and use only TABLE_TYPE = "BASE TABLE"
Any help hugely appreciated.
Unless somebody else knows a trick that I don't, you're probably stuck using dynamic SQL and iterating through a list of table names using either a cursor or a temporary table. The cursor approach would look something like this:
declare #TableName nvarchar(257);
declare #sql nvarchar(max);
declare TableCursor cursor read_only for
select
TABLE_SCHEMA + '.' + TABLE_NAME
from
INFORMATION_SCHEMA.TABLES
where
TABLE_NAME not like 'aspnet\_%' escape '\' and
TABLE_TYPE = 'BASE TABLE';
open TableCursor;
fetch next from TableCursor into #TableName;
while ##fetch_status = 0
begin
set #sql = 'select top 1 * from ' + #TableName;
exec sp_executesql #sql;
fetch next from TableCursor into #TableName;
end
close TableCursor;
deallocate TableCursor;
You can read more about cursors here. Alternatively, you could do it with an in-memory table like this:
declare #Tables table (RowId int identity(1, 1), TableName nvarchar(257));
declare #TableName nvarchar(257);
declare #Index int;
declare #TableCount int;
declare #sql nvarchar(max);
insert into #Tables (TableName)
select
TABLE_SCHEMA + '.' + TABLE_NAME
from
INFORMATION_SCHEMA.TABLES
where
TABLE_NAME not like 'aspnet\_%' escape '\' and
TABLE_TYPE = 'BASE TABLE';
set #TableCount = ##rowcount;
set #Index = 1
while #Index <= #TableCount
begin
select #TableName = TableName from #Tables where RowId = #Index;
set #sql = 'select top 1 * from ' + #TableName;
exec sp_executesql #sql;
set #Index = #Index + 1;
end
In the interest of brevity, my examples use a much simpler SQL statement than yours—I'm just selecting one record from each table—but this ought to be enough to illustrate how you can get this done.

Run operations on all the tables in all the databases

I'm trying to create a SQL Server script that applies some operations to all the tables in all the databases. I need to rename some tables if some conditions are respected, truncate the tables otherwise.
This is my script
EXEC sp_MSforeachdb
#command1 = '
IF not exists(select 1 where ''?'' in (''master'',''model'',''msdb'',''tempdb''))
EXEC [?].dbo.sp_MSforeachtable
#command1 = ''
IF(substring(&, 1, 3)=pv_ and right(&, 5) != _data and right(&, 4) != _BCK)
exec sp_RENAME & , &_BCK''
ELSE IF (right(&, 4) != _BCK)
TRUNCATE TABLE &
#replacechar = ''&'''
I got some errors but I'm new to SQL Server and I have not idea how to fix this script.
Any suggestions?
Many thanks
Here is a solution for start. It won't be quick, but it loops all tables of all databases on the server. Inside in the second cursor you can deceide what to do with the table.
(The query is not optimalized, just a quick solution)
DECLARE #DBName NVARCHAR(50)
DECLARE #TableName NVARCHAR(100)
DECLARE #DynamicSQL NVARCHAR(300)
DECLARE #DBCursor CURSOR
SET #DBCursor = CURSOR FOR
SELECT NAME FROM SYS.DATABASES
WHERE NAME NOT IN ('master','tempdb','model','msdb')
OPEN #DBCursor
FETCH NEXT FROM #DBCursor INTO #DBName
WHILE ##FETCH_STATUS = 0
BEGIN
CREATE TABLE #TempTableDatas
(
name varchar(100),
objectID int
)
SET #DynamicSQL = 'INSERT INTO #TempTableDatas
SELECT name, object_id FROM [' + #DBName + ']' + '.sys.Tables '
EXEC SP_EXECUTESQL #DynamicSQL
DECLARE #TableCursor CURSOR
SET #TableCursor = CURSOR FOR
SELECT name FROM #TempTableDatas
OPEN #TableCursor
FETCH NEXT FROM #TableCursor INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #TableName, #DBName
FETCH NEXT FROM #TableCursor INTO #TableName
END
CLOSE #TableCursor
DEALLOCATE #TableCursor
DROP TABLE #TempTableDatas
FETCH NEXT FROM #DBCursor INTO #DBName
END
CLOSE #DBCursor
DEALLOCATE #DBCursor

Alter "Default" in SQL Server

I have custom default value in a SQL server 2008 table.
Similar to this
CREATE DEFAULT [dbo].[Default_Timestamp]
AS
GetDate()
Now I want to change the value in that default.
CREATE DEFAULT [dbo].[Default_Timestamp]
AS
GETUTCDATE()
Before I can edit the existing one, I need to drop the first one and recreate it.
DROP DEFAULT [dbo].[Default_Timestamp]
it gives following error.
Msg 3716, Level 16, State 3, Line 4
The default 'dbo.Default_Timestamp' cannot be dropped because it is bound to one or more column.
Since the default is already use by few tables I cannot drop and recreate a new one.
I know I need to unbind all the tables from this default before I can recreate it.
Can anyone provide a script to list all the table and columns which are bound with that default?
It's a multi-step process:
1) Find the object_id for your default :
DECLARE #DefaultObjectID INT
SELECT #DefaultObjectID = OBJECT_ID('Default_Timestamp')
2) Find all the columns that reference that default:
SELECT
ColumnName = c.Name,
TableName = t.Name,
UnbindCmd = 'EXEC sp_unbindefault ''' + t.Name + '.' + c.name + ''''
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE default_object_id = #DefaultObjectID
This will produce a list of UnbindCmd commands to actually remove the DEFAULT from those columns.
3) Now, copy that column from your SQL Server Mgmt Studio window, and execute it in a new query window to actually "unbind" the default from all those columns
4) Now define your new default
However: these days, I would probably not define a new DEFAULT per se - can't you just set the default constraint on the columns in question directly?
ALTER TABLE dbo.YourTable
ADD CONSTRAINT DF_YourTable_TimeStamp
DEFAULT GETUTCDATE() FOR YourColumnName
Seems a like easier to work with going into the future! When you explicitly name your constraint, you can also easily find and drop that constraint again, if need be.
I ran across this issue when I found some old style defaults in my database where I had to update uses_ansi_nulls and uses_quoted_identifier en mass in my database.
Here is the code that I ended up writing to replace the old style defaults (CREATE DEFAULT sp_BindDefault) with the newer style (ALTER TABLE).
DECLARE #strSQL varchar(max)
, #DBName varchar(50) = DB_NAME();
DROP TABLE IF EXISTS #tmp;
SELECT IDENTITY(int, 1,1) AS ID,
UnbindCmd = 'EXEC sp_unbindefault ''' + t.Name + '.' + c.name + ''';',
DropCmd = 'DROP DEFAULT IF EXISTS [' + SCHEMA_NAME(SO.schema_id) + '].[' + OBJECT_NAME(SO.object_id) + '];',
CreateCmd = 'ALTER TABLE [' + SCHEMA_NAME(t.Schema_id) + '].[' + t.Name + ']'
+ ' ADD CONSTRAINT df_' + REPLACE(t.Name, ' ', '') + '_' + REPLACE(c.Name, ' ', '')
+ ' DEFAULT (' + RIGHT(m.definition, LEN(m.definition) - CHARINDEX(' AS ', m.definition) - 3)
+ ') FOR ' + QUOTENAME(c.Name) + ';'
INTO #tmp
FROM sys.sql_modules m
join sys.columns c on c.default_object_id = m.object_id
INNER JOIN sys.tables t ON c.object_id = t.object_id
JOIN sys.objects SO ON SO.object_id = C.default_object_id
WHERE (m.uses_ansi_nulls = 0
OR m.uses_quoted_identifier = 0)
ORDER BY
t.name
, c.name;
BEGIN TRANSACTION
BEGIN TRY
DECLARE UnbindCursor CURSOR LOCAL FAST_FORWARD
FOR SELECT UnbindCmd
FROM #tmp
ORDER BY
ID;
OPEN UnbindCursor;
FETCH NEXT FROM UnbindCursor INTO #strSQL;
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC (#strSQL);
FETCH NEXT FROM UnbindCursor INTO #strSQL;
END
CLOSE UnbindCursor;
DEALLOCATE UnbindCursor;
DECLARE DropCursor CURSOR LOCAL FAST_FORWARD
FOR SELECT DropCmd
FROM #tmp
GROUP BY
DropCmd
ORDER BY
MIN(id)
OPEN DropCursor;
FETCH NEXT FROM DropCursor INTO #strSQL;
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC (#strSQL);
FETCH NEXT FROM DropCursor INTO #strSQL;
END
CLOSE DropCursor;
DEALLOCATE DropCursor;
DECLARE CreateCursor CURSOR LOCAL FAST_FORWARD
FOR SELECT CreateCmd
FROM #tmp
ORDER BY
id
OPEN CreateCursor;
FETCH NEXT FROM CreateCursor INTO #strSQL;
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC (#strSQL);
FETCH NEXT FROM CreateCursor INTO #strSQL;
END
CLOSE CreateCursor;
DEALLOCATE CreateCursor;
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE #ErrorMessage nvarchar(4000)
, #ErrorSeverity int
, #ErrorState int;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
RAISERROR (#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
);
END CATCH
I never saw CREATE DEFAULT or DROP DEFAULT as standalone commands, but only know the CONSTRAINT clause to add or drop a default constraint.
SSMS 2008 generates the following code (right click in table designer, "Generate Change Script..."):
ALTER TABLE dbo.T ADD CONSTRAINT
DF_T_DateTimeColumn DEFAULT getdate() FOR DateTimeColumn
GO
ALTER TABLE dbo.T
DROP CONSTRAINT DF_T_DateTimeColumn
GO
ALTER TABLE dbo.T ADD CONSTRAINT
DF_T_DateTimeColumn DEFAULT getutcdate() FOR DateTimeColumn
GO
update:
I admit it, I never used EXEC sp_bindefault, but I think its use is discouraged, as MSDN says:
This feature will be removed in a future version of Microsoft SQL
Server. Do not use this feature in new development work, and modify
applications that currently use this feature as soon as possible. We
recommend that you create default definitions by using the DEFAULT
keyword of the ALTER TABLE or CREATE TABLE statements instead.
This also applies to sp_unbindefault, of course.
You can find the columns that use a default object by looking at the default_object_id in sys.columns:
ID of the default object, regardless of whether it is a stand-alone
object sys.sp_bindefault, or an inline, column-level DEFAULT
constraint.
Knowing this is trivial to build a script that unbinds all columns from a default object and replaces the default with a constraint based default value:
use master;
go
if db_id('test') is not null
drop database test;
go
create database test;
go
use test;
go
create default foo as 1;
go
create table t1 (a int);
create table t2 (b int);
go
exec sp_bindefault 'foo', 't1.a';
exec sp_bindefault 'foo', 't2.b';
go
drop default foo;
-- Msg 3716, Level 16, State 3, Line 2
-- The default 'foo' cannot be dropped because it is bound to one or more column.
go
declare crs cursor static forward_only read_only for
select object_schema_name(object_id) as schema_name,
object_name(object_id) as object_name,
name as column_name
from sys.columns where default_object_id = object_id('foo');
open crs;
declare #schema_name sysname, #object_name sysname, #column_name sysname, #sql nvarchar(max);
fetch next from crs into #schema_name, #object_name, #column_name;
while ##fetch_status = 0
begin
set #sql = N'exec sp_unbindefault ' + quotename(
quotename(#schema_name) + N'.'+
quotename(#object_name) + N'.'+
quotename(#column_name), '''');
print #sql;
exec sp_executesql #sql;
set #sql = N'alter table ' +
quotename(#schema_name) + N'.' +
quotename(#object_name) + N' add constraint ' +
quotename(N'default_' + #column_name) + N' default 2 for ' +
quotename(#column_name);
print #sql;
exec sp_executesql #sql;
fetch next from crs into #schema_name, #object_name, #column_name;
end
close crs;
deallocate crs;
go
drop default foo;
-- it now succeeds
go

Select columns with NULL values only

How do I select all the columns in a table that only contain NULL values for all the rows? I'm using MS SQL Server 2005. I'm trying to find out which columns are not used in the table so I can delete them.
Here is the sql 2005 or later version: Replace ADDR_Address with your tablename.
declare #col varchar(255), #cmd varchar(max)
DECLARE getinfo cursor for
SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
WHERE t.Name = 'ADDR_Address'
OPEN getinfo
FETCH NEXT FROM getinfo into #col
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #cmd = 'IF NOT EXISTS (SELECT top 1 * FROM ADDR_Address WHERE [' + #col + '] IS NOT NULL) BEGIN print ''' + #col + ''' end'
EXEC(#cmd)
FETCH NEXT FROM getinfo into #col
END
CLOSE getinfo
DEALLOCATE getinfo
SELECT cols
FROM table
WHERE cols IS NULL
This should give you a list of all columns in the table "Person" that has only NULL-values. You will get the results as multiple result-sets, which are either empty or contains the name of a single column. You need to replace "Person" in two places to use it with another table.
DECLARE crs CURSOR LOCAL FAST_FORWARD FOR SELECT name FROM syscolumns WHERE id=OBJECT_ID('Person')
OPEN crs
DECLARE #name sysname
FETCH NEXT FROM crs INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC('SELECT ''' + #name + ''' WHERE NOT EXISTS (SELECT * FROM Person WHERE ' + #name + ' IS NOT NULL)')
FETCH NEXT FROM crs INTO #name
END
CLOSE crs
DEALLOCATE crs
Or did you want to just see if a column only has NULL values (and, thus, is probably unused)?
Further clarification of the question might help.
EDIT:
Ok.. here's some really rough code to get you going...
SET NOCOUNT ON
DECLARE #TableName Varchar(100)
SET #TableName='YourTableName'
CREATE TABLE #NullColumns (ColumnName Varchar(100), OnlyNulls BIT)
INSERT INTO #NullColumns (ColumnName, OnlyNulls) SELECT c.name, 0 FROM syscolumns c INNER JOIN sysobjects o ON c.id = o.id AND o.name = #TableName AND o.xtype = 'U'
DECLARE #DynamicSQL AS Nvarchar(2000)
DECLARE #ColumnName Varchar(100)
DECLARE #RC INT
SELECT TOP 1 #ColumnName = ColumnName FROM #NullColumns WHERE OnlyNulls=0
WHILE ##ROWCOUNT > 0
BEGIN
SET #RC=0
SET #DynamicSQL = 'SELECT TOP 1 1 As HasNonNulls FROM ' + #TableName + ' (nolock) WHERE ''' + #ColumnName + ''' IS NOT NULL'
EXEC sp_executesql #DynamicSQL
set #RC=##rowcount
IF #RC=1
BEGIN
SET #DynamicSQL = 'UPDATE #NullColumns SET OnlyNulls=1 WHERE ColumnName=''' + #ColumnName + ''''
EXEC sp_executesql #DynamicSQL
END
ELSE
BEGIN
SET #DynamicSQL = 'DELETE FROM #NullColumns WHERE ColumnName=''' + #ColumnName+ ''''
EXEC sp_executesql #DynamicSQL
END
SELECT TOP 1 #ColumnName = ColumnName FROM #NullColumns WHERE OnlyNulls=0
END
SELECT * FROM #NullColumns
DROP TABLE #NullColumns
SET NOCOUNT OFF
Yes, there are easier ways, but I have a meeting to go to right now. Good luck!
Here is an updated version of Bryan's query for 2008 and later. It uses INFORMATION_SCHEMA.COLUMNS, adds variables for the table schema and table name. The column data type was added to the output. Including the column data type helps when looking for a column of a particular data type. I didn't added the column widths or anything.
For output the RAISERROR ... WITH NOWAIT is used so text will display immediately instead of all at once (for the most part) at the end like PRINT does.
SET NOCOUNT ON;
DECLARE
#ColumnName sysname
,#DataType nvarchar(128)
,#cmd nvarchar(max)
,#TableSchema nvarchar(128) = 'dbo'
,#TableName sysname = 'TableName';
DECLARE getinfo CURSOR FOR
SELECT
c.COLUMN_NAME
,c.DATA_TYPE
FROM
INFORMATION_SCHEMA.COLUMNS AS c
WHERE
c.TABLE_SCHEMA = #TableSchema
AND c.TABLE_NAME = #TableName;
OPEN getinfo;
FETCH NEXT FROM getinfo INTO #ColumnName, #DataType;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = N'IF NOT EXISTS (SELECT * FROM ' + #TableSchema + N'.' + #TableName + N' WHERE [' + #ColumnName + N'] IS NOT NULL) RAISERROR(''' + #ColumnName + N' (' + #DataType + N')'', 0, 0) WITH NOWAIT;';
EXECUTE (#cmd);
FETCH NEXT FROM getinfo INTO #ColumnName, #DataType;
END;
CLOSE getinfo;
DEALLOCATE getinfo;
You can do:
select
count(<columnName>)
from
<tableName>
If the count returns 0 that means that all rows in that column all NULL (or there is no rows at all in the table)
can be changed to
select
case(count(<columnName>)) when 0 then 'Nulls Only' else 'Some Values' end
from
<tableName>
If you want to automate it you can use system tables to iterate the column names in the table you are interested in
If you need to list all rows where all the column values are NULL, then i'd use the COLLATE function. This takes a list of values and returns the first non-null value. If you add all the column names to the list, then use IS NULL, you should get all the rows containing only nulls.
SELECT * FROM MyTable WHERE COLLATE(Col1, Col2, Col3, Col4......) IS NULL
You shouldn't really have any tables with ALL the columns null, as this means you don't have a primary key (not allowed to be null). Not having a primary key is something to be avoided; this breaks the first normal form.
Try this -
DECLARE #table VARCHAR(100) = 'dbo.table'
DECLARE #sql NVARCHAR(MAX) = ''
SELECT #sql = #sql + 'IF NOT EXISTS(SELECT 1 FROM ' + #table + ' WHERE ' + c.name + ' IS NOT NULL) PRINT ''' + c.name + ''''
FROM sys.objects o
JOIN sys.columns c ON o.[object_id] = c.[object_id]
WHERE o.[type] = 'U'
AND o.[object_id] = OBJECT_ID(#table)
AND c.is_nullable = 1
EXEC(#sql)
Not actually sure about 2005, but 2008 ate it:
USE [DATABASE_NAME] -- !
GO
DECLARE #SQL NVARCHAR(MAX)
DECLARE #TableName VARCHAR(255)
SET #TableName = 'TABLE_NAME' -- !
SELECT #SQL =
(
SELECT
CHAR(10)
+'DELETE FROM ['+t1.TABLE_CATALOG+'].['+t1.TABLE_SCHEMA+'].['+t1.TABLE_NAME+'] WHERE '
+(
SELECT
CASE t2.ORDINAL_POSITION
WHEN (SELECT MIN(t3.ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS t3 WHERE t3.TABLE_NAME=t2.TABLE_NAME) THEN ''
ELSE 'AND '
END
+'['+COLUMN_NAME+'] IS NULL' AS 'data()'
FROM INFORMATION_SCHEMA.COLUMNS t2 WHERE t2.TABLE_NAME=t1.TABLE_NAME FOR XML PATH('')
) AS 'data()'
FROM INFORMATION_SCHEMA.TABLES t1 WHERE t1.TABLE_NAME = #TableName FOR XML PATH('')
)
SELECT #SQL -- EXEC(#SQL)
Here I have created a script for any kind of SQL table. please copy this stored procedure and create this on your Environment and run this stored procedure with your Table.
exec [dbo].[SP_RemoveNullValues] 'Your_Table_Name'
stored procedure
GO
/****** Object: StoredProcedure [dbo].[SP_RemoveNullValues] Script Date: 09/09/2019 11:26:53 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- akila liyanaarachchi
Create procedure [dbo].[SP_RemoveNullValues](#PTableName Varchar(50) ) as
begin
DECLARE Cussor CURSOR FOR
SELECT COLUMN_NAME,TABLE_NAME,DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #PTableName
OPEN Cussor;
Declare #ColumnName Varchar(50)
Declare #TableName Varchar(50)
Declare #DataType Varchar(50)
Declare #Flage int
FETCH NEXT FROM Cussor INTO #ColumnName,#TableName,#DataType
WHILE ##FETCH_STATUS = 0
BEGIN
set #Flage=0
If(#DataType in('bigint','numeric','bit','smallint','decimal','smallmoney','int','tinyint','money','float','real'))
begin
set #Flage=1
end
If(#DataType in('date','atetimeoffset','datetime2','smalldatetime','datetime','time'))
begin
set #Flage=2
end
If(#DataType in('char','varchar','text','nchar','nvarchar','ntext'))
begin
set #Flage=3
end
If(#DataType in('binary','varbinary'))
begin
set #Flage=4
end
DECLARE #SQL VARCHAR(MAX)
if (#Flage in(1,4))
begin
SET #SQL =' update ['+#TableName+'] set ['+#ColumnName+']=0 where ['+#ColumnName+'] is null'
end
if (#Flage =3)
begin
SET #SQL =' update ['+#TableName+'] set ['+#ColumnName+'] = '''' where ['+#ColumnName+'] is null '
end
if (#Flage =2)
begin
SET #SQL =' update ['+#TableName+'] set ['+#ColumnName+'] ='+'''1901-01-01 00:00:00.000'''+' where ['+#ColumnName+'] is null '
end
EXEC(#SQL)
FETCH NEXT FROM Cussor INTO #ColumnName,#TableName,#DataType
END
CLOSE Cussor
DEALLOCATE Cussor
END
You'll have to loop over the set of columns and check each one. You should be able to get a list of all columns with a DESCRIBE table command.
Pseudo-code:
foreach $column ($cols) {
query("SELECT count(*) FROM table WHERE $column IS NOT NULL")
if($result is zero) {
# $column contains only null values"
push #onlyNullColumns, $column;
} else {
# $column contains non-null values
}
}
return #onlyNullColumns;
I know this seems a little counterintuitive but SQL does not provide a native method of selecting columns, only rows.
I would also recommend to search for fields which all have the same value, not just NULL.
That is, for each column in each table do the query:
SELECT COUNT(DISTINCT field) FROM tableName
and concentrate on those which return 1 as a result.
SELECT t.column_name
FROM user_tab_columns t
WHERE t.nullable = 'Y' AND t.table_name = 'table name here' AND t.num_distinct = 0;
An updated version of 'user2466387' version, with an additional small test which can improve performance, because it's useless to test non nullable columns:
AND IS_NULLABLE = 'YES'
The full code:
SET NOCOUNT ON;
DECLARE
#ColumnName sysname
,#DataType nvarchar(128)
,#cmd nvarchar(max)
,#TableSchema nvarchar(128) = 'dbo'
,#TableName sysname = 'TableName';
DECLARE getinfo CURSOR FOR
SELECT
c.COLUMN_NAME
,c.DATA_TYPE
FROM
INFORMATION_SCHEMA.COLUMNS AS c
WHERE
c.TABLE_SCHEMA = #TableSchema
AND c.TABLE_NAME = #TableName
AND IS_NULLABLE = 'YES';
OPEN getinfo;
FETCH NEXT FROM getinfo INTO #ColumnName, #DataType;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = N'IF NOT EXISTS (SELECT * FROM ' + #TableSchema + N'.' + #TableName + N' WHERE [' + #ColumnName + N'] IS NOT NULL) RAISERROR(''' + #ColumnName + N' (' + #DataType + N')'', 0, 0) WITH NOWAIT;';
EXECUTE (#cmd);
FETCH NEXT FROM getinfo INTO #ColumnName, #DataType;
END;
CLOSE getinfo;
DEALLOCATE getinfo;
You might need to clarify a bit. What are you really trying to accomplish? If you really want to find out the column names that only contain null values, then you will have to loop through the scheama and do a dynamic query based on that.
I don't know which DBMS you are using, so I'll put some pseudo-code here.
for each col
begin
#cmd = 'if not exists (select * from tablename where ' + col + ' is not null begin print ' + col + ' end'
exec(#cmd)
end

Resources