How to assign multiple variables without repeating a clause - sql-server

I have around 10 variables which all need to be populated during my select statement.
It's all driven by a language code, if 'english' set all variables to english, otherwise set to native language.
The issue I'm having is alot of repeat code, I'm wondering what's the best approach to populate multiple variables within a CASE.
My current code
DECLARE
#x nvarchar(200),
#y nvarchar(200),
#z nvarchar(200)
SELECT
#x = CASE WHEN #language like '%english%'
THEN
T.washroom_English
ELSE
T.washroom
END,
#y = CASE WHEN #language like '%english%'
THEN
T.bed_English
ELSE
T.bed
END,
#z = CASE WHEN #language like '%english%'
THEN
T.kitchen_English
ELSE
T.kithen
END
FROM house as T

You can use a query wich will generate rows by language (english or not english) according to your #language variable.
The UNION ALL result will have the columns name same as the upper query.
Then you can assign your variables with a static column name from the subquery.
SELECT #x = washroom
, #y = bed
, #z = kitchen
FROM ( SELECT T.washroom
, T.bed
, T.kitchen
FROM house AS T
WHERE #language NOT LIKE '%english%'
UNION ALL
SELECT T.washroom_English
, T.bed_English
, T.kitchen_English
FROM house AS T
WHERE #language LIKE '%english%'
) data

