Delete all stored procedures in a specific SQL Server schema - sql-server

I have hundreds of procedures auto generated by DataSync.
I don't have the time and sense to delete them manually.
They all start with DataSync.
Is there a way to delete all stored procedures where the name start with DataSync.?

Use the information_schema.routines (which is fairly standard across RDBMSs such as MSSQL,Mysql):
If your proc names start "DataSync." then they are probably in a schema, so you can find them with:
select
'DROP PROCEDURE [' + routine_schema + '].[' + routine_name + ']'
from
information_schema.routines where routine_schema = 'DataSync' and routine_type = 'PROCEDURE'
If your proc names start "DataSync" then you can find them with:
select
'DROP PROCEDURE [' + routine_schema + '].[' + routine_name + ']'
from
information_schema.routines where routine_name like 'DataSync%' and routine_type = 'PROCEDURE'
If you wanted to execute all these drop statements, you can build a single execute using FOR XML PATH as follows:
declare #sql varchar(max)
set #sql = (
select
'DROP PROCEDURE [' + routine_schema + '].[' + routine_name + '] '
from
information_schema.routines where routine_schema = 'DataSync' and routine_type = 'PROCEDURE'
FOR XML PATH ('')
)
exec (#sql)

Assuming you mean SQL Server when you specify "SQL" - then the easiest way is this: run this query:
SELECT
name,
DropCmd = 'DROP PROCEDURE DataSync.' + name
FROM sys.procedures
WHERE
schema_id = SCHEMA_ID('DataSync')
and the even "lazier" version would be to use a cursor to do this automatically for you:
DECLARE DropSpCursor CURSOR FAST_FORWARD FOR
SELECT
name
FROM sys.procedures
WHERE schema_id = SCHEMA_ID('DataSync')
DECLARE #StoredProcName sysname
DECLARE #DropStatement NVARCHAR(1000)
OPEN DropSpCursor
FETCH NEXT FROM DropSpCursor INTO #StoredProcName, #SchemaName
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
SET #DropStatement = N'DROP PROCEDURE DataSync.' + #StoredProcName
EXEC(#DropStatement)
END
FETCH NEXT FROM DropSpCursor INTO #StoredProcName
END
CLOSE DropSpCursor
DEALLOCATE DropSpCursor

No need for XML or loops:
declare #sql varchar(max) = ''
select #sql += 'drop procedure [' + routine_schema + '].[' + routine_name + '];'
from information_schema.routines where routine_schema = 'DataSync' and routine_type = 'PROCEDURE'
exec(#sql)

DECLARE #name AS VARCHAR(max)
DECLARE MyCursor CURSOR FAST_FORWARD READ_ONLY FOR
SELECT name FROM sys.objects WHERE type='P' AND schema_id=SCHEMA_ID('DataSync')
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC('DROP PROCEDURE DataSync.' + #name)
FETCH NEXT FROM MyCursor INTO #name
END
CLOSE MyCursor
DEALLOCATE MyCursor
EDIT: changed where clause since it turned out DataSync is a schema name.

I've been using this short script to clear all SPs from a given schema (when using SQL Server). It iterates direct sys.procedures.
DECLARE #schema VARCHAR(100)
SET #schema = 'DataSync'
DECLARE #CurrentStatement AS VARCHAR(MAX)
SET #CurrentStatement = (SELECT TOP(1) 'DROP PROCEDURE [' + #schema + '].[' + name + ']'
FROM sys.procedures
WHERE schema_id = SCHEMA_ID(#schema))
WHILE #CurrentStatement IS NOT NULL
BEGIN
EXEC (#CurrentStatement)
SET #CurrentStatement = (SELECT TOP(1) 'DROP PROCEDURE [' + #schema + '].[' + name + ']'
FROM sys.procedures
WHERE schema_id = SCHEMA_ID(#schema))
END
The premise is very similar to the answer provided by marc_s; however doesn't utilize a cursor for the iteration. While there's a record in sys.procedures matching our schema, we need to delete it.

try this with sql2012 or above,
this will be help to delete all objects by selected schema
keep 'P' and remove rest for stored procedure only (o.type IN ('P')
DECLARE #MySchemaName VARCHAR(50)='dbo', #sql VARCHAR(MAX)='';
DECLARE #SchemaName VARCHAR(255), #ObjectName VARCHAR(255), #ObjectType VARCHAR(255), #ObjectDesc VARCHAR(255), #Category INT;
DECLARE cur CURSOR FOR
SELECT (s.name)SchemaName, (o.name)ObjectName, (o.type)ObjectType,(o.type_desc)ObjectDesc,(so.category)Category
FROM sys.objects o
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sysobjects so ON so.name=o.name
WHERE s.name = #MySchemaName
AND so.category=0
AND o.type IN ('P','PC','U','V','FN','IF','TF','FS','FT','PK','TT')
OPEN cur
FETCH NEXT FROM cur INTO #SchemaName,#ObjectName,#ObjectType,#ObjectDesc,#Category
SET #sql='';
WHILE ##FETCH_STATUS = 0 BEGIN
IF #ObjectType IN('FN', 'IF', 'TF', 'FS', 'FT') SET #sql=#sql+'Drop Function '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('V') SET #sql=#sql+'Drop View '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('P') SET #sql=#sql+'Drop Procedure '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('U') SET #sql=#sql+'Drop Table '+#MySchemaName+'.'+#ObjectName+CHAR(13)
--PRINT #ObjectName + ' | ' + #ObjectType
FETCH NEXT FROM cur INTO #SchemaName,#ObjectName,#ObjectType,#ObjectDesc,#Category
END
CLOSE cur;
DEALLOCATE cur;
SET #sql=#sql+CASE WHEN LEN(#sql)>0 THEN 'Drop Schema '+#MySchemaName+CHAR(13) ELSE '' END
PRINT #sql
EXECUTE (#sql)

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'

Need to run a stored procedure on all non system databases

I'm trying to loop through all non system databases and run a stored procedure. This stored procedure exists in all of the user databases.
This is what I have found so far:
DECLARE #command varchar(1000)
SELECT #command = 'USE ? SELECT name FROM sysobjects WHERE xtype = ''U'' ORDER BY name'
USE #command;
GO
EXECUTE Support.CleanIndiciesAndShrinkDatabase;
GO
I get an error this error:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '#command'.
Msg 2812, Level 16, State 62, Line 1
Could not find stored procedure 'Support.CleanIndiciesAndShrinkDatabase'.
Any suggestions on fixing this?
Try the following
DECLARE #command varchar(1000)
DECLARE #spName VARCHAR(50)
SET #spName = 'Support.CleanIndiciesAndShrinkDatabase'
SELECT #command = 'IF ''?'' NOT IN(''master'', ''model'', ''msdb'', ''tempdb'')
BEGIN
USE ?
IF EXISTS(SELECT TOP 1 1 FROM sys.procedures AS P WHERE p.name = ''' + #spName + ''')
BEGIN
PRINT ''running '+ #spName + ' on '' + DB_NAME()
EXEC ' +#spName+'
END
ELSE
BEGIN
PRINT ''' + #spName + ' was on found on database '' + DB_NAME()''
END
END '
EXEC sp_MSforeachdb #command
It will run on all non-system databases.
Now, the error you get means that SQL Server cannot find the stored procedure. You could fix this by creating the stored procedure on any database that does not have it yet and then running it.
So a better query would be
DECLARE #command varchar(1000)
DECLARE #schemaName VARCHAR(50)
DECLARE #spName VARCHAR(50)
SET #schemaName = 'Support'
SET #spName = 'CleanIndiciesAndShrinkDatabase'
SELECT #command = 'IF ''?'' NOT IN(''master'', ''model'', ''msdb'', ''tempdb'')
BEGIN
USE ?
IF NOT EXISTS(SELECT TOP 1 1
FROM sys.procedures AS P
INNER JOIN sys.schemas AS S ON S.schema_id = P.schema_id
WHERE p.name = ''' + #spName + '''
AND s.name = ''' + #schemaName + ''')
BEGIN
PRINT ''creating '+ #spName + ' on '' + DB_NAME()
IF NOT EXISTS ( SELECT TOP 1 1
FROM sys.schemas AS S
WHERE S.name = ''' + #schemaName + ''' )
BEGIN
PRINT ''CREATING SCHEMA ' + #schemaName + '''
EXEC ( '' CREATE SCHEMA ' + #schemaName + ''' );
END;
EXEC ( ''
CREATE PROCEDURE ' + #schemaName + '.' + #spName + '
AS
BEGIN
-- SP CODE GOES HERE
-- SELECT COUNT(*) FROM SYS.TABLES --uncomment this for check
END
'' );
END
PRINT ''running '+ #spName + ' on '' + DB_NAME()
EXEC ' + #schemaName + '.' + #spName +'
END '
EXEC sp_MSforeachdb #command
You can try this:
Create PROC PROC_NAME
AS
BEGIN
DECLARE #name nvarchar(50)
declare #cursor cursor
set #cursor = CURSOR FAST_FORWARD FOR select name from sys.databases where database_id > 4
open #cursor
FETCH NEXT FROM #cursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #use nvarchar(50) = 'USE '
SET #use = #use + #name
Declare #query nvarchar(max) = #use + ' exec Your_PROC'
EXEC sp_executesql #query
FETCH NEXT FROM #cursor INTO #name
END
CLOSE #cursor
DEALLOCATE #cursor
END
Try something like this:
DECLARE #DynamicTSQLStatement NVARCHAR(MAX);
SELECT #DynamicTSQLStatement = STUFF
(
(
SELECT 'USE [' + [name] + ']; EXECUTE Support.CleanIndiciesAndShrinkDatabase;'
FROM [sys].[databases]
WHERE [name] NOT IN ('master', 'tempdb', 'model', 'msdb')
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,1
,''
);
EXECUTE sp_executesql #DynamicTSQLStatement;

Convert Table name from lower case to upper case

The script below shows an example query for data that have been converted from lower case, but it only changed the data on one column in the table.
Use MYF601T
Go
UPDATE ROAD_LINE
SET NAM = UPPER(NAM)
However, the following script that I'm trying to write is to convert all on all columns on all tables, but the result generated with errors.
Use MYF601T
Go
UPDATE INFORMATION_SCHEMA.TABLES
SET INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA = UPPER(INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA
How to do this for all tables and all columns inside?
If for whather reasons you want to convert your tables names to Upper case, you can:
use a cursor that will select the tables you want to rename
loop through the table list
rename it using sp_rename or update it
Note that you have to update the Select in the cursor to suit your needs (select column or table name you want, ...)
This will rename tables:
declare #TABLE_NAME sysname, #TABLE_SCHEMA sysname
declare #TABLE sysname, #newName sysname
declare table_cursor Cursor
For Select TABLE_NAME, TABLE_SCHEMA From INFORMATION_SCHEMA.TABLES Where TABLE_NAME like 'xyz%' -- and TABLE_SCHEMA like ...
open table_cursor
Fetch Next From table_cursor Into #TABLE_NAME, #TABLE_SCHEMA;
While ##FETCH_STATUS = 0
Begin
Set #TABLE = quotename(UPPER(#TABLE_SCHEMA)) + '.' + quotename(UPPER(#TABLE_NAME))
Set #newName = UPPER(#TABLE_NAME)
print 'rename ' + #TABLE + ' to ' + #newName
-- uncomment next like if you really want to rename them
--exec sp_rename #TABLE, #newName
Fetch Next From table_cursor Into #TABLE_NAME, #TABLE_SCHEMA;
End
Close table_cursor
Deallocate table_cursor
If you want to update all columns xyz in table zyx, you can use this:
declare #TABLE_NAME sysname, #TABLE_SCHEMA sysname, #COLUMN_NAME sysname
declare #TABLE sysname, #sql nvarchar(max)
declare table_cursor Cursor
For Select TABLE_NAME, TABLE_SCHEMA, COLUMN_NAME From INFORMATION_SCHEMA.COLUMNS
Where COLUMN_NAME like 'xxx' -- and data_type '' ... and TABLE_NAME like 'xyz%' ... and TABLE_SCHEMA like ...
open table_cursor
Fetch Next From table_cursor Into #TABLE_NAME, #TABLE_SCHEMA, #COLUMN_NAME;
While ##FETCH_STATUS = 0
Begin
Set #TABLE = quotename(#TABLE_SCHEMA) + '.' + quotename(#TABLE_NAME)
set #sql = 'Update ' + #TABLE + ' set ' + #COLUMN_NAME + ' = UPPER(' + #COLUMN_NAME + ')'
print #sql
-- uncomment next like if you really want to execute them
--exec sp_executesql #sql
Fetch Next From table_cursor Into #TABLE_NAME, #TABLE_SCHEMA, #COLUMN_NAME;
End
Close table_cursor
Deallocate table_cursor
Use a dynamic query to update all the column content to upper case.
Query
declare #query varchar(max)
select #query =
stuff
(
(
select ';update ' + table_name + ' ' +
'set ' + column_name + ' = upper(' + column_name + ')'
from information_schema.columns
where table_name = 'ROAD_LINE'
order by table_name,column_name
for xml path('')
)
, 1, 1, '')
execute(#query);

Removing quotes added to column names from Excel import SQL Server 2008

I've noticed that when I use SSMS to import an Excel spreadsheet into SQL Server quotation marks are added. I've read somewhere that for whatever reason it's necessary for Excel to do this. Once in SQL Server, these quotes around the column names are useless and I'd like to have a programmatic way to remove them. The closest thing, which doesn't work, that I have tried to make is EXEC sp_rename 'Table.["withquotes"]', NewColumnName, 'replace(Table.["withquotes",'"','']. I'd like to loop through all of the column names in a table and use the replace function wherever a those column names contain quotation marks. Is there a typical, idiomatic way to do this?
I believe this should help...
DECLARE #tbl sysname, #col sysname
DECLARE #cmd nvarchar(max)
DECLARE cCol CURSOR FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '"%"'
OPEN cCol
FETCH NEXT FROM cCol INTO #tbl, #col
WHILE ##fetch_status = 0
BEGIN
SET #cmd =
N'EXEC sp_rename ''[' + #tbl + '].[' + #col + ']'', ' +
'''' + REPLACE(#col, '"', '') + N''', ''COLUMN'''
--PRINT #cmd
EXEC sp_executeSQL #cmd
FETCH NEXT FROM cCol INTO #tbl, #col
END
CLOSE cCol
DEALLOCATE cCol
Just for the info, I had errors with the procedure of OzrenTkalcecKrznaric.
After searching, it was due to absence of schema name. So here is my version, updated to include that schema name:
DECLARE #tbl sysname, #col sysname, #sch sysname
DECLARE #cmd nvarchar(max)
DECLARE cCol CURSOR FOR
SELECT TABLE_NAME, COLUMN_NAME, TABLE_SCHEMA
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '"%"'
OPEN cCol
FETCH NEXT FROM cCol INTO #tbl, #col, #sch
WHILE ##fetch_status = 0
BEGIN
SET #cmd =
N'EXEC sp_rename ''[' + #sch + '].[' + #tbl + '].[' + #col + ']'', ' +
'''' + REPLACE(#col, '"', '') + N''', ''COLUMN'''
--PRINT #cmd
EXEC sp_executeSQL #cmd
FETCH NEXT FROM cCol INTO #tbl, #col, #sch
END
CLOSE cCol
DEALLOCATE cCol
One can also generate the statements, to be then copied, pasted and executed:
USE myDb
select 'Exec sp_rename ''' + QuoteName(Schema_Name(tables.schema_id)) + '.' + QuoteName(tables.name) + '.' + QuoteName(columns.name) + '''' +
',''' + REPLACE ( columns.name , '"' , '') + ''', ''COLUMN'''
from sys.columns
join sys.tables on columns.object_id = tables.object_id
join sys.schemas on tables.schema_id = schemas.schema_id
where sys.columns.name like '"%"' AND sys.schemas.name = 'mySchema'
(replace myDb and mySchema by your values)

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