TSQL Find MIN/MAX LEN ColName over many tables - sql-server

I need to find the MAX LEN for all responses in column across many tables. Some of these column names match across tables, some don't. If they match, I need to use the column name through all the tables that it matches. So, say 10 tables with a total of 200 different column names. I created a TempCol table. I also have all the table names in a temp table. My thought is to add cols to the TempCol table for Table1MAX, Table1MIN, Table2MAX, Table2MIN etc.
This finds the MAX (IF Col_1 is in Table1):
SELECT MAX(LEN(Col_1)) FROM Table1
I'd like to fill in the TempCol table, with the values from above, but I keep hitting a wall.
Anybody have any ideas?

Here's one way, for the MAX length only; you can use it as a starting point and modify/extend it to include more information in the results table:
create table dbo.Results (
TableName sysname not null,
ColumnName sysname not null,
MaxLength int not null default 0,
primary key (TableName, ColumnName)
)
insert into dbo.Results (TableName, ColumnName)
select object_name(sc.object_id), sc.name
from sys.columns sc
join sys.types st
on sc.system_type_id = st.system_type_id
-- get data for varchar(max) columns only
where st.name = 'varchar' and sc.max_length = -1
declare #TableName sysname, #ColumnName sysname, #sql nvarchar(max)
declare TablesAndColumns cursor local fast_forward
for
select TableName, ColumnName
from dbo.Results
open TablesAndColumns
fetch next from TablesAndColumns into #TableName, #ColumnName
while ##fetch_status = 0
begin
set #sql = 'update dbo.Results set MaxLength = (select isnull(max(len(' + #ColumnName + ')),0) ' +
' from ' + #TableName + ') ' +
' where TableName = ''' + #TableName + ''' and ColumnName = ''' + #ColumnName + ''''
print #sql
exec sp_executesql #sql
fetch next from TablesAndColumns into #TableName, #ColumnName
end
close TablesAndColumns
deallocate TablesAndColumns
select * from dbo.Results
Using cursors and dynamic SQL isn't always a good idea, but for a one-time system task like this it's a reasonable approach.

Related

create a table with table and database statistics

