Search database through Views - sql-server

I m trying to search database values through the views.
I m stuck at the below error.
USE AdventureWorks
GO
--EXEC Customer.sp_FindInViews Stephen, Sales
ALTER PROCEDURE Customer.sp_FindInViews #stringToFind VARCHAR(100), #schema sysname
AS
SET NOCOUNT ON
DECLARE
#ViewName AS nVarChar(128)
, #TmpQuery AS nVarChar(500)
, #Out3 as int
, #sqlCommand VARCHAR(8000)
, #where VARCHAR(8000)
, #columnName sysname
, #cursor VARCHAR(8000)
DECLARE Outer_Cursor CURSOR FOR
SELECT schema_name(schema_id)+'.'+name as "View_Name",schema_id FROM [sys].[all_views]
where schema_id in (#schema)
OPEN Cur_Views
FETCH NEXT FROM Cur_Views INTO #ViewName
WHILE ##Fetch_Status = 0
BEGIN
SET #sqlCommand = 'SELECT * FROM ' + #ViewName + ' WHERE'
SET #where = ''
DECLARE col_cursor CURSOR FOR
SELECT syscolumns.name FROM sys.sysobjects "sysobjects"
INNER JOIN sys.syscolumns "syscolumns"
on syscolumns.id = sysobjects.id
WHERE (sysobjects.type = 'V' and SCHEMA_NAME(sysobjects.uid) + '.' +sysobjects.name = #ViewName)
OPEN col_cursor
FETCH NEXT FROM col_cursor INTO #columnName
WHILE ##FETCH_STATUS = 0
BEGIN
IF #where <> ''
SET #where = #where + ' OR'
---------------------------------------------------------------------------
SET #where = #where + ' ' + #columnName + ' LIKE ''' + #stringToFind + ''''
SET #sqlCommand = #sqlCommand + #where
CREATE TABLE #Data (var varchar)
SELECT #TmpQuery = #sqlCommand
INSERT #Data exec (#TmpQuery)
SELECT #Out3 = var from #Data
PRINT #Out3
DROP TABLE #Data
FETCH NEXT FROM col_cursor INTO #columnName
END
CLOSE col_cursor
DEALLOCATE col_cursor
CLOSE Outer_Cursor
DEALLOCATE Outer_Cursor
END
GO
The code compiles , but it does give the error when executed as below :
EXEC Customer.sp_FindInViews Stephen, Sales
Msg 16915, Level 16, State 1, Procedure sp_FindInViews, Line 19
A cursor with the name 'Outer_Cursor' already exists.
Msg 16905, Level 16, State 1, Procedure sp_FindInViews, Line 22
The cursor is already open.
Msg 16924, Level 16, State 1, Procedure sp_FindInViews, Line 23
Cursorfetch: The number of variables declared in the INTO list must match that of selected columns.
I m not sure , why I m getting this error. I feel i m handling them. Any input on this , would be helpful.
Thanks.

Looks to me that you've changed cursor names. You start by declaring Outer_Cursor then open a cursor called Cur_Views.
Also when you fetch from the cursor you are only putting the cursor values in to 1 variable, in the cursor declaration you list 2 fields (View_Name and schema_id).
DECLARE Outer_Cursor CURSOR FOR
SELECT schema_name(schema_id)+'.'+name as "View_Name",schema_id FROM [sys].[all_views]
where schema_id in (#schema)
OPEN Cur_Views
FETCH NEXT FROM Cur_Views INTO #ViewName
The "cursor is already open" errors occur when you run the procedure a second time becuase the original cursors are still open (as the first attempt errored before being able to close them).

Not sure if it's the answer you've been looking for, but SQLSearch (http://www.red-gate.com/products/sql-development/sql-search/) is an excellent tool for searching databases (of course, you can set it to search views only) and it's free...

Related

Object_ID does not detect the recently created or dropped tables in SQL Server

I am having issue with working of Object_ID to detect if the table already exists.
It works fine the first iteration and allows to create the required tables properly.
But if executed again, it still thinks/sees that tables are not created and tries to create the table and then SQL Server gives the error that tables already exist.
SQL Server version 2008
Code
--Alter Proc spCreateCustomerChartTables
--As
Begin
Declare
#mycursorMARKET Cursor,
#mycursorCUSTOMER Cursor,
#MarketNameEnglish nchar(30),
#CustomerID nchar(10),
#DDate date,
#textdate as nchar(12),
#tableName nchar(100),
#sqlcmd as nvarchar(500)
Set #DDate = GETDATE()
Set #mycursorMARKET = Cursor for Select Distinct MarketNameEnglish From dbo.tableMarketName Order by MarketNameEnglish ASC
Open #mycursorMARKET
Fetch Next From #mycursorMARKET Into #MarketNameEnglish
While ##FETCH_STATUS = 0
Begin
Set #mycursorCUSTOMER = Cursor for Select Distinct CustomerID From dbo.CustomerEmployeeDetail Order by CustomerID ASC
Open #mycursorCUSTOMER
Fetch Next From #mycursorCUSTOMER Into #CustomerID
While ##FETCH_STATUS =0
Begin
Set #textdate = cast(#DDate as NCHAR(12))
Set #tableName = RTrim(#MarketNameEnglish) + '_' + RTrim(#CustomerID) + '_' + RTrim(#textdate )
If OBJECT_ID(#tableName , 'U') IS Not Null
--IF Not EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES
-- WHERE TABLE_NAME = #tableName )
Begin
Print 'Table Does Not Exist'
Set #sqlcmd = 'Select * Into ' + RTrim(#tableName) + ' From BlankChart'
Set #sqlcmd = RTRIM(#sqlcmd)
Set #sqlcmd = REPLACE (#sqlcmd, '-', '_')
Exec(#sqlcmd)
End
Else
Begin
Print 'Table Exists'
Set #sqlcmd = 'Drop Table ' + #tableName
Set #sqlcmd = RTRIM(#sqlcmd)
Set #sqlcmd = REPLACE (#sqlcmd, '-', '_')
Exec(#sqlcmd)
End
--Print #sqlcmd --Create chart tables here
Fetch Next From #mycursorCUSTOMER Into #CustomerID
End
--Print #MarketNameEnglish
Fetch Next From #mycursorMARKET Into #MarketNameEnglish
End
Close #mycursorMARKET
Deallocate #mycursorMARKET
Close #mycursorCUSTOMER
Deallocate #mycursorCUSTOMER
End
Your condition is "inverted":
your If OBJECT_ID(#tableName , 'U') IS Not Null should be changed to If OBJECT_ID(#tableName , 'U') IS Null
Finally found the mistake in my code. It had got nothing to do with Object_ID.
Actually the formating of variable #tablename was done incorrectly and at incorrect place. The dashes (-) of date in tablename were not replaced with underscore (_). This was causing the error.

SQL search across multiple columns in any order

My users are trying to find records in my SQL db by providing simple text strings like this:
SCRAP 000000152 TMB-0000000025
These values can be in any order and any may be excluded. For example, they may enter:
SCRAP
TMB-0000000025 SCRAP
000000152 SCRAP
SCRAP 000000152
TMB-0000000025 000000152
All should work and include the same record as the original search, but they may also contain additional records because fewer columns are used in the match.
Here is a sample table to use for the results:
DECLARE #search1 varchar(50) = 'SCRAP 000000152 TMB-0000000025'
DECLARE #search2 varchar(50) = 'SCRAP'
DECLARE #search3 varchar(50) = 'TMB-0000000025 SCRAP'
DECLARE #search4 varchar(50) = '000000152 SCRAP'
DECLARE #search5 varchar(50) = 'SCRAP 000000152'
DECLARE #search6 varchar(50) = 'TMB-0000000025 000000152'
DECLARE #table TABLE (WC varchar(20),WO varchar(20),PN varchar(20))
INSERT INTO #table
SELECT 'SCRAP','000000152','TMB-0000000025' UNION
SELECT 'SCRAP','000012312','121-0000121515' UNION
SELECT 'SM01','000000152','121-0000155' UNION
SELECT 'TH01','000123151','TMB-0000000025'
SELECT * FROM #table
One additional wrinkle, the user does not have to enter 000000152, they can enter 152 and it should find the same results.
I can use patindex, but it requires the users to enter the search terms in a specific order, or for me to have an exponentially larger string to compare as I try to put them in all possible arrangements.
What is the best way to do this in SQL? Or, is this outside the capabilities of SQL? It is quite possible that the table will have well over 10,000 records (for some instances even over 100,000), so the query has to be efficient.
Agree with #MitchWheat (as usual). This database is not designed for queries like that, nor would any kind of "basic query" help. Best way would be to build a list of strings appearing in any column of the database, mapped back to the source column and row, and search that lookup table for your strings. This is pretty much what Lucene and any other full-text search library will do for you. SQL has a native implementation, but if the pros say go with a third party implementation, I'd say it's worth a look-see.
You can try this SP:
USE master
GO
CREATE PROCEDURE sp_FindStringInTable #stringToFind VARCHAR(100), #schema sysname, #table sysname
AS
DECLARE #sqlCommand VARCHAR(8000)
DECLARE #where VARCHAR(8000)
DECLARE #columnName sysname
DECLARE #cursor VARCHAR(8000)
BEGIN TRY
SET #sqlCommand = 'SELECT * FROM [' + #schema + '].[' + #table + '] WHERE'
SET #where = ''
SET #cursor = 'DECLARE col_cursor CURSOR FOR SELECT COLUMN_NAME
FROM ' + DB_NAME() + '.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = ''' + #schema + '''
AND TABLE_NAME = ''' + #table + '''
AND DATA_TYPE IN (''char'',''nchar'',''ntext'',''nvarchar'',''text'',''varchar'')'
EXEC (#cursor)
OPEN col_cursor
FETCH NEXT FROM col_cursor INTO #columnName
WHILE ##FETCH_STATUS = 0
BEGIN
IF #where <> ''
SET #where = #where + ' OR'
SET #where = #where + ' [' + #columnName + '] LIKE ''' + #stringToFind + ''''
FETCH NEXT FROM col_cursor INTO #columnName
END
CLOSE col_cursor
DEALLOCATE col_cursor
SET #sqlCommand = #sqlCommand + #where
--PRINT #sqlCommand
EXEC (#sqlCommand)
END TRY
BEGIN CATCH
PRINT 'There was an error. Check to make sure object exists.'
IF CURSOR_STATUS('variable', 'col_cursor') <> -3
BEGIN
CLOSE col_cursor
DEALLOCATE col_cursor
END
END CATCH
This will have results as follow:
USE AdventureWorks
GO
EXEC sp_FindStringInTable 'Irv%', 'Person', 'Address'
USE AdventureWorks
GO
EXEC sp_FindStringInTable '%land%', 'Person', 'Address'
That's all there is to it. Once this has been created you can use this against any table and any database on your server.(Read More)

SQL Server - Variable declared but still says "Must declare the scalar variable"

I'm trying to run this set of SQL commands on Microsoft SQL Server but I am getting this error:
Msg 137, Level 15, State 1, Line 1
Must declare the scalar variable "#dbstatus".
I thought I did declare the variable so I'm not sure why it's still throwing the error?
DECLARE #dbname nvarchar(100)
DECLARE #dbstatus varchar(500)
DECLARE #sqlCommand NVARCHAR(1000)
create table #temptable (dbname nvarchar(100), status varchar(500))
DECLARE c1 CURSOR READ_ONLY
FOR
SELECT '[' + name + ']' FROM sys.databases WHERE name = 'EDDS1084543'
OPEN c1
FETCH NEXT FROM c1 INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlCommand = 'SET #dbstatus = (SELECT Status FROM ' + #dbname + '.[EDDSDBO].[dtSearchIndex])'
EXECUTE sp_executesql #sqlCommand
INSERT INTO #tempTable(dbname, [status])VALUES (#dbname, #dbstatus)
FETCH NEXT FROM c1 INTO #dbname
END
CLOSE c1
DEALLOCATE c1
EXEC/sp_executesql creates a new connection (SPID) to the SQL Server, which is not your current session, so it cannot see the variable. Check the documentation.
Basically, you have to declare the parameter you want to pass into the call, and give it a value. In this case, both have to include the OUTPUT specifier.
EXECUTE sp_executesql #sqlCommand, '#dbstatus varchar(500) output', #dbstatus output
The problem is here:
SET #sqlCommand = 'SET #dbstatus = (SELECT Status FROM ' + #dbname + '.[EDDSDBO].[dtSearchIndex])'
EXECUTE sp_executesql #sqlCommand
This causes the server to execute the value of #sqlCommand as a standalone statement. Within this statement, #dbstatus has not been declared as a variable, hence the error. This is what's getting executed:
SET #dbstatus = (SELECT Status FROM [value in #dbname].[EDDSDBO].[dtSearchIndex])
Try this instead:
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlCommand = 'SET #dbstatus = (SELECT Status FROM ' + #dbname + '.[EDDSDBO].[dtSearchIndex])'
EXECUTE sp_executesql #sqlCommand, '#dbstatus varchar(500) output', #dbstatus output
INSERT INTO #tempTable(dbname, [status])VALUES (#dbname, #dbstatus)
FETCH NEXT FROM c1
INTO #dbname
END

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

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