TSQL - Parameters and dynamic table names - sql

Please see the DDL below:
CREATE TABLE Person (ID int identity, Name varchar(30), primary key(ID))
INSERT INTO Person (Name) VALUES ('Ian')
Please see the TSQL below:
Declare #ID int
Declare #Name varchar(30)
set #Name = 'Ian'
select #ID=ID FROM Person WHERE Name=#Name
Print #ID
This works as I would expect i.e. 1 is printed to the screen. I want to make a change so that the table name is dynamic i.e.
Declare #ID int
Declare #Name varchar(30)
Declare #TableName as varchar(30)
set #TableName= 'Person'
set #Name = 'Ian'
select #ID=ID FROM #TableName WHERE Name=#Name
Print #ID
The above SQL obviously does not work. I realise that I have to use TSQL. I have tried using EXEC and sp_executesql, but I can only get part way there. How do I implement this. The SQL statement must be: select #ID=ID FROM #TableName WHERE Name=#Name.

You will need to use dynamic sql for this. Have a look here...
Declare #ID int
Declare #Name varchar(30)
Declare #TableName sysname
DECLARE #Sql NVARCHAR(MAX);
set #TableName= 'Person'
set #Name = 'Ian'
SET #Sql = N'select #ID = ID FROM ' + QUOTENAME(#TableName)
+ N' WHERE Name = #Name'
EXECUTE sp_executesql #Sql
,N'#ID int OUTPUT, #Name varchar(30)'
,#ID OUTPUT
,#Name
PRINT #ID

Related

T sql - How to store results from a dynamic query using EXEC or EXECUTE sp_executesql

I am trying to write a dynamic query. Let's say i have a table like below, which represents the hierarchy level of a sales agent:
AgentNumber Level1Agent Level2Agent Level3Agent Level4Agent Level5Agent
1122334455 1122334499 1122334488 1122334477 1122334466 1122334455
I want to be able to dynamically select a level based on a specified agent. My EXECUTE statement seems to work correctly, but how do I get the result stored in a variable I can use later? Every answer I have found seems to only get me a success return variable, not the actual query result.
Below is my code:
DECLARE #level INT = 1;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
DECLARE #whereclause NVARCHAR(35) = CONCAT('WHERE AgentNumber = ',#agent);
DECLARE #qry NVARCHAR(300) = 'SELECT ' + #colname + ' FROM dbo.TABLE ' + #whereclause;
DECLARE #up NVARCHAR(10);
EXECUTE sp_executesql #qry, #up OUT
SELECT #up
The output of #up is NULL. If I change the last two lines to:
EXECUTE #up = sp_executesql #qry
SELECT #up
Now the output of #up is 0.
I want the output of 1122334499 and I need it stored in a variable that can later be used and inserted into a table.
Here is a fully functional example of how you can do this. Notice this is using a parameterized where clause and quotename around the column name in the dynamic sql to prevent sql injection.
if OBJECT_ID('tempdb..#Agents') is not null
drop table #Agents
create table #Agents
(
AgentNumber char(10)
, Level1Agent char(10)
, Level2Agent char(10)
, Level3Agent char(10)
, Level4Agent char(10)
, Level5Agent char(10)
)
insert #Agents
select '1122334455', '1122334499', '1122334488', '1122334477', '1122334466', '1122334455'
DECLARE #level INT = 3;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
declare #agentout char(10)
DECLARE #qry NVARCHAR(300) = 'SELECT #agent_out = ' + quotename(#colname) + ' FROM #Agents WHERE AgentNumber = #agentin';
EXECUTE sp_executesql #qry, N'#agentin char(10), #agent_out char(10) output', #agentin = #agent, #agent_out = #agentout output
select #agentout
You can try this :
DECLARE #level INT = 1;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
DECLARE #whereclause NVARCHAR(35) = CONCAT('WHERE AgentNumber = ',#agent);
DECLARE #qry NVARCHAR(300) = 'SELECT #agentout=' + #colname + ' FROM dbo.TABLE ' + #whereclause;
DECLARE #up NVARCHAR(10);
EXECUTE sp_executesql #qry, N'#agentout NVARCHAR(10) OUTPUT', #agentout=#up OUTPUT
SELECT #up
Create a variable table and makes your query insert the results you want there. Something like this:
declare #results table(field1 varchar(max), field2 varchar(max));
declare #sqlStatement varchar(max);
set #sqlStatement = 'insert into #results(field1, field2) select field1, field2 from table';
EXECUTE #sqlStatement;
select * from #results; --It will print the results from your sql statement!

Dynamic SQL output of a query to a variable

