I would like to know, how to include a variable as a part of a SQL statement, to clarify more about my question, here is the code
declare #PartNo as nvarchar(20)
declare #PPFno as nvarchar(20)
declare #Dimension as nvarchar(30)
declare #cursor CURSOR
declare #colname as nvarchar(30)
declare #top as integer
declare #query as nvarchar(MAX)
declare #categoryid NVARCHAR(MAX)
set #cursor = CURSOR FOR
(select [Name] from sys.columns where object_id = (select object_id from sys.tables where name = 'ProductProperty') and [Name] like 'T%' and [name] <> 'TEMP')order by [Name] asc
OPEN #cursor
FETCH NEXT
FROM #cursor INTO #colname
WHILE ##FETCH_STATUS = 0
BEGIN
--set #query = (select #colname from ProductProperty where PartNo = #PartNo and PPFNo = #PPFno )
--set #query = 'select distinct '+#colname+' from ProductProperty where PartNo = '''+#PartNo+''' and PPFNo = '''+#PPFno+''' and DName = '''+#Dimension+''''
BEGIN
EXEC sp_executesql N'set #categoryid = (select distinct #colname from ProductProperty where PartNo = #PartNo and PPFNo = #PPFno and DName = #Dimension)',
N'#colname nvarchar(30), #PartNo nvarchar(20), #PPFno nvarchar(20),#Dimension nvarchar(30), #categoryid NVARCHAR(MAX) OUTPUT', #colname,#PartNo, #PPFno,#Dimension, #categoryid OUTPUT
select #categoryid,#colname ,#PartNo
END
--end
FETCH NEXT
FROM #cursor INTO #colName
END
CLOSE #cursor
DEALLOCATE #cursor
Please do take note I did not included the variable types. I would just want to know how can #colname become part of the SQL Statement.
To Elaborate more. Using this code, I am receiving this data
Where T1 is the table name. I want to create a query where I could pass table names into a variable, then retrieve the contents of that query.
So the SQL Query should look like this:
select T1 from ProductProperty
But I am not receiving the query, instead, I am receiving the variable data, which is in the screenshot above.
The problem is, if you might notice in my code, I have the variable #categoryid as a output parameter. This is to check the contents of the query.
it seems like I am producing a query which looks like this
select 'T1' from ProductProperty
May I ask, what am I doing wrong? If you would want additional information, please do tell me.
EDIT:
completed the query for more clarification
The issue here is that you are telling it to select the value of the #colname variable itself as the first value in your query, not the value of the column name stored in the variable. This is the equivalent of doing:
SELECT #colname;
What you need to do is output the value of the #colname variable into the SQL string you are passing to sp_executesql. As long as the #colname variable isn't entered by the user, you can concatenate it into the string passed to sp_executesql, as follows:
DECLARE #SqlQuery NVARCHAR(MAX);
SET #SqlQuery = N'set #categoryid = (select distinct ' + #colname + ' from ProductProperty
where PartNo = #PartNo and PPFNo = #PPFno and DName = #Dimension)';
EXEC sp_executesql #SqlQuery,
#PartNo nvarchar(20), #PPFno nvarchar(20),#Dimension
nvarchar(30), #categoryid NVARCHAR(MAX) OUTPUT', #PartNo, #PPFno,#Dimension,
#categoryid OUTPUT
select #categoryid, #colname, #PartNo
That will effectively give you:
EXEC sp_executesql N'set #categoryid = (select distinct T1 from ProductProperty
where PartNo = #PartNo and PPFNo = #PPFno and DName = #Dimension)',
#PartNo nvarchar(20), #PPFno nvarchar(20),#Dimension
nvarchar(30), #categoryid NVARCHAR(MAX) OUTPUT', #PartNo, #PPFno,#Dimension,
#categoryid OUTPUT
Related
declare #tab_name varchar(100)
declare #col_name varchar(100)
declare #sqlquery nvarchar(max)
declare cursor_table cursor
for
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES --where table_name!='tab'
open cursor_table
fetch next from cursor_table into #tab_name
while ##fetch_status = 0
begin
declare cursor_count cursor
for
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #tab_name
open cursor_count
fetch next from cursor_count into #col_name
while ##FETCH_STATUS =0
begin
set #sqlquery='
select '+''''+#tab_name+''''+','+''''+ #col_name+''''+',count('+#col_name+') as count from '+#tab_name+' where ISNULL('+#col_name+','''') !='''' '
print #sqlquery
exec sp_executesql #sqlquery
fetch next from cursor_count into #col_name
End
CLOSE cursor_count
DEALLOCATE cursor_count
print #tab_name
fetch next from cursor_table into #tab_name
end
CLOSE cursor_table
DEALLOCATE cursor_table
I would approach it this way if I "needed" to get a count of all null values per column, per table.
This is very inefficient query and may take a while to execute as you are bound to perform multiple full table scans for all non-indexed fields. I would advise, for this exercise, that you limit it to a few tables.
SELECT CommandOrder=1,'DECLARE #TEMP TABLE(TableName NVARCHAR(100), ColumnName NVARCHAR(100), NullRecordCount INT)'
UNION
SELECT CommandOrder=3,
'INSERT #TEMP SELECT '''+S.Name+'.'+T.Name+''','''+C.Name+''', COUNT(*) FROM '+S.Name+'.'+T.Name+' WHERE COALESCE('+C.Name+',NULL)=NULL'
FROM
SYS.Columns C
INNER JOIN SYS.Tables T ON C.object_id = T.object_id
INNER JOIN SYS.Schemas S ON T.schema_id = S.schema_id
UNION
SELECT CommandOrder=4,'SELECT * FROM #TEMP T WHERE NullRecordCount > 0 ORDER BY TableName,ColumnName'
If it is a requirement to minimize it to one cursor at the very least, use this.
If you really have to use cursors, use FAST_FORWARD cursor option.
declare #tab_name varchar(100)
declare #col_name varchar(100)
declare #sqlquery nvarchar(max)
DECLARE #mainTable TABLE(
Id INT IDENTITY(1,1) PRIMARY KEY,
TABLE_NAME Varchar(500)
)
--GET TABLES data into main table
INSERT INTO #mainTable
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
DECLARE #startTables INT = 1
DECLARE #finalTables INT = 0
SELECT #finalTables = MAX(Id) FROM #mainTable
-- Do a while loop over id
WHILE #startTables <= #finalTables
BEGIN
-- Get the table name
SELECT #tab_name = TABLE_NAME FROM #mainTable WHERE Id = #startTables
-- Initialize cursor
declare cursor_count cursor
for
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #tab_name
open cursor_count
fetch next from cursor_count into #col_name
while ##FETCH_STATUS =0
begin
set #sqlquery='select '+''''+#tab_name+''''+','+''''+ #col_name+''''+',count('+#col_name+') as count from '+#tab_name+' where ISNULL('+#col_name+','''') !='''' '
print #sqlquery
exec sp_executesql #sqlquery
fetch next from cursor_count into #col_name
End
CLOSE cursor_count
DEALLOCATE cursor_count
print #tab_name
SET #startTables = #startTables + 1
END
To use no cursor at all, use this.
declare #tab_name varchar(100)
declare #col_name varchar(100)
declare #sqlquery nvarchar(max)
-- Table stores Id, table name, Query in one go.
DECLARE #secondaryTable TABLE(
Id INT IDENTITY(1,1) PRIMARY KEY,
TABLE_NAME Varchar(500),
Query Varchar(8000)
)
INSERT INTO #secondaryTable
SELECT a.TABLE_NAME, 'select '+''''+a.TABLE_NAME+''''+','+''''+ b.COLUMN_NAME+''''+',count('+b.COLUMN_NAME+') as count from '+a.TABLE_NAME+' where ISNULL('+b.COLUMN_NAME+','''') !='''' '
FROM INFORMATION_SCHEMA.TABLES a INNER JOIN INFORMATION_SCHEMA.COLUMNS b ON a.TABLE_NAME = b.TABLE_NAME
--SELECT * FROM #secondaryTable
DECLARE #startTables INT = 1
DECLARE #finalTables INT = 0
SELECT #finalTables = MAX(Id) FROM #secondaryTable
-- Loop through the table, get the table name and query. Execute the query.
WHILE #startTables <= #finalTables
BEGIN
SELECT #tab_name = TABLE_NAME, #sqlquery = Query FROM #secondaryTable WHERE Id = #startTables
print #sqlquery
exec sp_executesql #sqlquery
print #tab_name
SET #startTables = #startTables + 1
END
I would like to add the following stored procedure to all existing databases which contain the table schichten. All my approaches have failed so I'm looking for help here.
This is my approach:
IF object_id('tempdb.dbo.#database') is not null
drop TABLE #database
GO
CREATE TABLE #database(id INT identity primary key, name sysname)
GO
SET NOCOUNT ON
INSERT INTO #database(name)
SELECT name
FROM sys.databases
WHERE source_database_id is null
ORDER BY name
SELECT * FROM #database
DECLARE #id INT, #cnt INT, #sql NVARCHAR(MAX), #currentDb SYSNAME;
SELECT #id = 1, #cnt = max(id) FROM #database
WHILE #id <= #cnt
BEGIN
BEGIN TRY
SELECT #currentDb = name
FROM #database
WHERE id = #id
IF OBJECT_ID(#currentDb+'.dbo.schichten') IS NOT NULL
CREATE PROCEDURE #currentDb.[dbo].[Ausw_Tabelle_Taxi_Pers_Jahr]
#ColumnName nvarchar(MAX),
#Selector nvarchar(MAX),
#Gesamtergebnis nvarchar(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql1 AS NVARCHAR(MAX),
#ASSelector nvarchar(MAX),
#IFPers nvarchar(MAX);
IF #Selector = 'konz'
BEGIN
SET #ASSelector = 'Taxi'
SET #IFPers=''
END
ELSE
BEGIN
SET #ASSelector = 'Personal'
SET #IFPers = '[name] AS Name,'
END
SET #sql1 = N';WITH temp AS (SELECT *
FROM (
SELECT
ISNULL((DATENAME(m,[datum])+ cast(datepart(yyyy,[datum]) as varchar(5))),0) AS MONTHYEAR,
ISNULL(['+ #Selector +'],0) AS '+ #ASSelector +','+ #IFPers +'
ISNULL((ISNULL([umsum],0) +
ISNULL([sonst_0],0) +
ISNULL([sonst_7],0) +
ISNULL([sonst_16],0) +
ISNULL([sonst_z],0) -
ISNULL([ff],0)),0) AS UMSATZSUMME
FROM [dbo].[schichten]
) AS SOURCE
PIVOT (SUM([UMSATZSUMME]) FOR [MONTHYEAR] IN ('+ #ColumnName + N' )) AS UMSAETZE )
SELECT *, '+ #Gesamtergebnis +' AS Gesamtergebnis FROM temp ORDER BY '+ #ASSelector +''
EXEC sp_executesql #sql
END
END TRY
BEGIN CATCH
END CATCH
SET #id = #id + 1;
END
GO
I am hoping that there is someone who can help me.
You have to execute the create procedure separately, so if you wrap it up into a variable and use exec sp_executesql it should work.
IF object_id('tempdb.dbo.#database') is not null
drop TABLE #database
GO
CREATE TABLE #database(id INT identity primary key, name sysname)
GO
SET NOCOUNT ON
INSERT INTO #database(name)
SELECT name
FROM sys.databases
WHERE source_database_id is null
ORDER BY name
SELECT * FROM #database
DECLARE #id INT, #cnt INT, #sql NVARCHAR(MAX), #currentDb SYSNAME;
SELECT #id = 1, #cnt = max(id) FROM #database
WHILE #id <= #cnt
BEGIN
BEGIN TRY
SELECT #currentDb = name
FROM #database
WHERE id = #id
IF OBJECT_ID(#currentDb+'.dbo.schichten') IS NOT NULL
begin
set #sql = 'CREATE PROCEDURE '+#currentDb+'.[dbo].[Ausw_Tabelle_Taxi_Pers_Jahr]
#ColumnName nvarchar(MAX),
#Selector nvarchar(MAX),
#Gesamtergebnis nvarchar(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql1 AS NVARCHAR(MAX),
#ASSelector nvarchar(MAX),
#IFPers nvarchar(MAX);
IF #Selector = ''konz''
BEGIN
SET #ASSelector = ''Taxi''
SET #IFPers=''''
END
ELSE
BEGIN
SET #ASSelector = ''Personal''
SET #IFPers = ''[name] AS Name,''
END
SET #sql1 = N'';WITH temp AS (SELECT *
FROM (
SELECT
ISNULL((DATENAME(m,[datum])+ cast(datepart(yyyy,[datum]) as varchar(5))),0) AS MONTHYEAR,
ISNULL([''+ #Selector +''],0) AS ''+ #ASSelector +'',''+ #IFPers +''
ISNULL((ISNULL([umsum],0) +
ISNULL([sonst_0],0) +
ISNULL([sonst_7],0) +
ISNULL([sonst_16],0) +
ISNULL([sonst_z],0) -
ISNULL([ff],0)),0) AS UMSATZSUMME
FROM [dbo].[schichten]
) AS SOURCE
PIVOT (SUM([UMSATZSUMME]) FOR [MONTHYEAR] IN (''+ #ColumnName + N'' )) AS UMSAETZE )
SELECT *, ''+ #Gesamtergebnis +'' AS Gesamtergebnis FROM temp ORDER BY ''+ #ASSelector +''''
EXEC sp_executesql #sql1
END'
EXEC sp_executesql #sql
END TRY
BEGIN CATCH
END CATCH
SET #id = #id + 1;
END
GO
Assuming this is a one time need as opposed to a nightly maintenance task, you can use a built-in stored procedure, sys.sp_MSforeachdb, to execute a statement in each database. It is safe to use and has been discussed extensively on the web. However, it is an undocumented feature and can be removed without notice by Microsoft so you don't want to depend on it for recurring tasks.
Create and validate your statement in one database, then use this stored procedure to execute it in all of the databases. ? is the placeholder for the database name.
EXEC sys.sp_MSforeachdb #command1 =
'IF OBJECT_ID(''?.dbo.schichten'') IS NOT NULL
AND OBJECT_id(''?.[dbo].[Ausw_Tabelle_Taxi_Pers_Jahr]'') IS NOT NULL
BEGIN
CREATE PROCEDURE ?.[dbo].[Ausw_Tabelle_Taxi_Pers_Jahr]
#ColumnName nvarchar(MAX),
#Selector nvarchar(MAX),
#Gesamtergebnis nvarchar(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql1 AS NVARCHAR(MAX),
#ASSelector nvarchar(MAX),
#IFPers nvarchar(MAX);
IF #Selector = ''konz''
BEGIN
SET #ASSelector = ''Taxi''
SET #IFPers=''''
END
ELSE
BEGIN
SET #ASSelector = ''Personal''
SET #IFPers = ''[name] AS Name,''
END
SET #sql1 = N'';WITH temp AS (SELECT *
FROM (
SELECT
ISNULL((DATENAME(m,[datum])+ cast(datepart(yyyy,[datum]) as varchar(5))),0) AS MONTHYEAR,
ISNULL([''+ #Selector +''],0) AS ''+ #ASSelector +'',''+ #IFPers +''
ISNULL((ISNULL([umsum],0) +
ISNULL([sonst_0],0) +
ISNULL([sonst_7],0) +
ISNULL([sonst_16],0) +
ISNULL([sonst_z],0) -
ISNULL([ff],0)),0) AS UMSATZSUMME
FROM [dbo].[schichten]
) AS SOURCE
PIVOT (SUM([UMSATZSUMME]) FOR [MONTHYEAR] IN (''+ #ColumnName + N'' )) AS UMSAETZE )
SELECT *, ''+ #Gesamtergebnis +'' AS Gesamtergebnis FROM temp ORDER BY ''+ #ASSelector +''''
EXEC sp_executesql #sql1
END
'
I am using SQL Server 2012.
The first part of my query is already answered in this thread. But I also want a second column that will show the corresponding maximum value of that column in its corresponding table.
I have tried this approach: use a function that takes in table name and column name as parameter and return the max value. But it is illegal to use dynamic SQL from a function. Moreover, i cannot seem to call a function from within a SELECT query.
I have also tried using stored procedure, but i cannot figure out how to call it and use it. Please suggest alternative ways to achieve this.
I am new to SQL Server.
Thanks
I think the easiest solution would be stored procedure. As far as I know:
Dynamic SQL can't be placed in functions
Dynamic SQL can't be place in OPENROWSET
I addition, if you write such procedure:
Beware of names containing spaces, qoutes (SQL injection possible)
MAX(column) on non-Indexed columns would require full scan (can be very slow)
Table and column names can be duplicated (placed in differend schemas)
Id duplicates and performance is not a problem, take a look at the following snippet:
CREATE PROC FindMaxColumnValues
#type sysname = '%',
#table sysname = '%'
AS
DECLARE #result TABLE (TableName sysname, ColumnName sysname, MaxValue NVARCHAR(MAX))
DECLARE #tab sysname
DECLARE #col sysname
DECLARE cur CURSOR FOR
SELECT TABLE_NAME TableName, COLUMN_NAME [Column Name]
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE LIKE #type and TABLE_NAME LIKE #table
OPEN cur
FETCH NEXT FROM cur INTO #tab, #col
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql nvarchar(MAX) = 'SELECT '+QUOTENAME(#tab,'''')+' [TableName], '+QUOTENAME(#col, '''')+' [ColumnName], MAX('+QUOTENAME(#col)+') FROM '+QUOTENAME(#tab)
INSERT INTO #result EXEC(#sql)
FETCH NEXT FROM cur INTO #tab, #col
END
CLOSE cur
DEALLOCATE cur
SELECT * FROM #result
Samples:
--MAX of INT's
EXEC FindMaxColumnValues 'INT'
--MAX of INT's in tables matching 'TestTab%'
EXEC FindMaxColumnValues 'INT', 'TestTab%'
--MAX of ALL columns
EXEC FindMaxColumnValues
Results:
TableName ColumnName MaxValue
IdNameTest ID 2
TestTable ID 5
TestTable Number 3
TableName ColumnName MaxValue
TestTable ID 5
TestTable Number 3
TableName ColumnName MaxValue
UpdateHistory UpdateTime 2016-07-14 12:21:37.00
IdNameTest ID 2
IdNameTest Name T2
TestTable ID 5
TestTable Name F
TestTable Number 3
You can use the below SP and enhance it per your Need,
CRETE PROCEDURE Getmaxtablecolval
AS
BEGIN
CREATE TABLE #t
(
tablename VARCHAR(50),
columnname VARCHAR(50),
id INT,
counts INT
)
INSERT INTO #t
SELECT table_name [Table Name],
column_name [Column Name],
NULL,
NULL
FROM information_schema.columns
WHERE data_type = 'INT'
BEGIN TRAN
DECLARE #id INT
SET #id = 0
UPDATE #t
SET #id = id = #id + 1
COMMIT TRAN
DECLARE #RowCount INT
SET #RowCount = (SELECT Count(0)
FROM #t)
DECLARE #I INT
SET #I = 1
DECLARE #Counter INT
DECLARE #TName VARCHAR(50)
DECLARE #CName VARCHAR(50)
DECLARE #DynamicSQL AS VARCHAR(500)
WHILE ( #I <= #RowCount )
BEGIN
SELECT #TName = tablename
FROM #t
WHERE id = #I
SELECT #CName = columnname
FROM #t
WHERE id = #I
SET #DynamicSQL = 'Update #T Set Counts = '
+ '(Select ISNull(Max(' + #CName + '), 0) From '
+ #TName + ') Where Id = '
+ CONVERT(VARCHAR(10), #I)
--PRINT #DynamicSQL
EXEC (#DynamicSQL)
SET #I = #I + 1
END
SELECT *
FROM #t
END
go
Getmaxtablecolval
You can create a procedure out of this:
CREATE PROCEDURE GET_COLUMNS_WITH_MAX_VALUE
#COLUMN_TYPE NVARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- DUMMY VARIABLE TO COPY STRUCTURE TO TEMP
DECLARE #DUMMY TABLE
(
TABLE_NAME NVARCHAR(50),
COLUMN_NAME NVARCHAR(50),
MAX_VALUE NVARCHAR(MAX)
)
-- CREATE TEMP TABLE FOR DYNAMIC SQL
SELECT TOP 0 * INTO #TABLE FROM #DUMMY
INSERT INTO #TABLE
(TABLE_NAME, COLUMN_NAME)
SELECT TABLE_NAME, COLUMN_NAME
FROM information_schema.columns where data_type = #COLUMN_TYPE
DECLARE #TABLE_NAME VARCHAR(50) -- database name
DECLARE #COLUMN_NAME VARCHAR(256) -- path for backup files
DECLARE db_cursor CURSOR FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM #TABLE
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #TABLE_NAME, #COLUMN_NAME
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #SQL NVARCHAR(MAX) = 'UPDATE #TABLE SET MAX_VALUE = (SELECT MAX([' + #COLUMN_NAME + ']) FROM [' + #TABLE_NAME + ']) '
+ 'WHERE [COLUMN_NAME] = ''' + #COLUMN_NAME + ''' AND TABLE_NAME = ''' + #TABLE_NAME + '''';
PRINT #SQL
EXEC (#SQL)
FETCH NEXT FROM db_cursor INTO #TABLE_NAME, #COLUMN_NAME
END
CLOSE db_cursor
DEALLOCATE db_cursor
SELECT * FROM #TABLE
DROP TABLE #TABLE
END
GO
Usage:
EXEC GET_COLUMNS_WITH_MAX_VALUE 'INT'
Results:
TABLE1 ID 50
TABLE2 ID 100
TABLE3 CarID 20
TABLE4 StudentID 30
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.
set #SQL=N' select #minTableId = MIN(id) from ' + #AcDB + '.dbo.vTblOfRollNo '
Declare Cursor For
EXEC SP_EXECUTESQL #SQL
if i have declared all the variables in above query but Declaration of cursor in above
query shows ERROR.
What is Solution?
In order to execute a cursor over dynamic SQL you must put the output of your dynamic sql into a temporary table and then cursor over the temporary table like this:
DECLARE #TableName NVARCHAR(100)
DECLARE #SQL NVARCHAR(1000)
CREATE TABLE #TempTABLE(email NVARCHAR(200))
SET #TableName='Users'
SELECT #SQL='INSERT INTO #TempTable SELECT email FROM ' + #TableName
EXEC (#SQL)
DECLARE MyCursor CURSOR FOR SELECT * FROM #TempTable
OPEN MyCursor
DECLARE #Email NVARCHAR(200)
FETCH NEXT FROM MyCursor INTO #Email
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT 'Email = ' + #Email
FETCH NEXT FROM MyCursor INTO #Email
END
CLOSE MyCursor
DEALLOCATE MyCursor
DROP TABLE #TempTABLE
I dont think you need a cursor for this
try
DECLARE #AcDB VARCHAR(10),
#Sql NVARCHAR(MAX)
set #SQL=N' select MIN(id) from ' + #AcDB + '.dbo.vTblOfRollNo '
DECLARE #Temp TABLE(
MinID INT
)
INSERT INTO #Temp EXEC SP_EXECUTESQL #SQL
DECLARE #minTableId INT
SELECT TOP 1 #minTableId = MinID FROM #Temp
SELECT #minTableId
EDIT: Also here is the actual CURSOR documentation
DECLARE CURSOR (Transact-SQL)