dynamic SQL query in SQL Server - sql-server

declare #text as varchar(100)
declare #rep as varchar
declare #ac as varchar
declare #sub as varchar(4)
declare #stmt as varchar(50)
set #text='1214324324234324'
set #ac='2'
set #rep ='4'
set #sub='#rep'
set #stmt = 'Select Replace('''+#text+''','''+#ac+''','+#sub+')'
print #stmt
--dynamic query execution
exec(#stmt)
I am facing below issue.
Select Replace('1214324324234324','2',#rep) Msg 137, Level 15, State
2, Line 1 Must declare the scalar variable "#rep"

Your error is pretty clear.
set #rep ='4'
set #sub='#rep'
You set a value to #rep and use another variable (#sub) to point at the previous assigned variable #rep. In fact, your dynamic SQL statement is combined like this:
set #stmt = 'Select Replace('''+#text+''','''+#ac+''','+#sub+')'
This will interpreted like this: SELECT REPLACE('1214324324234324','2',#rep)
Your dynamic doesn't know that there is a variable #rep. You need to concat #rep into your dynamic SQL instead of those additional assignment to #sub.
You can use this:
set #stmt = 'Select Replace('''+#text+''','''+#ac+''','+#rep+')'

You need to run the entire statement at once. If you run one line at a time, SQL will forget the variables you previously declared. I took all of your SQL and ran it, and it worked perfectly fine for me.

Related

How to pass a variable value in a FROM clause in Microsoft TSQL

sorry I am uploading a pic of my query as I dont know to format my text...as a newbie its confusing.
So you want to execute:
select * from File_20170703 -- where your table name is a variable.
It is not possible to use variables for table or column names, what you need to do is to build a dynamic sql and execute it using sp_executesql.
here is an example:
DECLARE #sql nvarchar(4000)
SELECT #sql = 'SELECT * FROM File_20170703'
EXEC sp_executesql #sql
More info about dynamic sql
A simple TSQL "dynamic sql" looks like this:
DECLARE #file_name AS VARCHAR(100)
DECLARE #query AS VARCHAR(MAX)
SET #file_name = 'file_20170101'
SET #query = 'SELECT * FROM ' + #file_name
execute(#query)
Basically you need to create a valid sql query by concatenating various parts of the query together, then you can execute that whole big string as your query.
You can use SQL Cursor along with while loop. Examples are given here:
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/while-transact-sql

Declaring output parameters for sp_executesql

I'm trying to make a bit of SQL script that will output all the table names in a large database, along with the numbers of fields and records in each, and a list of the field names. This will allow us to focus on the tables with data, and look for field names that match from different tables, which might be appropriate places for joins.
To do this, I'm trying to write dynamic SQL that can cycle through all the tables. But I haven't been able to get sp_executesql to yield outputs that I can insert into my table variable. Here's the code I've written so far:
USE MITAS_TEST;
DECLARE #TablesAbstract TABLE(
TableName VARCHAR(50),
NumberOfFields INT,
NumberOfRecords INT
);
DECLARE #NumberOfRowsCounted INTEGER;
SET #NumberOfRowsCounted = 0;
DECLARE #RecSql NVARCHAR(500);
SET #RecSql = 'EXECUTE(''SELECT #NumberOfRows = COUNT(*) FROM ''+#TableName)';
DECLARE #ParmDefinition NVARCHAR(100);
SET #ParmDefinition = '#TableName NVARCHAR(100), #NumberOfRows INTEGER OUTPUT';
DECLARE #TableN NVARCHAR(100);
SET #TableN = 'MITAS_TEST.dbo.AP500';
EXECUTE sp_executesql #RecSql,
#ParmDefinition,
#TableName = #TableN,
#NumberOfRows = #NumberOfRowsCounted OUTPUT;
I get the following error:
Msg 137, Level 15, State 1, Line 1
Must declare the scalar variable "#NumberOfRows"
I would have thought it sufficed to declare #NumberOfRows in the #ParmDefinition field (based on this source: https://technet.microsoft.com/en-us/library/ms188001(v=sql.90).aspx). What am I doing wrong? Is there a better way?
The inner execute looks like:
EXECUTE('SELECT #NumberOfRows = COUNT(*) FROM MITA_TEST.dbo.AP500')
In that context, #NumberOfRows does not exist. You could change that to another call to sp_executesql, passing the output parameter #NumberOfRows down another level.
Assuming that this represents learning code, and not production. Depending on the source of #TableN, this could be susciptable to SQL injection attacks. See quotename in books online.

SQL variable for Database Name

I am trying to pass a database name in as a parameter and execute some dynamic SQL. As a test I created this:
declare #HRMSDatabase_1 nvarchar(50) = N'FirstDatabase',
#Example_1 nvarchar(max) =
'select #HRMSDatabase'
execute sp_executesql #Example_1, N'#HRMSDatabase nvarchar(50)', #HRMSDatabase_1
which returns FirstDatabase as I expected.
When I try this:
declare #HRMSDatabase_2 nvarchar(50) = N'FirstDatabase',
#Example_2 nvarchar(max) =
'select
''Test''
from
#HRMSDatabase.dbo.hrpersnl hp'
execute sp_executesql #Example_2, N'#HRMSDatabase nvarchar(50)', #HRMSDatabase_2
I get an error message:
Msg 102, Level 15, State 1, Line 29
Incorrect syntax near '.'.
Is what I am trying to do possible? I cannot simply use a USE FirstDatabase as I have a few databases I have to query in the same dynamic SQL using inner joins.
Also, I cannot use SQLCMD as this script gets executed from a GUI.
Basically, I don't believe you can parameterize the database name in the table specifier. Instead try this,
DECLARE #HRMSDatabase NVARCHAR(50) = N'FirstDatabase';
DECLARE #Example3 NVARCHAR(MAX) ='SELECT
''Test''
FROM
' + QUOTENAME(#HRMSDatabase) + '.[dbo].[hrpersnl] hp';
EXEC sp_executesql #Example3;
As you'll note, it's important that the #HRMSDatabase is not recieved from user input as this would be susceptible to injection attacks.

SQL - Can I pass a variable to be used in the FROM statement?

Can I pass a variable to a SELECT statement?
I keep getting an error message saying I need to declare it.
However, it is declared.
SELECT (list of columns)
FROM #database_table
You are looking to use Dynamic SQL to perform this type of query.
The Curse and Blessings of Dynamic SQL
Here is a quick sample
declare #sqlstatement nvarchar(4000)
declare #table sysname
set #table = 'yourTableName'
set #sqlstatement = 'SELECT * FROM ' + QUOTENAME(#table)
exec(#sqlstatement)
Yes, use dynamic sql statements to build your select statement.
-- Procedure input parameters
#TableName varchar(50)
-- Query guts
Declare #sql varchar(2000)
Set #sql = 'Select columnname from ' + #TableName
exec (#sql)
The one time you can do what you want is when you use table variables. You have to define the variables as:
declare #name table (<column list>)
This is alternative method of declaring a temporary table.
Other than this, I fully agree with bluefeet. You should read the link he posted.

Using sp_executesql with params complains of the need to declare a variable

I am attempting to make a stored procedure that uses sp_executesql. I have looked long and hard here, but I cannot see what I am doing incorrectly in my code. I'm new to stored procedures/sql server functions in general so I'm guessing I'm missing something simple. The stored procedure alter happens fine, but when I try run it I'm getting an error.
The error says.
Msg 1087, Level 15, State 2, Line 3
Must declare the table variable "#atableName"
The procedure looks like this.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[sp_TEST]
#tableName varchar(50),
#tableIDField varchar(50),
#tableValueField varchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQLString nvarchar(500);
SET #SQLString = N'SELECT DISTINCT #aTableIDField FROM #atableName';
EXEC sp_executesql #SQLString,
N'#atableName varchar(50),
#atableIDField varchar(50),
#atableValueField varchar(50)',
#atableName = #tableName,
#atableIDField = #tableIDField,
#atableValueField = #tableValueField;
END
And I'm trying to call it with something like this.
EXECUTE sp_TEST 'PERSON', 'PERSON.ID', 'PERSON.VALUE'
This example isn't adding anything special, but I have a large number of views that have similar code. If I could get this stored procedure working I could get a lot of repeated code shrunk down considerably.
Thanks for your help.
Edit: I am attempting to do this for easier maintainability purposes. I have multiple views that basically have the same exact sql except the table name is different. Data is brought to the SQL server instance for reporting purposes. When I have a table containing multiple rows per person id, each containing a value, I often need them in a single cell for the users.
You can not parameterise a table name, so it will fail with #atableName
You need to concatenate the first bit with atableName, which kind defeats the purpose fo using sp_executesql
This would work but is not advisable unless you are just trying to learn and experiment.
ALTER PROCEDURE [dbo].[sp_TEST]
#tableName varchar(50),
#tableIDField varchar(50),
#tableValueField varchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQLString nvarchar(500);
SET #SQLString = N'SELECT DISTINCT ' + quotename(#TableIDField) + ' FROM ' + quotename(#tableName);
EXEC sp_executesql #SQLString;
END
Read The Curse and Blessings of Dynamic SQL
You cannot use variables to pass table names and column names to a dynamic query as parameters. Had that been possible, we wouldn't actually have used dynamic queries for that!
Instead you should use the variables to construct the dynamic query. Like this:
SET #SQLString = N'SELECT DISTINCT ' + QUOTENAME(#TableIDField) +
' FROM ' + QUOTENAME(#TableName);
Parameters are used to pass values, typically for use in filter conditions.

Resources