I would like to output the result of the dynamic SQL into a variable called #Count but not sure what the syntax or even the code should like to accomplish this.
The code looks as follows:
declare #tab nvarchar(255) = 'Person.person'
declare #Count int
declare #SQL nvarchar(max) = 'select count(*) from '+ #tab
exec(#SQl)
select #Count
thank you
Here's another way to do it that also safely addresses the SQL Injection isuues:
/* Counts the number of rows from any non-system Table, *SAFELY* */
-- The table name passed
DECLARE #PassedTableName as NVarchar(255) = 'Person.Person';
-- Make sure this isn't a SQL Injection attempt
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = TABLE_SCHEMA + '.' + TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = PARSENAME(#PassedTableName,1)
AND TABLE_SCHEMA = PARSENAME(#PassedTableName,2)
-- make a temp table to hold the results
CREATE TABLE #tmp( cnt INT );
-- create the dynamic SQL
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ';'
-- execute it and store the output into the temp table
INSERT INTO #tmp( cnt )
EXEC(#SQL);
-- Now, finally, we can get it into a local variable
DECLARE #result AS INT;
SELECT #result = cnt FROM #tmp;
You can utilize sp_executesql to execute your count() query, and output it #Count.
Try this:
-- Set the table to count from
declare #tab nvarchar(255) = 'Person.person'
-- Assign the SQL query
declare #SQL nvarchar(255) = N'SELECT count(*) FROM ' + #tab
-- Pepare for sp_executesql
declare #Count int
declare #Params nvarchar(100) = N'#Count int output'
-- Set the count to #Count
exec sp_executesql #SQL, #Params, #Count=#Count output
-- Output #Count
select #Count
One last thing: Person.person looks like you might be trying to reference a person column from a Person table. But the above query is a literal representation of what it looks like you're trying to achieve in your question.
The below question is pretty much identical to what you are asking here.
sp_executeSql with output parameter
DECLARE #retval int
DECLARE #sSQL nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
DECLARE #tablename nvarchar(50)
SELECT #tablename = N'products'
SELECT #sSQL = N'SELECT #retvalOUT = MAX(ID) FROM ' + #tablename;
SET #ParmDefinition = N'#retvalOUT int OUTPUT';
EXEC sp_executesql #sSQL, #ParmDefinition, #retvalOUT=#retval OUTPUT;
SELECT #retval;

Dynamic Name for Database Table - Stored Procedure

I want to create dynamic name for my database tables. I declare variable and use it as my table name.
ERROR: Incorrect syntax near '#sample'. Expecting '.',ID or QUOTED_ID
CREATE PROCEDURE [dbo].[sp_SAMPLE]
#name nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sample nvarchar(50);
SET #sample = 'tbl_function_' + #name;
Create Table #sample
(
id int not null,
UserType nvarchar(50) null,
paramater2 nvarchar(50) null
)
END
Is there any way to make my table name dynamic? Thank you.
I'm not sure why you would want to do this. But, you can do it using dynamic SQL:
CREATE PROCEDURE [dbo].[sp_SAMPLE]
#name nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql nvarchar(max);
SET #sql = '
Create Table tbl_function_#name
(
id int not null,
UserType nvarchar(50) null,
paramater2 nvarchar(50) null
)';
SET #sql = REPLACE(#sql, '#name', #name);
EXEC sp_executesql #sql;
END;
Why would you want to create a separate table for each #name, instead of just inserting rows with #name in a column?
CREATE PROCEDURE [dbo].[sp_SAMPLE]
#name nvarchar(50)
AS
BEGIN
SET NOCOUNT ON
DECLARE #sql varchar(4000);
SET #sql = '
Create Table tbl_function_'+#name+'
(
id int not null,
UserType nvarchar(50) null,
paramater2 nvarchar(50) null
)'
EXEC (#sql)
END

Output parameter in stored procedure is null

I can't seem to get the output parameter right, it's empty where I'm exepecting 'TEMPTABLE'?
create table TEMPTABLE
(
Id int identity primary key,
Name nvarchar(50) not null,
);
GO
insert into TEMPTABLE(Name) values('Name 1');
GO
DECLARE #PARMOUTP nvarchar(50)
DECLARE #ParameterDefinition AS NVARCHAR(2000)
DECLARE #DestTable VARCHAR(50)
declare #sql nvarchar(max)
set #sql = 'SELECT OBJECT_NAME(OBJECT_ID) AS TABLENAME
FROM SYS.IDENTITY_COLUMNS
WHERE OBJECT_NAME(OBJECT_ID) = #DestTable'
set #DestTable = 'TEMPTABLE'
set #ParameterDefinition = '#DestTable VARCHAR(50), #PARMOUTP VARCHAR(50) OUTPUT'
EXECUTE sp_executesql #sql,
#ParameterDefinition,
#DestTable,
#PARMOUTP OUTPUT
print #PARMOUTP;
print isnull(#PARMOUTP, 'PARMOUTP is null!');
What am I doing wrong here?
Regards,
Mike
Your query is not suited for sp_executesql with one parameter.
In the query you should assign value to that parameter and execute it.
Something like this:
create table TEMPTABLE
(
Id int identity primary key,
Name nvarchar(50) not null,
);
GO
insert into TEMPTABLE(Name) values('Name 1');
GO
DECLARE #PARMOUTP nvarchar(50)
DECLARE #ParameterDefinition AS NVARCHAR(2000)
DECLARE #DestTable VARCHAR(50)
declare #sql nvarchar(max)
set #sql = 'SELECT #PARMOUTP = OBJECT_NAME(OBJECT_ID) AS TABLENAME
FROM SYS.IDENTITY_COLUMNS
WHERE OBJECT_NAME(OBJECT_ID) = #DestTable'
set #DestTable = 'TEMPTABLE'
set #ParameterDefinition = '#DestTable VARCHAR(50), #PARMOUTP VARCHAR(50) OUTPUT'
EXECUTE sp_executesql #sql,
#ParameterDefinition,
#DestTable,
#PARMOUTP OUTPUT
print #PARMOUTP;
print isnull(#PARMOUTP, 'PARMOUTP is null!');
Remember that you are returning scalar value from your dynamic query.
In your dynamic SQL statement, you're never assigning any value to the output parameter!
You're selecting the table name as a result set - but it never gets stored into the output variable.
Try this:
set #sql = 'SELECT #PARMOUTP = OBJECT_NAME(OBJECT_ID)
FROM SYS.IDENTITY_COLUMNS
WHERE OBJECT_NAME(OBJECT_ID) = #DestTable'

Update a Table by Passing Table Name, ColumnName as a Variable Using Cursor

I want to Update a Table. I am getting Table Name and Column Name as a XML DataSet from the Front End. I have written One Cursor for that. But it throws error. Below is my Cursor
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[PMT_Formstatus_Update_Test]
(
#XMLTableNames VARCHAR(MAX)
)
AS
BEGIN
DECLARE #docHandle INT, #ErrorMessage VARCHAR(200), #doc VARCHAR(200)
SET #doc = '<?xml version="1.0" encoding="iso-8859-1" ?>'
DECLARE #Names TABLE
(
TName VARCHAR(50),
CName VARCHAR(50),
IDField VARCHAR(50),
FunctionID INT,
ID INT,
StatusID INT
)
SET #XMLTableNames = #doc + #XMLTableNames
EXEC sp_xml_preparedocument #docHandle OUTPUT, #XMLTableNames
INSERT INTO #Names
SELECT * FROM
OPENXML(#docHandle,'NewDataSet/NameDetails',2)
WITH
(
TName VARCHAR(50),
CName VARCHAR(50),
IDField VARCHAR(50),
FunctionID INT,
ID INT,
StatusID INT
)
DECLARE #FunctionID INT
DECLARE #StatusID INT
DECLARE #ID INT
DECLARE #TableName VARCHAR(50)
DECLARE #ColumnName VARCHAR(50)
DECLARE #IDField VARCHAR(50)
DECLARE #getTables CURSOR
SET #getTables = CURSOR FOR
SELECT FunctionID, TName, CName, StatusID, IDField, ID FROM #Names
OPEN #getTables
FETCH NEXT
FROM #getTables INTO #FunctionID, #TableName, #ColumnName, #StatusID, #IDField, #ID
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE #TableName SET #ColumnName = 3 WHERE #IDField = #ID
FETCH NEXT
FROM #getTables INTO #FunctionID, #TableName, #ColumnName, #StatusID, #IDField, #ID
END
CLOSE #getTables
DEALLOCATE #getTables
END
How to write Update Query in this case? Please I need all your suggestions...
You need to concatenate them as string then call EXEC('')
EXEC ('UPDATE TableName SET ColumnName1 = 3 WHERE ColumnName2= Value')
Simple Dynamic SQL Example:
DECLARE #SQL NVARCHAR(max),#TableName VARCHAR(128),#ColumnName1 VARCHAR(128),#ColumnName2 VARCHAR(128),#Value NVARCHAR(MAX),#NewValue NVARCHAR(MAX)
SET #TableName='User'
SET #ColumnName1='Session_Id'
SET #ColumnName2='Session_Id_Old'
SET #Value=''''+CAST(NEWID() as NVARCHAR(50))+''''
SET #NewValue=''''+CAST(NEWID() as NVARCHAR(50))+''''
SET #SQL=
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
'UPDATE [#TableName] SET [#ColumnName1] = #NewValue WHERE [#ColumnName2]= #Value','#TableName',#TableName),
'#ColumnName1',#ColumnName1),'#Value',#Value),'#NewValue',#NewValue),'#ColumnName2',#ColumnName2)
EXECUTE(#SQL)
You should add apostrophes to both sides of old/new values if data types are strings
You can hopefully see why what you've written doesn't work, since it's an update statement to execute against a table variable, which affects no actual columns in that table:
declare #TableName table (ID int not null)
declare #ColumnName1 int
declare #ColumnName2 int
declare #Value int
UPDATE #TableName SET #ColumnName1 = 3 WHERE #ColumnName2= #Value
One means to try and achieve what you're doing are dynamic SQL. It's ugly (and will be more so if the data types in the columns vary). There's no real "meta-programming" system built into T-SQL.