Try my little trick
DECLARE #English NVARCHAR(10) = '_English'
DECLARE #Fields NVARCHAR(500) = 'washroom,bed,kithen,'
DECLARE #TableName NVARCHAR(50) = 'house'
DECLARE #ColumnValue NVARCHAR(100)
DECLARE #Index INT
DECLARE #SelectString NVARCHAR(4000) = 'SELECT '
WHILE CHARINDEX(',', #Fields) > 0
BEGIN
SELECT #Index = CHARINDEX(',', #Fields)
SELECT #ColumnValue = SUBSTRING(#Fields, 1, #Index-1)
SET #SelectString = #SelectString + '''' + #ColumnValue + #English +'''As ' + #ColumnValue + ', '
SELECT #Fields = SUBSTRING(#Fields, #Index + 1, LEN(#Fields) - #Index)
END
SELECT #SelectString = SUBSTRING(#SelectString,0, LEN(#SelectString)) + ' From ' + #TableName
SELECT #SelectString
EXEc sp_sqlexec #SelectString

Don't know if I understood you correctly, but my proposition is:
DECLARE
#x nvarchar(200),
#y nvarchar(200),
#z nvarchar(200)
IF #language like '%english%'
SELECT #x = T.washroom_English, #y = T.bed_English, #z = T.kitchen_English FROM house as T
ELSE
SELECT #x = T.washroom, #y = T.bed, #z = T.kitchen FROM house as T

Related

loop to add value in dynamic OR statement

I broke this query down to the most basic. I need to add an OR statement dynamically, which includes a variable. I need to get any id and its corresponding id with an underscore. So, my resulting #SQL to execute would be:
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
--
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
SET #SQL = #SQL + ' AND OrigID in (''' + #OriginId + ''') '
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = '_%'
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10))) + #Origin
SET #SQL_2 = N' OR OrigID LIKE ''' + #Origin + ''' '
SET #SQL_2 = #SQL + #SQL_2
print(#SQL_2)
SET #counter = #counter + 1
END
EXEC sp_executesql #SQL_2,#ParamDefinition,#OrganizationId,#OriginId
drop table #inVars
drop table #Test
Here is how my query is executing now:
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '31_%'
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '33_%'
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '25_%'
This is my desired result:
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '31_%'
OR OrigID LIKE '33_%'
OR OrigID LIKE '25_%'
A few problems: You can't concatenate a NULL with a string EVER; the result is always NULL (please look at the IF #Origin IS NOT NULL line). In your loop, you should be updating #SQL, not #SQL_2. Lastly, you should wrap ORs in parens so the logic is always explicit.
SET NOCOUNT ON
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
SET #SQL = #SQL + ' AND (OrigID in (''' + #OriginId + ''') '
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = '_%'
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10))) + #Origin
IF #Origin IS NOT NULL
BEGIN
SET #SQL_2 = N' OR OrigID LIKE ''' + #Origin + ''' '
SET #SQL = #SQL + #SQL_2
END
SET #counter = #counter + 1
END
SET #SQL=#SQL+')'
print #SQL
drop table #inVars
drop table #Test
It is not very clear what you want here but I think you are making it harder on yourself than you need to. There is no need to use the IN because you are also finding all values that begin with the same value. And you have hard coded the same values into your temp table. Using a string splitter this is about a million times less complicated. Just split your #OriginID on the commas and use LIKE in the join.
I am using the DelimitedSplit8k which you can find here
I am pretty sure this should get you the information you are looking for. I would recommend avoiding loops whenever possible.
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
select *
from #Test t
join DelimitedSplit8K(#OriginID, ',') x on t.OrigID like x.Item + '%'
drop table #Test
I solved this.Thanks all who replied.
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
BEGIN
SET #SQL = #SQL +' AND (OrigID in (''' + #OriginId + ''')) '
END
IF ISNULL(#OriginId,'') <> ''
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10)))
SET #Origin = #Origin+'_%'
SET #SQL_2 = N' OR (OrigID LIKE ''' + #Origin + ''') '
SET #SQL = #SQL + #SQL_2
SET #counter = #counter + 1
END
print(#SQL)
EXEC sp_executesql #SQL,#ParamDefinition,#OrganizationId,#OriginId
drop table #inVars
drop table #Test

SQL Server : dynamic query

I have a SQL Server 2008 with a table that acts like a hash-map. basically, there's three columns (id, key, val) and I need to pull the other columns a, b, c, d, e.
The purpose is to basically choose the database I need to query data from. Similar to this issue Using the correct database
I have got the SQL using a brute force method. I'm just trying do this in a better, more efficient way
Here's the SQL I'm trying to get to work:
CREATE PROCEDURE [dbo].[me]
#partitionName VARCHAR(64),
#id INT
AS
BEGIN
SET NOCOUNT ON
SET ROWCOUNT 0
DECLARE #table as varchar(128)
DECLARE #sql as nvarchar(4000)
DECLARE #params as nvarchar(4000)
DECLARE #s_key as varchar(64)
DECLARE #paramDefinition as nvarchar(4000)
DECLARE #a INT
DECLARE #b VARCHAR(32)
DECLARE #c VARCHAR(32)
DECLARE #d VARCHAR(32)
DECLARE #e VARCHAR(32)
SET #table = #partitionName + '.dbo.hash_table'
SET #sql =
N'SELECT ' +
N' #a = MAX(CASE WHEN [key] = ''a'' THEN value ELSE '''' END),
#b = MAX(CASE WHEN [key] = ''b'' THEN value ELSE '''' END),
#c = MAX(CASE WHEN [key] = ''c'' THEN value ELSE '''' END),
#d = MAX(CASE WHEN [key] = ''d'' THEN value ELSE '''' END),
#e = MAX(CASE WHEN [key] = ''e'' THEN value ELSE '''' END)
FROM ' + #table +
N'WHERE id = ' + CONVERT(VARCHAR(3), #id)
EXEC sp_executesql #sql
But, this gives the following error
Must declare the scalar variable "#a"
I have a feeling I need to do something like pass in #paramsDefinition to sp_executesql
But so far, these have failed
SET #paramDefinition = '#a INT OUTPUT, '
+ ' #b varchar(32) OUTPUT, '
+ ' #c varchar(32) OUTPUT, '
+ ' #d varchar(32) OUTPUT,'
+ ' #r varchar(32) OUTPUT'
...
EXEC sp_executesql #sql, #paramDefintions
I get
Incorrect syntax near '='.
Here is the brute force method (which works but hits the DB 5 times)
SET #key = 'a'
SET #sql =
N' SELECT #a = val FROM ' + #table +
N' WHERE key = ' + quotename(#key, '''') +
N' AND id = ' + CONVERT(VARCHAR(3), #nid)
EXEC sp_executesql #sql, N'#a varchar(32) OUTPUT', #a = #a OUTPUT
SET #key = 'b'
SET #sql =
N' SELECT #b = val FROM ' + #table +
N' WHERE key = ' + quotename(#key, '''') +
N' AND id = ' + CONVERT(VARCHAR(3), #id)
EXEC sp_executesql #sql, N'#b varchar(32) OUTPUT', #b = #b OUTPUT
SET #key = 'c'
SET #sql =
N' SELECT #c = val FROM ' + #table +
N' WHERE key = ' + quotename(#key, '''') +
N' AND id = ' + CONVERT(VARCHAR(3), #id)
EXEC sp_executesql #sql, N'#c varchar(32) OUTPUT', #c = #c OUTPUT
SET #key = 'd'
SET #sql =
N' SELECT #d = val FROM ' + #table +
N' WHERE key = ' + quotename(#key, '''') +
N' AND id = ' + CONVERT(VARCHAR(3), #id)
EXEC sp_executesql #sql, N'#d varchar(32) OUTPUT', #d = #d OUTPUT
SET #key = 'e'
SET #sql =
N' SELECT #e = val FROM ' + #table +
N' WHERE key = ' + quotename(#key, '''') +
N' AND id = ' + CONVERT(VARCHAR(3), #id)
EXEC sp_executesql #sql, N'#e varchar(32) OUTPUT', #e = #e OUTPUT
SELECT #a as [a], #b as [b], #c as [c], #d as [d], #r as [r]
You can try to use a temporary table like this:
CREATE PROCEDURE [dbo].[me]
#partitionName VARCHAR(64),
#id INT
AS
BEGIN
SET NOCOUNT ON
SET ROWCOUNT 0
DECLARE #table as varchar(128)
DECLARE #sql as nvarchar(4000)
DECLARE #params as nvarchar(4000)
DECLARE #s_key as varchar(64)
DECLARE #paramDefinition as nvarchar(4000)
DECLARE #a INT
DECLARE #b VARCHAR(32)
DECLARE #c VARCHAR(32)
DECLARE #d VARCHAR(32)
DECLARE #e VARCHAR(32)
SET #table = #partitionName + '.dbo.hash_table'
CREATE TABLE #tmp (code varchar(50))
SET #sql =
N'SELECT ' +
N' MAX(CASE WHEN [key] = ''a'' THEN value ELSE '''' END) as [a],
MAX(CASE WHEN [key] = ''b'' THEN value ELSE '''' END) as [b],
MAX(CASE WHEN [key] = ''c'' THEN value ELSE '''' END) as [c],
MAX(CASE WHEN [key] = ''d'' THEN value ELSE '''' END) as [d],
MAX(CASE WHEN [key] = ''e'' THEN value ELSE '''' END) as [e]
FROM ' + #table +
N'WHERE id = ' + CONVERT(VARCHAR(3), #id)
INSERT INTO #tmp (code)
EXEC sp_executesql #sql
SELECT * from #tmp
Hope it helps.
Try this.....
Dynamic SQL has its own scope, Variables in your stored procedure arent visible to to your dynamic sql, you will need to declare these variables as second parameter to sp_execuetsql and since you are reverting values back in these variables, you will need to use key word OUTPUT with these variables when passing them to sp_executesql , as follows
CREATE PROCEDURE [dbo].[me]
#partitionName SYSNAME,
#id INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #table as varchar(128)
DECLARE #sql as nvarchar(4000)
DECLARE #params as nvarchar(4000)
DECLARE #s_key as varchar(64)
DECLARE #paramDefinition as nvarchar(4000)
DECLARE #a INT
DECLARE #b VARCHAR(32)
DECLARE #c VARCHAR(32)
DECLARE #d VARCHAR(32)
DECLARE #e VARCHAR(32)
SET #table = #partitionName + 'hash_table'
SET #sql = N'SELECT ' +
N' #a = MAX(CASE WHEN [key] = ''a'' THEN value ELSE '''' END),
#b = MAX(CASE WHEN [key] = ''b'' THEN value ELSE '''' END),
#c = MAX(CASE WHEN [key] = ''c'' THEN value ELSE '''' END),
#d = MAX(CASE WHEN [key] = ''d'' THEN value ELSE '''' END),
#e = MAX(CASE WHEN [key] = ''e'' THEN value ELSE '''' END)
FROM dbo.' + QUOTENAME(#table) +
N' WHERE id = #id)'
EXEC sp_executesql #sql
,N'#a INT OUTPUT, #b VARCHAR(32) OUTPUT,#b VARCHAR(32) OUTPUT,#c VARCHAR(32) OUTPUT,
#d VARCHAR(32) OUTPUT,#e VARCHAR(32) OUTPUT, #id INT'
,#a OUTPUT
,#b OUTPUT
,#c OUTPUT
,#d OUTPUT
,#e OUTPUT
,#id
END

Transform text in SQL Server

I am trying to create a dynamic query in SQL Server.
Input: #value= abc,def,en,
Output: MAX(abc) as abc, MAX(def) as def, MAX(en) as en
My efforts so far took me no where.
With CONVERT() and REPLACE() I achieved a bit but finding it difficult. Need help!
Try this:
declare #value varchar(50) = 'abc,def,en'
declare #result varchar(100) = ''
select #result = replace(#value,'abc', 'MAX(''abc'') as abc')
select #result = replace(#result,'def', 'MAX(''def'') as def')
select #result = replace(#result,'en', 'MAX(''en'') as en')
select #result
You can also do the replacements in one line by nesting the expressions.
EDIT: If you have variable values in #value, you can take the below approach:
Use a splitter function to get the individual values in the string as a list. You can take a look at this article for implementations.
Insert this list to a temp table.
Update the temp table as shown above.
Concatenate the values into a single string using STUFF like so:
select stuff((select ',' + val from #temp for xml path('')),1,1,'')
Try this:
DECLARE #Value VARCHAR(200) = 'abc,def,en'
DECLARE #Template VARCHAR(100) = 'MAX(''##'') as ##'
DECLARE #Result VARCHAR(1000) = ''
DECLARE #Data VARCHAR(100) = ''
WHILE LEN(#Value) > 0
BEGIN
SET #Data = REPLACE(LEFT(#Value, ISNULL(NULLIF(CHARINDEX(',', #Value),0), LEN(#Value))),',','')
SET #Result = #Result + REPLACE(#Template, '##', #Data)
IF CHARINDEX(',', #Value) > 0
BEGIN
SET #Result = #Result + ','
SET #Value = REPLACE(#Value,#Data + ',','')
END
ELSE
SET #Value = REPLACE(#Value,#Data,'')
END
SELECT #Result
Have a look at SQL User Defined Function to Parse a Delimited String
So you can do like
Declare #Value varchar(200) = 'abc,def,en'
Declare #Item varchar(20) = null
declare #Str varchar(1000)=''
WHILE LEN(#Value) > 0
BEGIN
IF PATINDEX('%,%',#Value) > 0
BEGIN
SET #Item = SUBSTRING(#Value, 0, PATINDEX('%,%',#Value))
-- SELECT #Item
IF(LEN(#Str)>0)
SET #Str = #Str + ', SELECT MAX('+#Item+') as ' +#Item
ELSE
SET#Str = #Str + ' SELECT MAX('+#Item+') as ' +#Item
SET #Value = SUBSTRING(#Value, LEN(#Item + ',') + 1, LEN(#Value))
END
ELSE
BEGIN
SET #Item = #Value
SET #Value = NULL
SET #Str = #Str + 'SELECT MAX('+#Item+') as ' + #Item
END
END
select #Str
See the fiddle sample here

Find column names in executed query sql server

I have a table that stores SQL queries. I retrieve a query according to a condition and store it in a variable:
---------------------------------------------------------
ID | Query
---------------------------------------------------------
1 | 'Select Id,Name from Student'
2 | 'Select Id,Name,Father_Name from Student'
3 | 'Select Id,Name,Email from Student_Detail'
....
---------------------------------------------------------
For example, a variable #sql might have the first query from above:
Declare #sql nvarchar(500)
set #sql = 'Select Id,Name from Student'
I execute this query using:
Exec(#sql)
The problem is, how do I know which columns are used in that query? I'm trying to achieve something like what ColdFusion does with query.ColumnList, which returns the column list used in that query.
Try this:
SELECT SUBSTRING(query,8,CHARINDEX('from',query)-9) AS ColumnList
FROM YourTable
this is a variant of mehdi lotfi solution but is equally weak in the sense that only gives you whatever is in between the select and from statements so if you have aliases or calculations or 'case' statements it will not work properly; it does work if the column list is straight forward comma separated columns:
SELECT LEFT(REPLACE(#SQL,'Select ',''), CHARINDEX(' from',REPLACE(#SQL,'Select ',''))) AS ColumnList
Finally i managed to solve at my own using this solution.
Declare #sql varchar(1000)
Declare #valueList nvarchar(500)
Declare #tbl Table(Name varchar(100))
Declare #selectPos Int
Declare #fromPos Int
Declare #len Int
Declare #pos Int
Declare #prevpos Int
Declare #Delimeter varchar(2)
set #sql = 'Select Id,Name,Father_Name from Student'
set #selectPos = CHARINDEX('Select ', #sql, 1)+7
set #fromPos = CHARINDEX('From ', #sql, 1)
set #len = #fromPos - #selectPos
set #valueList = SUBSTRING(#sql, #selectPos, #len)
set #Delimeter = ', '
set #pos = 1
set #prevpos = 0
while #pos > 0
Begin
set #pos = charIndex(#Delimeter, #valueList, #pos)
If #pos = 0
Begin
Insert into #tbl
Select SUBSTRING(#valueList,#prevPos + 1,LEN(#valueList) - #prevpos)
Break;
End
Insert into #tbl
Select SUBSTRING(#valueList,#prevPos + 1,#pos-#prevpos - 1)
set #prevpos = #pos
set #pos = #pos + 1
End
select * from #tbl

Want to check fields for data fast

We have a database setup that consists of two parts: a static structure, and dynamic additions. For each database, the dynamic can be different, and sometimes we don't have data for all the dynamic fields. Rigt now, we check for empties by looking at the total count of records in the entire table, but we want to move to a more refined method of checking for empties if possible. Is it possible to quickly check through several hundred fields and see which ones are empty and which ones are populated?
For searching for any rows that have NULLS in any column you can do this, first create this proc which is based on the code here Search all columns in all the tables in a database for a specific value
CREATE PROCEDURE FindMyData_StringNull
#DataToFind NVARCHAR(4000),
#ExactMatch BIT = 0
AS
SET NOCOUNT ON
DECLARE #Temp TABLE(RowId INT IDENTITY(1,1), SchemaName sysname, TableName sysname, ColumnName SysName, DataType VARCHAR(100), DataFound BIT)
INSERT INTO #Temp(TableName,SchemaName, ColumnName, DataType)
SELECT C.Table_Name,C.TABLE_SCHEMA, C.Column_Name, C.Data_Type
FROM Information_Schema.Columns AS C
INNER Join Information_Schema.Tables AS T
ON C.Table_Name = T.Table_Name
AND C.TABLE_SCHEMA = T.TABLE_SCHEMA
WHERE Table_Type = 'Base Table'
DECLARE #i INT
DECLARE #MAX INT
DECLARE #TableName sysname
DECLARE #ColumnName sysname
DECLARE #SchemaName sysname
DECLARE #SQL NVARCHAR(4000)
DECLARE #PARAMETERS NVARCHAR(4000)
DECLARE #DataExists BIT
DECLARE #SQLTemplate NVARCHAR(4000)
SELECT #SQLTemplate = 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
IS NULL
)
Set #DataExists = 1
Else
Set #DataExists = 0'
,
#PARAMETERS = '#DataExists Bit OUTPUT',
#i = 1
SELECT #i = 1, #MAX = MAX(RowId)
FROM #Temp
WHILE #i <= #MAX
BEGIN
SELECT #SQL = REPLACE(REPLACE(#SQLTemplate, 'ReplaceTableName', QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)), 'ReplaceColumnName', ColumnName)
FROM #Temp
WHERE RowId = #i
PRINT #SQL
EXEC SP_EXECUTESQL #SQL, #PARAMETERS, #DataExists = #DataExists OUTPUT
IF #DataExists =1
UPDATE #Temp SET DataFound = 1 WHERE RowId = #i
SET #i = #i + 1
END
SELECT SchemaName,TableName, ColumnName
FROM #Temp
WHERE DataFound = 1
Call it like this
FindMyData_StringNull NULL,1
Assuming that you are just checking for whether or not there are any non-NULL values in the column, using EXISTS should generally be faster than getting a COUNT(*). The COUNT needs to scan the whole table to come up with the correct number. EXISTS just needs to find one row that satisfies the condition before it stops looking.
If the whole column is NULL then the time will be about the same, but in all of those cases where you have values it could be substantially shorter.
From Search all columns in all the tables in a database for a specific value
first create this function
CREATE PROCEDURE FindMyData_String
#DataToFind NVARCHAR(4000),
#ExactMatch BIT = 0
AS
SET NOCOUNT ON
DECLARE #Temp TABLE(RowId INT IDENTITY(1,1), SchemaName sysname, TableName sysname, ColumnName SysName, DataType VARCHAR(100), DataFound BIT)
INSERT INTO #Temp(TableName,SchemaName, ColumnName, DataType)
SELECT C.Table_Name,C.TABLE_SCHEMA, C.Column_Name, C.Data_Type
FROM Information_Schema.Columns AS C
INNER Join Information_Schema.Tables AS T
ON C.Table_Name = T.Table_Name
AND C.TABLE_SCHEMA = T.TABLE_SCHEMA
WHERE Table_Type = 'Base Table'
And Data_Type In ('ntext','text','nvarchar','nchar','varchar','char')
DECLARE #i INT
DECLARE #MAX INT
DECLARE #TableName sysname
DECLARE #ColumnName sysname
DECLARE #SchemaName sysname
DECLARE #SQL NVARCHAR(4000)
DECLARE #PARAMETERS NVARCHAR(4000)
DECLARE #DataExists BIT
DECLARE #SQLTemplate NVARCHAR(4000)
SELECT #SQLTemplate = CASE WHEN #ExactMatch = 1
THEN 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
= ''' + #DataToFind + '''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
ELSE 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
Like ''%' + #DataToFind + '%''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
END,
#PARAMETERS = '#DataExists Bit OUTPUT',
#i = 1
SELECT #i = 1, #MAX = MAX(RowId)
FROM #Temp
WHILE #i <= #MAX
BEGIN
SELECT #SQL = REPLACE(REPLACE(#SQLTemplate, 'ReplaceTableName', QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)), 'ReplaceColumnName', ColumnName)
FROM #Temp
WHERE RowId = #i
PRINT #SQL
EXEC SP_EXECUTESQL #SQL, #PARAMETERS, #DataExists = #DataExists OUTPUT
IF #DataExists =1
UPDATE #Temp SET DataFound = 1 WHERE RowId = #i
SET #i = #i + 1
END
SELECT SchemaName,TableName, ColumnName
FROM #Temp
WHERE DataFound = 1
Now call it like this for rows with empty strings in any string type columns
exec FindMyData_String '',1
it will give you an output with column name, table name and schema name
Just keep in mind that it will search all tables
I would think the simplest solution is to use the CHECKSUM function. First you would want to determine the checksum on an empty row and then compare that to the other rows.
Select Checksum(*)
From Table
The catch with using * here is that it will include the PK. You would likely have to specify the individual columns excluding the PK to get an accurate read. So something like:
Select Checksum(Col1, Col2, Col3)
From Table
Checksum Function.

Resources