Printing dynamic SQL with parameter values - sql-server-2008

I want to print the SQL query which is used in the below stored procedure with parameter values. Currently it is printing the SQL query without parameter
values substitution while executing the stored procedure. It is printing the the parameters as it is (for example AND TP.F_LANGUAGE = #LANGUAGE)
CREATE PROCEDURE [dbo].[SEARCH]
#LANGUAGE VARCHAR(2),
#SUBFORMAT NVARCHAR(2000),
#ICO NVARCHAR(4000),
AS
SET NOCOUNT ON
DECLARE #sqlQuery AS NVARCHAR(MAX)
DECLARE #pdfQuery AS NVARCHAR(MAX)
DECLARE #htmlQuery AS NVARCHAR(MAX)
DECLARE #param AS NVARCHAR(3000)
DECLARE #paramDefinition AS NVARCHAR(3000)
DECLARE #AllSubformats AS SubformatType
DECLARE #InputSubformats AS SubformatType
INSERT INTO #AllSubformats(Val)
SELECT S.Val
FROM (SELECT IsNull(TLK.f_value, '') As FValue
FROM T_LOOKUP TLK
WHERE TLK.f_parent = 'WEBVIEWER_INT_SUB') TLV
CROSS APPLY dbo.dfnSplit(TLV.FValue, ',') S;
IF (#SUBFORMAT <> '-1')
BEGIN
INSERT INTO #InputSubformats(Val)
SELECT S.Val
FROM dbo.dfnSplit(#SUBFORMAT, ',') S
END;
SET #pdfQuery = 'SELECT TOP 1001 TP.F_PRODUCT AS ID,
TP.F_PRODUCT_NAME AS NAME,
FROM PDF_DETAILS TP '
WHERE TP.F_PRODUCT<>'''''
SET #param = ' AND TP.F_AUTHORIZED IN(1,3) AND EXISTS (SELECT 1 FROM #AllSubformats ASF WHERE ASF.Val = TP.F_SUBFORMAT)'
IF NOT(#LANGUAGE IS NULL OR #LANGUAGE = '')
SET #param = #param + ' AND TP.F_LANGUAGE = #LANGUAGE '
IF NOT(#SUBFORMAT IS NULL OR #SUBFORMAT = '')
SET #param = #param + ' AND EXISTS (SELECT 1 FROM #InputSubformats ISF WHERE ISF.Val = TP.F_SUBFORMAT) '
IF NOT(#ICO IS NULL OR #ICO = '')
SET #param = #param + ' AND (TP.F_ICO_DATA LIKE #ICO) '
SET #ParamDefinition = ' #SUBFORMAT NVARCHAR(2000),
#LANGUAGE VARCHAR(2), #ICO NVARCHAR(4000),#AllSubformats SubformatType READONLY, #InputSubformats SubformatType READONLY '
SET #sqlQuery = #pdfQuery + #param
EXECUTE SP_EXECUTESQL #sqlQuery, #paramDefinition, #SUBFORMAT, #LANGUAGE, #ICO, #AllSubformats, #InputSubformats
Print #sqlQuery
Please help.I want to debug and execute the SQL QUERY.

You could PRINT the result of a REPLACE function. You would need to nest a REPLACE for every parameter in the string:
PRINT REPLACE(
REPLACE(#sqlQuery, '#Parameter1', #Parameter1)
, '#Parameter2', #Parameter2
);
Note this assumes all of your parameters are string types. If any of them are non-string, you will need to CAST them to strings inside the REPLACE.

Related

Passing values to dynamic query in SQL Server procedure

CREATE TYPE TableVariable AS TABLE
(
id int identity(1,1),
field_ids INT,
value VARCHAR(MAX)
)
Type created successfully.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE Testing
(
#TableVar TableVariable READONLY,
#C_id INT
)
AS
Declare #maxPK INT;
Declare #pk INT;
Declare #fid INT;
Declare #val VARCHAR(max);
Declare #Where VARCHAR(max);
Declare #SQL VARCHAR(MAX);
Set #pk = 1
BEGIN
BEGIN TRY
SET NOCOUNT ON;
Select #maxPK = count(*) From #TableVar
SELECT #maxPK
SELECT #C_id
Set #SQL = 'SELECT DISTINCT v1.e_id from values v1 inner join listings l ON v1.e_id =
l.e_id WHERE l.c_id='+ #C_id
SELECT #SQL
While #pk <= #maxPK
BEGIN
SELECT #fid= field_ids FROM #TableVar where id=#pk;
SELECT #val= value FROM #TableVar where id=#pk;
SELECT #fid
SELECT #val
SET #SQL += ' and exists (select 1 from values v#pk+1 where v1.e_id = #pk+1.e_id and #pk+1.f_id=#fid and(value=#val))'
Select #pk = #pk + 1
END
SELECT #SQL
EXECUTE SP_EXECUTESQL #SQL
END TRY
BEGIN CATCH
END CATCH
END
DECLARE #DepartmentTVP AS TableVariable;
INSERT INTO #DepartmentTVP VALUES (14567, 'first')
INSERT INTO #DepartmentTVP VALUES (145678, 'second')
SELECT *
FROM #DepartmentTVP
EXEC Testing #DepartmentTVP, 83
I executed the above procedure.Values are not passed to the query
This is my orginal query
select distinct
v1.e_id
from
values v1
inner join
listings l on v1.e_id = l.e_id
where
l.c_id = 83
and exists (select 1
from values v2
where v1.e_id = v2.e_id
and v2.f_id = 1780
and (value = N'Peppermint Whole Care Toothpaste'))
and exists (select 1
from values v3
where v1.e_id = v3.e_id
and v3.f_id = 22483
and (value = N'sasdfa'))
order by
l.id desc
and exists part will add dynamically.
If you are wanting a variable to be part of the text such as:
'select 1 from values v#pk+1 where v1.e_id = #pk+1.e_id'
Then you need to escape the string and add the variable -- but beware this is prone to SQL Injection attacks if you don't strictly control the source of the variable data!
Example:
'select 1 from values v'+convert(varchar(15),#pk+1)+' where v1.e_id = '+convert(varchar(15),#pk+1)+'.e_id'
If you simply want to pass the variable into the string such as:
'and v5.f_id=#fid and(value=#val))'
Then you leave those variables unescaped, and pass them into sp_executesql
Example:
exec sp_executesql #SQL, N'#fid int, #val varchar(max)', #fid=#fid, #val=#val
More info on sp_executesql and its parameters:
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql

SQL Server - Unable to run cursor FETCH statement dynamically stored in variable

I've a cursor which fetch dynamic number of columns because the "SELECT STATEMENT" which I use to declare this cursor is dynamic.
Since I do not know at any point of time, how many columns this cursor will have, I cannot declare fixed number of variables into fetch.
So I have built FETCH statement as dynamic and stored in one #variable... but when i run fetch statement using EXEC sp_executesql
its failing with error ..Must declare the scalar variable "#objcursor".
I know that #objcursor variable is not accessible becasue while sp_executesql run which run on isolate THREAD
is there any way someone can advise, how to handle this code to run without an error?
Here is my T-SQL code:
/* ==== Variable Declaration ==== */
declare #AllValues nvarchar(max)
declare #objcursor as cursor
declare #MonthCount integer
declare
#vsql as nvarchar(max)
,#vquery as nvarchar(max)
,#id as int
,#value as varchar(50)
BEGIN
SELECT #AllValues = CASE
WHEN t.column_id=1 THEN
(COALESCE(#AllValues +'"', '')+ t.name)+'"'
WHEN t.column_id > 1 THEN
(COALESCE(#AllValues + ',"', '') + t.name)+'"'
END
FROM
(
SELECT sc.name, sc.column_id FROM sys.objects o
INNER JOIN sys.columns sc ON o.object_id = sc.object_id
WHERE o.name = 'temp_daywise' AND o.type = 'U' AND (sc.name like '%Curr Yr%' or column_id=1)
) AS t
ORDER BY t.column_id
SET #AllValues='SELECT "'+#AllValues+' FROM dbo.temp_daywise'
set #vquery = #AllValues
set #vsql = 'set #cursor = cursor forward_only static for ' + #vquery + ' open #cursor;'
exec sys.sp_executesql
#vsql
,N'#cursor cursor output'
,#objcursor output
---Handling Dynamic number of columns in a cursor, get the column count first and build FETCH statement dynamically
Select #CurCount=COUNT(*) from sys.columns where object_id in(
SELECT object_id from sys.objects where name = 'dbo.temp_daywise' and type = 'U' )
and (name like '%Curr Yr%');
SET #LoopCount = 1
--here building my fetch statement
SET #fetchsql ='fetch next from #objcursor into #AgreementID'
WHILE #LoopCount <= #CurCount
BEGIN
SET #fetchsql = #fetchsql+','+'#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)
SET #LoopCount = #LoopCount + 1
END
--EXEC #fetchsql
EXEC sp_executesql #fetchsql
while (##fetch_status = 0)
begin
BEGIN
'update ...here something'
END
EXEC #fetchsql
end
close #objcursor
deallocate #objcursor
END
Here is my data and expected resullts:
1) My dynamic cusror will read column name from sys.columns because coulmns are not static that's based on columns count I'm building FETCH statement. following code build cusrsor SELECT statement
SELECT #AllValues = CASE
WHEN t.column_id=1 THEN
(COALESCE(#AllValues +'"', '')+ t.name)+'"'
WHEN t.column_id > 1 THEN
(COALESCE(#AllValues + ',"', '') + t.name)+'"'
END
FROM
(
SELECT sc.name, sc.column_id FROM sys.objects o
INNER JOIN sys.columns sc ON o.object_id = sc.object_id
WHERE o.name = 'temp_daywise' AND o.type = 'U' AND (sc.name like '%Curr Yr%' or column_id=1)
) AS t
ORDER BY t.column_id
SET #AllValues='SELECT "'+#AllValues+' FROM dbo.temp_daywise'
set #vquery = #AllValues
set #vsql = 'set #cursor = cursor forward_only static for ' + #vquery + ' open #cursor;'
exec sys.sp_executesql
#vsql
,N'#cursor cursor output'
,#objcursor output
2) I want to update fetch data into following table for columns Day1...Day31. if cusrsor found 20 columns data will update until CY_Day20.
3) In short, i do not know the cusror retrieving columns at design time so i can't produce fetching variable. Since columns are known at run tiume, i have to build fetch & update statment in while loop as like below:
Note: ignore DECLARE which is on start of the code... but i placed here to get an idea.
DECLARE
#CY_Day1 Numeric(18,2), #CY_Day2 Numeric(18,2), #CY_Day3 Numeric(18,2), #CY_Day4 Numeric(18,2), #CY_Day5 Numeric(18,2),
, #CY_Day7 Numeric(18,2), #CY_Day8 Numeric(18,2), #CY_Day9 Numeric(18,2), #CY_Day10 Numeric(18,2), #PY_Day10 Numeric(18,2), #CY_Day11 Numeric(18,2), #CY_Day12 Numeric(18,2),........ #CY_Day31 Numeric(18,2)
Select #CurCount=COUNT(*) from sys.columns where object_id in(
SELECT object_id from sys.objects where name = 'dbo.temp_daywise' and type = 'U' )
and (name like '%Curr Yr%');
SET #LoopCount = 1
SET #fetchsql ='fetch next from #objcursor into #AgreementID'
SET #updatesql ='UPDATE dbo.TPDD_Report_Monthly_Details SET '
WHILE #LoopCount <= 2
BEGIN
SET #fetchsql = #fetchsql+','+'#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)
SET #updatesql= #updatesql +'CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+' = #CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+',CY_TPDD_Day'+CONVERT(VARCHAR(2),#LoopCount)+' = (#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+'/1/1),'
SET #LoopCount = #LoopCount + 1
END
SET #updatesql =#updatesql + ' dss_update_time = #v_dss_update_time WHERE AgreementId = #AgreementID and TpddYear=CONVERT(VARCHAR(4),#Current_year)+CONVERT(VARCHAR(4),#Previous_year) and Running_Month = #MonthNo'
--EXEC #fetchsql
PRINT #fetchsql
PRINT #updatesql
---executing FETCH statement
EXEC sp_executesql #fetchsql
while (##fetch_status = 0)
begin
BEGIN
---updating table columns
EXEC sp_executesql #updatesql
END
EXEC #fetchsql
end
close #objcursor
deallocate #objcursor
Finally my cusrsor fetch & udpate statement will looks like below:
fetch next from #objcursor into #AgreementID,#CY_Day1,#CY_Day2,#CY_Day3,#CY_Day4,#CY_Day5,#CY_Day6,#CY_Day7,#CY_Day8,#CY_Day9,#CY_Day10
UPDATE dbo.TPDD_Report_Monthly_Details SET
CY_Day1 = #CY_Day1, CY_TPDD_Day1 = (#CY_Day1/1/1),
CY_Day2 = #CY_Day2, CY_TPDD_Day2 = (#CY_Day2/1/1),
CY_Day3 = #CY_Day3, CY_TPDD_Day3 = (#CY_Day3/1/1),
CY_Day4 = #CY_Day4, CY_TPDD_Day4 = (#CY_Day4/1/1),
CY_Day5 = #CY_Day5, CY_TPDD_Day5 = (#CY_Day5/1/1),
CY_Day6 = #CY_Day6, CY_TPDD_Day6 = (#CY_Day6/1/1),
CY_Day7 = #CY_Day7, CY_TPDD_Day7 = (#CY_Day7/1/1),
CY_Day8 = #CY_Day8, CY_TPDD_Day8 = (#CY_Day8/1/1),
CY_Day9 = #CY_Day9, CY_TPDD_Day9 = (#CY_Day9/1/1),
CY_Day10 = #CY_Day10, CY_TPDD_Day10 = (#CY_Day10/1/1),
dss_update_time = #v_dss_update_time
WHERE AgreementId = #AgreementID
Hope I;m able to present my problem correctly.
I have a good start. You're probably going to have to tweak a few things. I did my best to get it as close as possible as your actual situation. Hope this helps. If you have any questions, let me know.
NOTE I USE THE SAME TABLE NAMES AND DROP THEM.
IF OBJECT_ID('dbo.temp_daywise') IS NOT NULL
DROP TABLE dbo.temp_daywise;
IF OBJECT_ID('dbo.TPDD_report_Monthly_Details') IS NOT NULL
DROP TABLE dbo.TPDD_report_Monthly_Details;
CREATE TABLE dbo.temp_daywise
(
AgreementID CHAR(6),
RunningMonth INT,
[Curr Yr1] VARCHAR(100),
[Curr Yr2] VARCHAR(100),
[Curr Yr3] VARCHAR(100)
);
INSERT INTO temp_daywise
VALUES ('A10001',3,'col1_1','col2_1','col3_1'),
('A10003',3,'col1_2','col2_2','col3_2'),
('A10006',3,'col1_3','col2_3','col3_3'),
('A10008',3,'col1_4','col2_4','col3_4');
CREATE TABLE dbo.TPDD_report_Monthly_Details
(
TpddYear DATE,
AgreementID CHAR(6),
RunningMonth INT,
[CY_Day1] VARCHAR(100),
[CY_Day2] VARCHAR(100),
[CY_Day3] VARCHAR(100)
);
INSERT INTO TPDD_report_Monthly_Details
VALUES ('20131220','A10001',3,NULL,NULL,NULL),
('20131220','A10003',3,NULL,NULL,NULL),
('20131220','A10006',3,NULL,NULL,NULL),
('20131220','A10008',3,NULL,NULL,NULL);
--Now that I've created my versions of your table, here's the actual code
--Variable to hold columns that need to be updated
DECLARE #ColToBeUpdated VARCHAR(MAX);
--Gets your column information for temp_daywise
WITH CTE_temp_daywise_Cols
AS
(
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'temp_daywise'
)
--Now join temp_daywise columns to TPDD_report columns
--QUOTENAME() add's brackets [] around each column
SELECT #ColToBeUpdated = COALESCE(#ColToBeUpdated + ',','') + QUOTENAME(A.COLUMN_NAME) + ' = B.' + QUOTENAME(B.COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS A
INNER JOIN CTE_temp_daywise_Cols B
--The "+1" compensates for difference in ordinal positions
ON A.Ordinal_Position = B.ORDINAL_POSITION + 1
--This makes the table alisaed A to only get columns for TPDD_report
WHERE A.TABLE_NAME = 'TPDD_report_Monthly_Details'
--Don't return AgreementID
AND A.COLUMN_NAME != 'AgreementID'
AND B.COLUMN_NAME != 'AgreementID'
ORDER BY A.ORDINAL_POSITION
--Variable to hold code
DECLARE #sql VARCHAR(MAX);
SELECT #sql = 'UPDATE dbo.TPDD_Report_Monthly_Details
SET ' + #ColToBeUpdated +'
FROM dbo.TPDD_Report_Monthly_Details AS A
INNER JOIN temp_daywise AS B
ON A.AgreementID = B.AgreementID'
--Look at code
--Notice you can join on AgreementID and just set the columns equal to each other
SELECT #sql;
--To execute
--EXEC(#sql)
Results stored in #sql:
UPDATE dbo.TPDD_Report_Monthly_Details
SET [RunningMonth] = B.[RunningMonth],
[CY_Day1] = B.[Curr Yr1],
[CY_Day2] = B.[Curr Yr2],
[CY_Day3] = B.[Curr Yr3]
FROM dbo.TPDD_Report_Monthly_Details AS A
INNER JOIN temp_daywise AS B
ON A.AgreementID = B.AgreementID

Something equivalent to "SELECT * FROM (SELECT table_name FROM...)"?

This query runs, but it produces the name of a table as a result, rather than actually selecting from that table.
SELECT T.*
FROM (SELECT tablename
FROM ListOfTables
WHERE id = 0) AS T
where ListOfTables contains id=0, tablename='some_table', I want to return the same result set as if I had written this directly:
SELECT * FROM some_table
Is there a native way to do this in MySQL 5, or do I have to do in in the application?
To do this in MySQL, you need to create a prepared statement which you can only create from a user variable:
SELECT #tn := tablename FROM ListOfTables WHERE id = 0;
SET #qs = CONCAT('SELECT * FROM ', #tn);
PREPARE ps FROM #qs;
EXECUTE ps;
You need to use dynamic SQL to get this result (the below code assumes SQL Server, I can't speak for other RDBMS').
declare #tableName varchar(100)
declare #query varchar(500)
select #tableName = tablename
from ListOfTables
where id = 0
select #query = 'select * from ' + #tableName
exec (#query)
Almost the same as #Shark's answer, except you also quote the name of the table to avoid syntax errors.
-- Using variables just for better readability.
DECLARE #Name NVARCHAR(4000)
DECLARE #Query NVARCHAR(4000)
-- Get the relevant data
SET #Name = QUOTENAME(SELECT tablename FROM ListOfTables WHERE id=0)
-- Build query
SET #Query = 'SELECT * FROM ' + #Schema + '.' + #Name + ''
-- execute it.
EXEC(#Query)

SQL Parameter as part of a query

I want to use a parameter value as a part of query, like this:
SELECT * FROM SOME_TABLE WHERE #PARAM
Where #PARAM = "ID = 1"
Is this even possible?
Declare #query Varchar(max)
Set #query = 'SELECT * FROM table WHERE ' + #parameter
exec(#query)
i dont remember syntex but u can do something like this.
Yes it is, you just need to use dynamic SQL:
http://www.codeproject.com/Articles/20815/Building-Dynamic-SQL-In-a-Stored-Procedure
DECLARE #SQLQuery AS NVARCHAR(500)
SET #SQLQuery = 'SELECT * FROM table WHERE ' + #PARAMS
EXECUTE sp_executesql #SQLQuery
dynamic SQL has some downfalls that you should be aware of, if you wanna use it, read this article for more details:
http://www.sommarskog.se/dynamic_sql.html
The other answers appear to be more-or-less correct, but here's a complete example that you can try yourself:
/* We'll want two different variables--one
for the query as a whole, one for the
parameter.
*/
DECLARE #sSql VARCHAR(MAX),
#sParm VARCHAR(MAX);
----------------------------------------------------
/* Build a temp table for demonstration ... */
IF OBJECT_ID('tempdb..#table') IS NOT NULL BEGIN
DROP TABLE #table
END
CREATE TABLE #table (
[Id] INT IDENTITY PRIMARY KEY,
[Name] VARCHAR(100),
[Value] INT
)
INSERT INTO #table (Name, Value) VALUES ('Test1', 1)
INSERT INTO #table (Name, Value) VALUES ('Test2', 2)
----------------------------------------------------
/* Our complete query is some base plus the input
parameter
*/
SELECT #sParm = 'Id = 1';
SELECT #sSql =
'SELECT
t.[Name],
t.[Value]
FROM #table t WITH (NOLOCK)
WHERE ' + #sParm + ''
EXEC(#sSQL)

Conversion failed when converting the nvarchar value 'SELECT * FROM

Using Sql Server 2008, developed a view "vw_MasterView" I get this error:
Conversion failed when converting the nvarchar value 'SELECT * FROM VW_MASTERVIEW v WHERE 1=1 AND v.ClinicId = '' to data type int.
when I run the following stored procedure:
USE [xxxxxxx]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ClientSummary1]
#LocationId int,
#startDate datetime,
#endDate datetime,
#userName nvarchar(50)
AS
declare #sql nvarchar(2000);
SET NOCOUNT ON
set #sql = 'SELECT * FROM VW_MASTERVIEW v WHERE 1=1 ';
IF #LocationId is not null
begin
set #sql = #sql + ' AND v.LocationId = ''' + #LocationId + '''';
end
if #userName is not null
begin
set #sql = #sql + ' AND (v.FirstUser = '' OR v.SecondUser = '')' + #userName + '''';
end
if #startDate is not null
begin
set #sql = #sql + ' AND v.FirstVisitDate = ''' + #startDate + '''';
end
if #endDate is not null
begin
set #sql = #sql + ' AND v.LastVisitDate = ''' + #endDate + '''';
end
EXEC(#sql)
I get both the LocationId and userName from a VS2010 application.
Thanks in Advance
When appending strings together in SQL Server, you have to cast non-textual types (such as int) to a textual type (such as varchar):
set #sql = #sql + ' AND v.LocationId = ''' +
cast(#LocationId as varchar(10)) + '''';
-- ^^^^ have to cast ^^ make sure size is big enough
Note that dynamic SQL should not be necessary in the first place. You can just run the query directly with the parameters (I implemented the null checks with the extra or conditions):
SELECT * FROM VW_MASTERVIEW v
WHERE (v.LocationId = #LocationId OR #LocationId is null)
AND (v.FirstUser = #userName OR v.Seconduser = #userName OR #userName is null)
AND (v.FirstVisitDate = #startDate OR #startDate is null)
AND (v.LastVisitDate = #endDate OR #endDate is null)
I may not have the logic right for FirstUser and SecondUser - I took an educated guess from your incomplete code.
Hope this helps!