Programmatically set column nullable - sql-server

I would like to remove not null constraint on a column, whatever its type is (nvarchar, bingint, smallint).
I am pretty sure it can be achieved using sp_executesql and building the ALTER TABLE xxx ALTER COLUMN cccc type NULL statement (by getting column type information from INFORMATION_SCHEMA.COLUMNS).
Is there any other way?

No. The only way to remove the NOT NULL constraint is by using ALTER TABLE as you describe. Any variation on how you do it will come back to the same thing. However, if you do it through a GUI tool such as SSMS it might choose to drop and re-create the table (you shouldn't lose any data but it might take much longer than you imagined). In general be careful of using GUI tools to make changes to big tables.

maybe this work :
Declare #TableName As nvarchar(250)
,#ColumnName As nvarchar(250)
,#TypeName As nvarchar(250)
Declare Cr Cursor for
Select Top 10 obj.name As TableName ,clm.name As ColumnName ,typ.name As TypeName
from sys.Columns As clm
inner join sys.Objects As obj On obj.object_Id = clm.object_id
inner join sys.types As typ On typ.system_type_id = clm.system_type_id
where obj.type = N'U'
And typ.system_type_id in (52 ,127 ,167)
open Cr
fetch next from Cr into #TableName ,#ColumnName , #TypeName
while(##fetch_status = 0)
begin
Declare #StrSQL nvarchar(max)
Set #StrSQL = N' Alter Table ' + #TableName + N' Alter Column ' + #ColumnName + N' ' + #TypeName
Print #StrSQL
fetch next from Cr into #TableName ,#ColumnName , #TypeName
End
Close CR
Deallocate CR

create procedure sp_RemoveNotNullConstraint
(
#tableName nvarchar(255),
#columnName nvarchar(255)
)
as
begin
declare #dataType nvarchar(255)
declare #sql nvarchar(max);
select #dataType =
case
when C.CHARACTER_MAXIMUM_LENGTH is not null
then C.DATA_TYPE + '(' + CAST(C.CHARACTER_MAXIMUM_LENGTH as nvarchar(255)) + ')'
else C.DATA_TYPE
end
from INFORMATION_SCHEMA.COLUMNS C
where C.TABLE_NAME = #tableName AND C.COLUMN_NAME = #columnName
set #sql = 'ALTER TABLE ' + #tableName + ' ALTER COLUMN ' + #columnName + ' ' + #dataType + ' NULL;';
exec sp_executesql #sql;
end
go

Related

Function variable is not recognize in subquery

I want to write a function that counts non null and non empty entries of a field. My problem is that the query does not run since the #tableName variable is not recognized in the select statement and I do not know why
create function dbo.getCount(#cod int, #columnName as varchar(20), #tableName as varchar(20))
Returns int as
Begin
--Count all filled entries
Return (select COUNT(*) from #tableName
where #columnName <> '' and #columnName is not null)
End;
go
As mentioned in the comments, but to reiterate, as I'll delete them after this answer:
You can't do this with a function, for multiple reasons. SELECT
COUNT(*) FROM #TableName means count the number of rows in the
table variable #TableName not the table who's name is the value of #TableName. WHERE #ColumnName <> '' would mean where the value of the scalar variable doesn't have the value '',
not where the column (in the aforementioned table) with the name of value of #ColumnName doesn't have the value ''.
And you can't do this in a function as to do this type of thing, you
need dynamic SQL; and you can't use dynamic SQL in a function (as you
can't use the EXEC command).
You can, however, do this with a Stored Procedure:
CREATE PROC dbo.GetCount #SchemaName sysname = N'dbo', #TableName sysname, #ColumnName sysname, #Count int OUTPUT AS
BEGIN
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = N'SELECT #Count = COUNT(NULLIF(' + QUOTENAME(c.[name]) + N',''''))' + #CRLF +
N'FROM ' + QUOTENAME(s.name) + N'.' + QUOTENAME(t.[name]) + N';'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE s.[name] = #SchemaName
AND t.[name] = #TableName
AND c.[name] = #ColumnName;
--PRINT #SQL; --Your debugging friend
EXEC sp_executesql #SQL, N'#Count int OUTPUT', #Count OUTPUT;
END
GO
And you run the SP like below (with sample table):
CREATE TABLE dbo.TestTable (SomeColumn varchar(10));
INSERT INTO dbo.TestTable (SomeColumn)
VALUES(''),('abc'),(NULL);
GO
DECLARE #Count int;
EXEC dbo.GetCount #TableName = N'TestTable', #ColumnName = N'SomeColumn', #Count = #Count OUTPUT;
SELECT #Count; --Returns 1
GO
DB<>Fiddle

Get the column_Name if I know the column value in sql server

My requirement is to compare data between two environments and i there is diff in both tables of both environments, insert that data to a temp table and display it.The above solution is not suiting for my scenario. I will explain my scenario in a better way.
In a Curor Cur1, I have all data of DEV from a Table(Report) where Rep_ID=1, Getting corresponding data from the TEST of REPORT Table where Rep_ID=1 In a while loop I am comparing the data of DEV and TEST
if (#DevData1 <> #TestData1)
BEGIN Get ColumnName from Report table where #DevData1 =1 Insert Into #TempTable (ColumnName, DevData1, TestData1)
ENDS Cur1 Ends
When I try to get the column name for a varchar column, I am getting the column name properly with the below query
Declare #ColStrRep nvarchar(1000)= 'select #retValOut= Col.value(''local-name(.)'', ''varchar(max)'') from (select * from Rep_attr where Rep_Name = '''+#reptName +''' for xml path(''''), type) as T(XMLCol) cross apply T.XMLCol.nodes(''*'') as n(Col) where Col.value(''.'', ''varchar(100)'') = '+#reptName +''
print #ColStrRep
EXEC Sp_executesql #ColStrRep,N'#retValOut nvarchar(100) out',#Column_Name OUT
But when I try to get the columnName for an integer column, and that too when we have the same value as 1 in the table( like RepID=1, Flag=1 , IsEmpty=1 etc), the query is getting confused and instead of Rep_ID, it retrieves the column IsEmpty. SO I need another query which just give me the columnname for a columnValue.
Thanks and Regards,
Sajitha
This solution will search using LIKE operator for varchar columns (i.e. column like '%5%') and a strict value for int columns (i.e. column=5)
DECLARE #table_name SYSNAME = 'your_table',
#search_string VARCHAR(100) = '5', --what to search
#column_name SYSNAME,
#type_name SYSNAME,
#sql_string VARCHAR(2000)
BEGIN TRY
DECLARE columns_cur CURSOR
FOR
SELECT columns.name, types.name type_name FROM sys.columns
JOIN sys.types ON columns.system_type_id = types.system_type_id
JOIN sys.objects ON columns.object_id=objects.object_id
WHERE objects.type = 'U' AND objects.name=#table_name
AND types.name IN ('varchar', 'nvarchar', 'int', 'bigint', 'smallint') --types of columns which you want to use for search
OPEN columns_cur
FETCH NEXT FROM columns_cur INTO #column_name, #type_name
WHILE (##FETCH_STATUS = 0)
BEGIN
IF #type_name IN ( 'varchar', 'nvarchar')
SET #sql_string = 'IF EXISTS (SELECT * FROM ' + #table_name + ' WHERE [' + #column_name + '] LIKE ''%' + #search_string + '%'') RAISERROR(''' + #table_name + ', ' + #column_name + ''',0,1) WITH NOWAIT'
ELSE
SET #sql_string = 'IF EXISTS (SELECT * FROM ' + #table_name + ' WHERE [' + #column_name + '] = TRY_CAST(''' + #search_string + ''' AS '+ #type_name +')) RAISERROR(''' + #table_name + ', ' + #column_name + ''',0,1) WITH NOWAIT'
EXECUTE(#sql_string)
FETCH NEXT FROM columns_cur INTO #column_name, #type_name
END
CLOSE columns_cur
DEALLOCATE columns_cur
END TRY
BEGIN CATCH
CLOSE columns_cur
DEALLOCATE columns_cur
RAISERROR(' - No access to table %s',0,1,#table_name) WITH NOWAIT
END CATCH
Thanks for the suggestion.
But I could manage the situation with the below query.
In case, the column value is a varchar, then the below query gives me the column Name.
Declare #ColStrDesc nvarchar(1000)= 'select
#retValOut= Col.value(''local-name(.)'', ''varchar(max)'')
from (select *
from Rep_attr
where Rep_Name = '''+#reptName +'''
for xml path(''''), type) as T(XMLCol)
cross apply
T.XMLCol.nodes(''*'') as n(Col)
where Col.value(''.'', ''varchar(100)'') = '''+#rep_Desc +''''
print #ColStrDesc
EXEC Sp_executesql #ColStrDesc,N'#retValOut nvarchar(100) out',#Column_Name OUT
In case, the column Value is an integer , thenn below query gives me column name.
Declare #ColErr nvarchar(1000)= 'SELECT #retValOut= STUFF(''''
+ CASE WHEN EXISTS (SELECT 1 FROM [dbo].[Rep_attr] WHERE Cast([Rep_Errs] as VARCHAR(64)) = '+#rep_Errs+') THEN '' Rep_Errs'' ELSE '''' END , 1, 1, '''')'
EXEC Sp_executesql #ColErr,N'#retValOut nvarchar(100) out',#Column_Name OUT

Convert blank to NULL for a table

In my table I have few columns which are having blank values. Can anyone suggest me a query by which I can replace all blanks to NULL for a given table?
EDIT
I am sorry if I couldn't specify my question correctly, I don't want to give the column name in my query. All I have is the table name. So, for a given table I want to check all columns and convert their blank values to NULL.
As an approach next stored procedure could be help:
CREATE PROCEDURE up_replaceBlanksByNulls
#schemaName nvarchar(50),
#tableName nvarchar(100)
AS
declare #query1 nvarchar(max) = ''
select #query1 = #query1 + 'UPDATE ' + #schemaName + '.' + #tableName + ' SET ' + c.COLUMN_NAME + ' = NULL WHERE ' +
c.COLUMN_NAME + ' = '''';' FROM INFORMATION_SCHEMA.COLUMNS c
WHERE C.TABLE_NAME = #tableName
EXECUTE sp_executesql #query1
GO
Usage:
up_replaceBlanksByNulls 'dbo', 'myTable'
To get rid of all blank values in a table :
CREATE PROCEDURE getRidOfBlanks
#tableName nvarchar(50)
AS
DECLARE #colName varchar(50)
DECLARE Table_Cursor CURSOR FOR
select COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME='#tableName'
OPEN Table_Cursor;
FETCH NEXT FROM Table_Cursor INTO #colName
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE #tableName SET #colName = NULL WHERE #colName = '';
FETCH NEXT FROM Table_Cursor INTO #colName
END;
CLOSE Table_Cursor;
DEALLOCATE Table_Cursor;
GO
To use this, you create your procedure with my code, then you execute it with your tableName.
Simply using UPDATE like this:
UPDATE myTable SET myColumn = NULL WHERE myColumn = '';
If your column names have spaces in them, here is an alteration of #alex.b procedure.
CREATE PROCEDURE up_replaceBlanksByNulls
#schemaName nvarchar(50),
#tableName nvarchar(100)
AS
declare #query1 nvarchar(max) = ''
select #query1 = #query1 + 'UPDATE ' + #schemaName + '.' + #tableName + ' SET ' + case when c.COLUMN_NAME like '% %' then '[' + c.COLUMN_NAME + ']' Else c.COLUMN_NAME end + ' = NULL WHERE ' +
case when c.COLUMN_NAME like '% %' then '[' + c.COLUMN_NAME + ']' Else c.COLUMN_NAME end + ' = '''';' FROM INFORMATION_SCHEMA.COLUMNS c
WHERE C.TABLE_NAME = #tableName
print #query1
EXECUTE sp_executesql #query1
GO

Changing columns collation using batch sql in sql server 2005

I took over a databases. It appears that at some point default database collation was changed. As a result some columns have old default collation, but new columns, added after collation was changed have new collation. Also there's a great deal of stored procedure code that uses unions. When that code executes it happens that I get
Cannot resolve collation conflict for column 5 in SELECT statement.
error (for instance first SELECT returns column in Collation A, whereas second SELECT returns column in Collation B). Is there a way to write an SQL that would for instance select all columns with collation SQL_Latin1_General_CP1_CI_AS (old collation) to new collation Latin1_General_CI_AS ?
Thanks
Something like this should do the trick
Look for all columns with incorrect collation
compose an alter table statement & alter column statement per incorrect column
DECLARE #sql nvarchar(4000)
, #tablename sysname
, #name sysname
, #datatype sysname
, #length int
, #precision int
, #scale int
, #is_nullable bit
DECLARE cur_collations CURSOR LOCAL READ_ONLY
FOR SELECT tablename = object_name(object_id)
, name
, TYPE_NAME(user_type_id)
, max_length
FROM sys.columns
WHERE collation_name = 'SQL_Latin1_General_CP1_CI_AS'
OPEN cur_collations
FETCH NEXT FROM cur_collations INTO #tablename, #name, #datatype, #length
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
set #sql = N'
ALTER TABLE ' + QUOTENAME(#tablename) + N'
ALTER COLUMN ' + QUOTENAME(#name) + N' ' + QUOTENAME(#datatype) + N'(' + cast(#length as nvarchar(10)) + N')
COLLATE Latin1_General_CI_AS
' + case when #is_nullable = 1 then N'NULL' else N'NOT NULL' end + N' '
EXEC (#sql)
END
FETCH NEXT FROM cur_collations INTO #tablename, #name, #datatype, #length
END
CLOSE cur_collations
DEALLOCATE cur_collations
Updated
Supports Schemas
Correctly implement is_nullable
DECLARE
#sql nvarchar(4000),
#tablename sysname,
#schemaname sysname,
#name sysname,
#datatype sysname,
#length int,
#precision int,
#scale int,
#is_nullable bit
DECLARE cur_collations CURSOR LOCAL READ_ONLY FOR
SELECT
tablename = OBJECT_NAME(columns.object_id),
schemaname = SCHEMA_NAME(schema_id),
columns.name,
TYPE_NAME(user_type_id),
max_length,
is_nullable
FROM sys.columns
INNER JOIN sys.objects on columns.object_id = objects.object_id
WHERE
collation_name = 'SQL_Latin1_General_CP1_CI_AS'
OPEN cur_collations
FETCH NEXT FROM cur_collations INTO #tablename, #schemaname, #name, #datatype, #length, #is_nullable
WHILE (##fetch_status -1) BEGIN
IF (##fetch_status -2) BEGIN
SET #sql = N'ALTER TABLE ' + QUOTENAME(#schemaname) + '.' + QUOTENAME(#tablename) + N' ALTER COLUMN ' + QUOTENAME(#name) + N' ' + QUOTENAME(#datatype) + N'(' + cast(#length as nvarchar(10)) + N') COLLATE Latin1_General_CI_AS ' + case when #is_nullable = 1 then N'NULL' else N'NOT NULL' end + N' '
--EXEC (#sql)
PRINT #sql
END
FETCH NEXT FROM cur_collations INTO #tablename, #schemaname, #name, #datatype, #length, #is_nullable
END

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