How to pass table name and column name dynamic in SQL - sql

I was trying to pass table name and column name dynamic, this is as part of SSIS process I am trying this stored procedure below.
CREATE PROCEDURE [lnd].[Get_ANCNotullColumn]
(#PassedTableName AS NVarchar(255),
#PassedColumnName AS NVARCHAR(100))
AS
BEGIN
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #PassedTableName
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ';'
DECLARE #final AS NVARCHAR(MAX)
SELECT #final = #sql + 'WHERE ' + #PassedColumnName + ' IS NULL OR ' + #PassedColumnName + '='''
EXEC(#SQL)
END
On executing this, I am NOT getting count as result, instead I am getting execution success.
EXEC [lnd].[Get_ANCNotullColumn] 'lnd.ANC_LND_ItemOverride', 'comments'
I need to get the count as output.
Also my simple direct query is like this
SELECT COUNT(*)
FROM lnd.ANC_LND_ItemOverride
WHERE Comments IS NULL OR Comments = '' -- 3 is the output

I think you may need to modify you value passing and your concatenation values.
from this statement you need to remove the semi colon as it will throw error
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ';'
While passing blank values you need additional quotes
SELECT #final = #sql + 'WHERE ' + #PassedColumnName + ' IS NULL OR ' + #PassedColumnName + '= '''''
While execution I believe you wanted to execute final instead of SQL
I think below should give your output:
CREATE PROC [lnd].[Get_ANCNotullColumn]( #PassedTableName as NVarchar(255),#PassedColumnName AS
NVARCHAR(100))
AS
BEGIN
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #PassedTableName
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ' '
DECLARE #final AS NVARCHAR(MAX)
SELECT #final = #sql + 'WHERE ' + #PassedColumnName + ' IS NULL OR ' + #PassedColumnName + '='''''
EXEC(#final)
END

Related

SQL Server : how to insert using variable

I am trying to insert data into a SQL Server table using a variable. I tried
DECLARE #table NVARCHAR(50) = 'ToolList',
#val NVARCHAR(50) = 'test'
EXEC ('INSERT INTO ' + #table + 'SELECT ' + #val)
and
EXEC ('INSERT INTO ' + #table + '([col1]) VALUES(' + #val +')'
but still get an error that says
Incorrect syntax near 'test'.
you missed a space before SELECT and the #val should enclosed in single quote
DECLARE #table nvarchar(50) = 'ToolList',
#val nvarchar(50) = 'test'
EXEC ( 'INSERT INTO ' + #table + ' SELECT ''' + #val + '''')
when you use Dynamic SQL, it is easier to form the query in a variable so that you can print out , inspect the value before execution
select #sql = 'INSERT INTO ' + #table + ' SELECT ''' + #val + ''''
print #sql
exec (#sql)
You'd better use sp_executesql that allows for statements to be parameterized, to avoid the risk of SQL injection.
DECLARE #Query NVARCHAR(1000),
#table NVARCHAR(50) = 'ToolList'
SET #Query = 'INSERT INTO ' + #table + ' SELECT #val'
EXEC sp_executesql #Query, N'#val nvarchar(50)', #val = 'test'
sp-executesql-transact-sql
You can also use CHAR(39) instead of adding single quotes every time for better readability. And also, you have not added a space after the variable which contains the table name.
Query
declare #table nvarchar(50) = 'ToolList',
#val nvarchar(50) = 'test2';
declare #sql as varchar(max) = 'insert into ' + #table
+ ' select ' + char(39) + #val + char(39);
exec(#sql);
You need 4 singlequotes before the #val field as it is a string and all strings needs to be encapsulated in single quotes.
You can print the dynamic string using PRINT command check what the final string you are going to execute.
DECLARE #table VARCHAR(50) = 'ToolList'
DECLARE #val VARCHAR(50) = 'test'
DECLARE #DSQL AS VARCHAR(MAX) = ''
SET #DSQL = #DSQL + ' INSERT INTO [' + #table + ']' + '
SELECT ' + '''' + #val + ''''
--PRINT #DSQL
EXEC(#DSQL)

Select table and column dynamically based on other table rows

I have following table and values,
Tb_name column_name1 column_name2
Citator_KTLO_CC Date_Created Date_Modified
Citator_KTLO_QA Date_Created Date_Modified
I want to select dynamically column from table, so the result is like this:
Select Date_Created,Date_Modified from Citator_KTLO_CC
and in next loop it will select for second row, like
Select Date_Created,Date_Modified from Citator_KTLO_QA
How can i do this by using dynamic sql ?
any example are appreciated.
here is an example of how to do this.
Since you dont post many info I just assume that the table containing all the tablenames is called 'tables'
Also this will only work if all tables have the same column types.
-- create a test table you dont need this
create table tables (tb_name varchar(100) primary key, field1 varchar(100), field2 varchar(100))
-- fill my test table you dont need this
insert into tables values ('table1', 'field1', 'field2')
insert into tables values ('table2', 'foo1', 'foo2')
insert into tables values ('table3', 'test1', 'test2')
-- this is the actual code you need, replace the names with your real names
declare #sql varchar(max) = ''
declare #tb_name varchar(100) = ''
declare #field1 varchar(100) = ''
declare #field2 varchar(100) = ''
declare myCursor cursor for
select tb_name, field1, field2 from tables -- dont know how your table is called
open myCursor
fetch next from myCursor into #tb_name, #field1, #field2
while ##FETCH_STATUS = 0
begin
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' union all '
fetch next from myCursor into #tb_name, #field1, #field2
end
close myCursor
deallocate myCursor
select #sql = left(#sql, len(#sql) - 10)
exec (#sql)
EDIT:
using a where clause is possible but things will get more complicated
declare #something date = getdate()
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' where ' + #field1 + ' = ' + #something + ' union all '
You can use the example above to build what you need just play with it.
EDIT:
using a where clause with a date format
declare #something date = getdate()
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' where ' + #field1 + ' = ''' + CONVERT(varchar(8), #something, 112) + ''' union all '
DECLARE #SQL VARCHAR(1000);
SET #SQL = '
SELECT *
FROM Citator_KTLO_CC
UNION ALL
SELECT *
FROM Citator_KTLO_QA;'
EXEC (#SQL);
How about something like this. If you've more than two cols, you can use dynamic sql to generate a list of cols to then generate more dynamic sql instead of hard coding.
DROP TABLE #Test
CREATE TABLE #Test
(Tb_name NVARCHAR(15),
column_name1 NVARCHAR(12),
column_name2 NVARCHAR(13));
INSERT INTO #Test VALUES
('Citator_KTLO_CC','Date_Created','Date_Modified'),
('Citator_KTLO_QA','Date_Created','Date_Modified');
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = (SELECT STUFF((SELECT ' UNION ALL SELECT ' + Cols + ' FROM '+TbL
FROM (SELECT QUOTENAME(Tb_name) TBL,
QUOTENAME(column_name1) + ', '+
QUOTENAME(column_name2) Cols
FROM #Test) Blah
FOR XML PATH('')),1,10,''))
PRINT #SQL
EXEC sys.sp_executesql #SQL
Try this..
For selecting one row if you are running in aloop
DECLARE #sql NVARCHAR(4000)
SELECT #sql = ' select ' + column_name_1 + ',' + column_name2 + ' from ' + Tb_name
FROM < yourtable >
EXEC (#sql)
OR
DECLARE #sql NVARCHAR(4000)
SELECT #sql = 'union all select ' + column_name_1 + ',' + column_name2 + ' from ' + Tb_name
FROM < yourtable >
SET #sql =stuff(#sql,1,10,'')
EXEC (#sql)
DECLARE #ColumnList1 VARCHAR(MAX) = '''''';
DECLARE #ColumnList2 VARCHAR(MAX) = '''''';
DECLARE #ColumnNameFromTable1 VARCHAR(50);
DECLARE #ColumnNameFromTable2 VARCHAR(50);
DECLARE MyCursor1 CURSOR
FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Citator_KTLO_CC'
ORDER BY ORDINAL_POSITION
DECLARE MyCursor2 CURSOR
FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Citator_KTLO_QA'
ORDER BY ORDINAL_POSITION
OPEN MyCursor1
OPEN MyCursor2
FETCH NEXT FROM MyCursor1 INTO #ColumnNameFromTable1;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM MyCursor2 INTO #ColumnNameFromTable2;
SET #ColumnList1 = #ColumnList1 + ',' + #ColumnNameFromTable1
SET #ColumnList2 = #ColumnList2 + ',' + #ColumnNameFromTable2
FETCH NEXT FROM MyCursor1 INTO #ColumnNameFromTable1;
END
CLOSE MyCursor1;
DEALLOCATE MyCursor1;
CLOSE MyCursor2;
DEALLOCATE MyCursor2;
EXEC ('SELECT ' + #ColumnList1 + ' FROM Citator_KTLO_CC UNION ALL SELECT ' +
#ColumnList2 + ' FROM Citator_KTLO_QA ')

Return Row Count Using Dynamic SQL

I'm trying to run the following Dynamic SQL statement:
#Tbl, #Fld, and #LookupValue have all been set according to Table to search, Field (Or Column) to search and column value to compare.
DECLARE #Sql AS VARCHAR(500)
SET #Sql = 'SELECT COUNT(*)
FROM ' + #Tbl +
' WITH (NOLOCK)
WHERE ' + #Fld + ' = ''' + #LookupValue + ''''
EXEC(#Sql)
I want to store the result into a variable so I can check to see if there are any returned rows. This statement is in the middle of a WHILE construct that is checking several tables and fields.
If records are found, then I want to display:
SET #Sql = 'SELECT ' + #Fld +
' FROM ' + #Tbl +
' WITH (NOLOCK)
WHERE ' + #Fld + ' = ''' + #LookupValue + ''''
EXEC(#Sql)
Yes, you can store it in a typed variable and use sp_executesql like
DECLARE #Sql AS NVARCHAR(500);
DECLARE #cnt INT;
SET #Sql = 'SELECT #cnt = COUNT(*)
FROM ' + #Tbl +
' WITH (NOLOCK)
WHERE ' + #Fld + ' = ''' + #LookupValue + '''';
EXEC sp_executesql #Sql, N'#cnt INT OUTPUT', #cnt OUTPUT;
SELECT #cnt;
you can create a temporary table and store the count value.
if object_id('tempdb.#mycount') is null
create table #mycount ( countVal int);
DECLARE #Sql AS VARCHAR(500)
SET #Sql = 'INSERT INTO #mycount
SELECT COUNT(*)
FROM ' + #Tbl +
' WITH (NOLOCK)
WHERE ' + #Fld + ' = ''' + #LookupValue + ''''
EXEC(#Sql)
select countVal from #mycount
-- once the temp table usage is done, you can delete it
drop table #mycount

Generate string processing for on rows from some table

I've got table with columns and procedure to create SQL table:
DECLARE #SQLString NVARCHAR(MAX)
SELECT #SQLString =
'
'+ ColName + ' ' + ColType + ' '+ ColNullable + ',
'
FROM FS_Report_Tables WHERE TableId = 0
PRINT ('CREATE TABLE '+ 'Test' + #SQLString)
EXEC ('CREATE TABLE '+ 'Test' + #SQLString)
Current code prints only last column when I need all ( without coma at last )
Data table example:
ColumnId TableId ColName ColType ColNullable
1 0 A int NOT NULL
2 0 B int NOT NULL
How can I build SQLString with nodes from SELECT from another table?
Please try:
DECLARE #SQLString NVARCHAR(MAX)
SELECT
#SQLString = COALESCE(#SQLString + ', ', '') + ColName + ' ' + ColType + ' ' + ColNullable
from
YourTable
select #SQLString
EXEC ('CREATE TABLE YourTableName (' + #SQLString + ')')
DECLARE #SQLString NVARCHAR(MAX)
SET #SQLString = 'CREATE TABLE '+ #TableName +
'
( '+#Column1Name+' '+#Column1DataType +' '+#Column1Nullable +')
'
PREPARE stmt FROM #SQLString;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
You need to use prepared statements
SQL server provides you a stored procedure, sp_executesql which will do this task for you

Execute a Stored Procedure in a SELECT statement

For an instance I a select statement and it is returning 1000 rows. I need to execute a particular stored procedure for every row the the select statement is returning.
have you got any idea how can I do that?
Construct the EXECUTE statements in your select like this:
SELECT 'EXEC sp_whatever ' + parameter stuff
FROM your_table
Then run the results! Alternatively, paste your results into a spreadsheet package, and use string concatenation to construct the EXEC statements - just create a formula and paste it down the 1,000 rows. I personally prefer the first approach.
To clarify the "parameter stuff", take the example of a stored procedure that takes two int parameters that you want to take from columns you your_table. You'd then have something like this:
SELECT 'EXEC sp_whatever ' + CAST(field1 AS varchar) + ', ' + CAST(field2 AS varchar)
FROM your_table
Not the need to be careful with string fields here - you run the risk of inadvertently exposing yourself to your own SQL injection attack, as with any SQL string concatenation.
I am reading your "for an instance" as "this is a one-off task". If this is a task that needs automating, then one of the other answers may be the right approach.
You can do it like this:
declare #execstatementsbatch nvarchar(max)
select #execstatementsbatch = ''
SELECT #execstatementsbatch = #execstatementsbatch + 'EXEC UpdateQty ' + ItemCode + ', ' + QtyBO + '; '
FROM ITEMSPO
INNER JOIN .....
<some conditions>
exec(#execstatementsbatch)
Disclaimer: I'm not sure if I understand your question correctly.
Assuming you are on SQL Server 2005 upwards, you could create a table-valued user defined function and use the OUTER APPLY operator in your query.
Most RDBMS will let you select rows from stored procedure result sets. Just put your stored procedures in the FROM clause, as you would for common table expressions. For instance:
SELECT sp.ColumnInResultSet, t.BaseTableColumnName
FROM sp_whatever ( Args) sp INNER JOIN BaseTable t ON t.ID = sp.ID;
CREATE PROCEDURE dbo.usp_userwise_columns_value
(
#userid BIGINT
)
AS
BEGIN
DECLARE #maincmd NVARCHAR(max);
DECLARE #columnlist NVARCHAR(max);
DECLARE #columnname VARCHAR(150);
DECLARE #nickname VARCHAR(50);
SET #maincmd = '';
SET #columnname = '';
SET #columnlist = '';
SET #nickname = '';
DECLARE CUR_COLUMNLIST CURSOR FAST_FORWARD
FOR
SELECT columnname , nickname
FROM dbo.v_userwise_columns
WHERE userid = #userid
OPEN CUR_COLUMNLIST
IF ##ERROR <> 0
BEGIN
ROLLBACK
RETURN
END
FETCH NEXT FROM CUR_COLUMNLIST
INTO #columnname, #nickname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #columnlist = #columnlist + #columnname + ','
FETCH NEXT FROM CUR_COLUMNLIST
INTO #columnname, #nickname
END
CLOSE CUR_COLUMNLIST
DEALLOCATE CUR_COLUMNLIST
IF NOT EXISTS (SELECT * FROM sys.views WHERE name = 'v_userwise_columns_value')
BEGIN
SET #maincmd = 'CREATE VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), #userid) + ') as userid , '
+ CHAR(39) + #nickname + CHAR(39) + ' as nickname, '
+ #columnlist + ' compcode FROM dbo.SJOTran '
END
ELSE
BEGIN
SET #maincmd = 'ALTER VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), #userid) + ') as userid , '
+ CHAR(39) + #nickname + CHAR(39) + ' as nickname, '
+ #columnlist + ' compcode FROM dbo.SJOTran '
END
--PRINT #maincmd
EXECUTE sp_executesql #maincmd
END
-----------------------------------------------
SELECT * FROM dbo.v_userwise_columns_value