There are around 200+ tables in our SQL DB and every table has 1 common field [updated_timestamp]
Is there a way to query the DB itself and list all tables, with the MAX value of [updated_timestamp] and the row count of each table?
i'm sorry if i've not explained that the best
are there secret/system tables that hold such info?
my desired output would be
table
updated_timestamp
row_count
Table A
2022-08-22
89,854
Table B
2022-08-18
103,55,166
if there is a table like this i could intergate that would be great, but i'm assuming not that simple.
i picked up some code from another stored procedure and was hoping this would be of use for the row count at least
SELECT
QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) AS [DB_Schema],
QUOTENAME(sOBJ.name) AS [TableName],
SUM(sPTN.Rows) AS [Row_Count]
INTO ##tmpRowCount2
FROM
sys.objects AS sOBJ
INNER JOIN sys.partitions AS sPTN
ON sOBJ.object_id = sPTN.object_id
WHERE
sOBJ.type = 'U'
AND sOBJ.is_ms_shipped = 0x0
AND index_id < 2
GROUP BY
sOBJ.schema_id
, sOBJ.name
ORDER BY [Row_Count]
GO
ALTER TABLE ##tmpRowCount2 ADD updated_timestamp datetime NULL;
-- keep only API rows
DELETE FROM ##tmpRowCount2
WHERE [DB_Schema] != '[api]'
DECLARE #Row_Count int
DECLARE #sql nvarchar(max)
DECLARE #TableName as VARCHAR(256)
DECLARE #DB_Schema as VARCHAR(256)
DECLARE #updated_timestamp as DATETIME
DECLARE tablenamefromcursor CURSOR FOR
SELECT TableName,
Row_Count,
DB_Schema
FROM ##tmpRowCount2
OPEN tablenamefromcursor
FETCH NEXT FROM tablenamefromcursor INTO #TableName, #Row_Count, #DB_Schema
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'UPDATE ##tmpRowCount2 SET updated_timestamp = ' +
'(SELECT MAX([updated_timestamp]) FROM ' + #DB_Schema + '.' + #TableName +
') WHERE TableName = ''' + #TableName + ''''
EXEC(#sql)
FETCH NEXT FROM tablenamefromcursor INTO #TableName, #Row_Count, #DB_Schema
END
CLOSE tablenamefromcursor
DEALLOCATE tablenamefromcursor
Code editied above and i can confirm it works, by debugging with select #sql iwas able to parse the statement and edit the syntax unitl it worked by getting the parethesis and quotes in the right order

SQL Server Query to show table name and specific column name and current value in all user table

All of our user tables have a primary key and a rowid_time column. We would like to develop a SQL query which lists:
table name
the value of the primary key
the value of the rowid_time column
(only these three columns and NOT ALL columns of the table)
for all rows and tables in the database.
Is that doable? Ideally this is delivered via a database view.
With dynamic SQL and using a SQL cursor, we can solve the requirement as follows
DECLARE #TableName sysname
DECLARE #SQL nvarchar(max)
DECLARE #PKColumnList nvarchar(max)
DECLARE mycursor CURSOR FAST_FORWARD
FOR
SELECT name FROM sys.tables order by Name
OPEN mycursor
FETCH NEXT FROM mycursor INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
----------------
SELECT #PKColumnList = string_agg(COLUMN_NAME, ',')
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE a
WHERE
EXISTS(
SELECT *
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS b
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY'
AND a.CONSTRAINT_NAME = b.CONSTRAINT_NAME) AND
TABLE_NAME = #tablename
SET #PKColumnList = concat(#PKColumnList+',','rowid_time')
SELECT #SQL = '
;with t1 as (
select ''' + #TableName + ''' as TableName
), t2 as (
SELECT
''' + #TableName + ''' as TableName,
COUNT(*) OVER (Partition By 1) as RowsCount, '
+ #PKColumnList +
' FROM [' + #TableName + ']
)
select
t1.TableName,
t2.RowsCount, '
+ #PKColumnList + '
from t1
full join t2
on t1.TableName = t2.TableName'
EXEC SP_EXECUTESQL #SQL
-----------------
FETCH NEXT FROM mycursor INTO #TableName
END
CLOSE mycursor
DEALLOCATE mycursor
If the PK column for all tables is ID column (no composite key and all PK fields are named as ID for all tables), then SQL sp_MSForEachTable procedure can be used as follows
EXEC sp_MSForEachTable 'SELECT ''?'' as TableName, ID, rowid_time FROM ?'

MSSQL Find Matching Columns in tables with no defined relationships

Is there a script out there that will let MSSQL find columns with records that have the same data in multiple tables.
What I want to do is find the primary keys to data tables that we imported from excel spread sheets that were made from another database.
Thanks,
Chris
You're going to want to look up the SysObjects and SysColumn system tables, very handy for this sort of thing.
Here's an example that looks through all tables for the integer value 500. Note that if you want to look for a different type of column you'll need to change the xtype. It's not a full blown "Compare every column in my database against every other column" example however it should give you the basic idea and hopefully get you started.
Additionally I'm using a memory table for this example. If your database is large you will want to use a temporary table and a cursor likely.
This returns a single column recordset with the value of "Table - ColumnName = Search Value"
-- declare my search table
DECLARE #Columns TABLE (TableName varchar(50), ColumnName varchar(50))
DECLARE #Results TABLE (Results VARCHAR(255))
DECLARE #SearchData INT
SET #SearchData = 500
DECLARE #TableName VARCHAR(50)
DECLARE #ColumnName VARCHAR(50)
DECLARE #Command VARCHAR(1024)
-- Find all tables with an integer column
Insert INTO #Columns
Select sysobjects.[Name] as TableName, syscolumns.[Name] as ColumnName
from dbo.sysobjects INNER Join dbo.syscolumns ON dbo.sysobjects.id = dbo.syscolumns.id
Where sysobjects.xtype = 'U' and syscolumns.xtype = 56 Order By TableName, ColumnName
--Loop!
WHILE NOT (Select TOP 1 TableName from #Columns) IS NULL
BEGIN
Select TOP 1 #TableName = TableName, #ColumnName = ColumnName from #Columns
SET #Command = 'Select ''' + #TableName + ' - ' + #ColumnName + ' = ' + CAST(#SearchData as varchar(32)) + ''' FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ' + CAST(#SearchData as VARCHAR(32))
Insert INTO #Results
exec(#Command)
Delete from #Columns where TableName = #TableName AND ColumnName = #ColumnName
END
-- Export all results
Select * from #Results

Bulk modification of unique ids in SQL Server

[This is a bit of an unusual problem, I know...]
What I need is a script that will change every unique id value to new one in our database. The problem is that we have configuration tables that can be exported between instances of our software which is id-sensitive (clobbering existing ids). Years ago, we set up a "wide-enough" id gap between our development "standard configuration" and our client's instances, which is now not wide enough :( - e.g. we're getting id conflicts when clients import our standard configuration.
A SQL script to do the following is definitely the simplest/shortest-timeframe thing that we can do. e.g. fixing the code is far too complicated and error prone to consider. Note that we are not "eliminating" the problem here. Just changing the gap from 1000's to 1000000's or more (the existing gap took 5 years to fill).
I believe the simplest solution would be to:
change all our tables to UPDATE_CASCADE (none of them are - this will greatly simplify the script)
create an identity table with the new lowest id that we want
For each table, modify the id to the next one in the identity table (using identity insert modifier flags where necessary). Perhaps after each table is processed, we could reset the identity table.
turn off UPDATE_CASCADE, and delete the identity table.
I am seeking any (partial or full) scripts for this.
Unfortunately UPDATE_CASCADE doesn't exist in the world of Sql Server. I suggest for each table you to re-key you do the following (Pseudo Code)
BACKUP DATABASE
CHECK BACKUP WORKS!
FOR EACH TABLE TO BE RE-KEYED
DROP ALL FOREIGN KEY CONSTRAINTS, INDEXES ETC FROM TABLE
SELECT ID + Number, ALL_OTHER_FIELDS INTO TEMP_TABLE FROM TABLE
RENAME TABLE OLD_TABLE
RENAME TEMP_TABLE TABLE
FOR ALL TABLES REFERENCING THIS TABLE
UPDATE FOREIGN_KEY_TABLE SET FK_ID = FK_ID + new number
END FOR
RE-APPLY FOREIGN KEY CONSTRAINTS, INDEXES ETC FROM TABLE
END FOR
Check it all still works ...
This process could be automated through DMO/SMO objects, but depending on the number of tables involved I'd say using management studio to generate scripts that can then be edited is probably quicker. After all, you only need to do this once/5 years.
Here we go with the code for SQL 2005. It's huge, it's hacky, but it will work (except in the case where you have a primary key that is a composite of two other primary keys).
If someone can re-write this with MrTelly's faster id addition (which wouldn't require building sql from a cursor for each updated row), then I'll mark that as the accepted answer. (If I don't notice the new answer, upvote this - then I'll notice :))
BEGIN TRAN
SET NOCOUNT ON;
DECLARE #newLowId INT
SET #newLowId = 1000000
DECLARE #sql VARCHAR(4000)
--**** SELECT ALL TABLES WITH IDENTITY COLUMNS ****
DECLARE tables SCROLL CURSOR
FOR
SELECT '[' + SCHEMA_NAME(schema_id) + '].[' + t.name + ']', c.name
FROM sys.identity_columns c
INNER JOIN sys.objects t
on c.object_id = t.object_id
WHERE t.type_Desc = 'USER_TABLE'
OPEN tables
DECLARE #Table VARCHAR(100)
DECLARE #IdColumn VARCHAR(100)
CREATE Table #IdTable(
id INT IDENTITY(1,1),
s CHAR(1)
)
FETCH FIRST FROM tables
INTO #Table, #IdColumn
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT('
****************** '+#Table+' ******************
')
--Reset the idtable to the 'low' id mark - remove this line if you want all records to have distinct ids across the database
DELETE FROM #IdTable
DBCC CHECKIDENT('#IdTable', RESEED, #newLowId)
--**** GENERATE COLUMN SQL (for inserts and deletes - updating identities is not allowed) ****
DECLARE tableColumns CURSOR FOR
SELECT column_name FROM information_schema.columns
WHERE '[' + table_schema + '].[' + table_name + ']' = #Table
AND column_name <> #IdColumn
OPEN tableColumns
DECLARE #columnName VARCHAR(100)
DECLARE #columns VARCHAR(4000)
SET #columns = ''
FETCH NEXT FROM tableColumns INTO #columnName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #columns = #columns + #columnName
FETCH NEXT FROM tableColumns INTO #columnName
IF ##FETCH_STATUS = 0 SET #columns = #columns + ', '
END
CLOSE tableColumns
DEALLOCATE tableColumns
--**** GENERATE FOREIGN ROW UPDATE SQL ****
DECLARE foreignkeys SCROLL CURSOR
FOR
SELECT con.name,
'[' + SCHEMA_NAME(f.schema_id) + '].[' + f.name + ']' fTable, fc.column_name ,
'[' + SCHEMA_NAME(p.schema_id) + '].[' + p.name + ']' pTable, pc.column_name
FROM sys.foreign_keys con
INNER JOIN sysforeignkeys syscon
ON con.object_id = syscon.constid
INNER JOIN sys.objects f
ON con.parent_object_id = f.object_id
INNER JOIN information_schema.columns fc
ON fc.table_schema = SCHEMA_NAME(f.schema_id)
AND fc.table_name = f.name
AND fc.ordinal_position = syscon.fkey
INNER JOIN sys.objects p
ON con.referenced_object_id = p.object_id
INNER JOIN information_schema.columns pc
ON pc.table_schema = SCHEMA_NAME(p.schema_id)
AND pc.table_name = p.name
AND pc.ordinal_position = syscon.rkey
WHERE '[' + SCHEMA_NAME(p.schema_id) + '].[' + p.name + ']' = #Table
OPEN foreignkeys
DECLARE #FKeyName VARCHAR(100)
DECLARE #FTable VARCHAR(100)
DECLARE #FColumn VARCHAR(100)
DECLARE #PTable VARCHAR(100)
DECLARE #PColumn VARCHAR(100)
--**** RE-WRITE ALL IDS IN THE TABLE ****
SET #sql='DECLARE tablerows CURSOR FOR
SELECT CAST('+#IdColumn+' AS VARCHAR) FROM '+#Table+' ORDER BY '+#IdColumn
PRINT(#sql)
exec(#sql)
OPEN tablerows
DECLARE #rowid VARCHAR(100)
DECLARE #id VARCHAR(100)
FETCH NEXT FROM tablerows INTO #rowid
WHILE ##FETCH_STATUS = 0
BEGIN
--generate new id
INSERT INTO #IdTable VALUES ('')
SELECT #id = CAST(##IDENTITY AS VARCHAR)
IF #rowId <> #Id
BEGIN
PRINT('Modifying '+#Table+': changing '+#rowId+' to '+#id)
SET #sql='SET IDENTITY_INSERT ' + #Table + ' ON
INSERT INTO '+#Table+' ('+#IdColumn+','+#columns+') SELECT '+#id+','+#columns+' FROM '+#Table+' WHERE '+#IdColumn+'='+#rowId
--Updating all foreign rows...
FETCH FIRST FROM foreignkeys
INTO #FKeyName, #FTable, #FColumn, #PTable, #PColumn
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = #sql + '
UPDATE '+#FTable+' SET '+#FColumn+'='+#id+' WHERE '+#FColumn+' ='+#rowId
FETCH NEXT FROM foreignkeys
INTO #FKeyName, #FTable, #FColumn, #PTable, #PColumn
END
SET #sql=#sql + '
DELETE FROM '+#Table+' WHERE '+#IdColumn+'='+#rowId
PRINT(#sql)
exec(#sql)
END
FETCH NEXT FROM tablerows INTO #rowid
END
CLOSE tablerows
DEALLOCATE tablerows
CLOSE foreignkeys
DEALLOCATE foreignkeys
--Revert to normal identity operation - update the identity to the latest id...
DBCC CHECKIDENT(#Table, RESEED, ##IDENTITY)
SET #sql='SET IDENTITY_INSERT ' + #Table + ' OFF'
PRINT(#sql)
exec(#sql)
FETCH NEXT FROM tables
INTO #Table, #IdColumn
END
CLOSE tables
DEALLOCATE tables
DROP TABLE #IdTable
--COMMIT
--ROLLBACK
Why don't you use negative numbers for your standard configuration values and continue to use positive numbers for other things?

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