Dynamic sql is giving syntax error. - sql

I am executing the following sql. I get a syntax error which is (Incorrect syntax near '=')
The query executes fine and gives proper results when executed normally. couldn't understand. plz take a look.
DECLARE #pvchMachineId VARCHAR(100) = ''
DECLARE #pvchMake VARCHAR(100) = ''
DECLARE #sql NVARCHAR(1000)
SELECT #sql = ' SELECT TOP 20 x.intId, x.vchMachineId, x.AUDenom, x.intGroupId,
x.vchMake, x.vchModel, x.mCurrency
from dbo.Machine x
inner join
(select max(m1.AUDenom) as audenom, m1.vchMachineId
from dbo.Machine m1
left JOIN dbo.ImportedFile ife on m1.intImportedFileId = ife.intId
WHERE ife.dtFileDate >= ''1-1-2013'' AND ife.dtFileDate <= ''1-29-2014'' AND
--following two lines cause the error
(' + #pvchMake + '= ''0'' OR m1.vchMake = #pvchMake) AND
(' + #pvchMachineId +'= ''0'' OR m1.vchMachineId = #pvchMachineId)
group by vchMachineId) y
on x.AUDenom = y.audenom and x.vchMachineId = y.vchMachineId
ORDER BY x.AUDenom DESC'

Update your query to the following
(#pvchMake = ''0'' OR m1.vchMake = #pvchMake) AND
(#pvchMachineId = ''0'' OR m1.vchMachineId = #pvchMachineId)
than later when you go to execute just pass it in as parameters to sp_executesql function.
EXEC sp_executesql #sql
,N'#pvchMachineId VARCHAR(100), #pvchMake VARCHAR(100)'
,#pvchMachineId,#pvchMake
or this which is cleaner
Declare #ParametersDefinition NVARCHAR(max) = N'#pvchMachineId VARCHAR(100), #pvchMake VARCHAR(100)'
EXEC sp_executesql #sql, #ParametersDefinition, #pvchMachineId,#pvchMake
In the end you do not want to concatenate your dynamic SQL statement, it opens it up for SQL Injections. Even though it is a valid option it should be avoided at all cost.

This statement :
'(' + #pvchMake + '= ''0'' OR m1.vchMake = #pvchMake)'
Will output, since the variables are not initialized by anything else than '' :
(= '0' OR m1.vchMake = #pvchMake)
Which is not correct syntaxically.
You should use :
'(''' + #pvchMake + '''= ''0'' OR m1.vchMake = #pvchMake)'
Which would output :
(''= '0' OR m1.vchMake = #pvchMake)

Maybe this can make sense:
...
(''' + #pvchMake + '''= ''0'' OR m1.vchMake = ''' + #pvchMake +''') AND
(''' + #pvchMachineId +'''= ''0'' OR m1.vchMachineId = ''' + #pvchMachineId + ''')
...

Related

How to use integer variable in Dynamic Query

I have created the below dynamic query to check if length of particular attribute is more than 50 or not. I am trying to make the length size also dynamic but getting below error.
Msg 207, Level 16, State 1, Line 7
Invalid column name '50'.
The query I came up with is as below. I am pretty new to SQL and trying to resolve this error. Thanks!
--Rule A.5.Summary :- Length
/* The 'DECLARE' statements below are used to
define standard test parameters and their datatypes. The values for these
parameters will be updated for each of the DQ dimensions/KDEs being tested */
DECLARE #DQ_DIMENSION_RULE VARCHAR(100)
DECLARE #RULE_NO VARCHAR(100)
DECLARE #TABLE_NAME VARCHAR(100)
DECLARE #DATA_ATTRIBUTE VARCHAR(100)
DECLARE #LENGTH_SIZE INT
/*The 'SET' statements below are used to
assign values to each of the test parameters declared above.
The values will depend on the DQ dimension/KDE being tested.*/
SET #DQ_DIMENSION_RULE = 'Accuracy - Negative Values'
SET #RULE_NO = 'A.4'
SET #TABLE_NAME = 'TRANSACTIONS'
SET #DATA_ATTRIBUTE = 'TRANSACTIONID'
SET #LENGTH_SIZE = 50
DECLARE #sql nvarchar(max) = N'
SELECT
' + QUOTENAME(#DQ_DIMENSION_RULE, '''') + N' AS [DQ_Dimension_Rule],
' + QUOTENAME(#RULE_NO, '''') + N' AS [Rule_No],
' + QUOTENAME(#TABLE_NAME, '''') + N' AS [Table Name],
' + QUOTENAME(#DATA_ATTRIBUTE, '''') + N' AS [Column Name],
case when SUM(CASE WHEN LEN(' + QUOTENAME(#DATA_ATTRIBUTE) + N') >' + QUOTENAME(#LENGTH_SIZE) + N' THEN 1 ELSE 0 END) > 0 then ''Y'' else ''N'' end as [Potential Issue(Y/N)]
FROM ' + QUOTENAME(#TABLE_NAME)
-- The data from 'SELECT' statement is being inserted into the summary table
--INSERT INTO summary
EXEC sp_executesql #sql;
You should not put QUOTENAME() around the integer values, the integers are not table names that you need to quote, etc.
You should just convert the integers to strings, without quotes...
DECLARE #sql nvarchar(max) = N'
SELECT
' + QUOTENAME(#DQ_DIMENSION_RULE, '''') + N' AS [DQ_Dimension_Rule],
' + QUOTENAME(#RULE_NO, '''') + N' AS [Rule_No],
' + QUOTENAME(#TABLE_NAME, '''') + N' AS [Table Name],
' + QUOTENAME(#DATA_ATTRIBUTE, '''') + N' AS [Column Name],
case when SUM(CASE WHEN LEN(' + QUOTENAME(#DATA_ATTRIBUTE) + N') >' + CAST(#LENGTHSIZE AS NVARCHAR(MAX)) + N' THEN 1 ELSE 0 END) > 0 then ''Y'' else ''N'' end as [Potential Issue(Y/N)]
FROM ' + QUOTENAME(#TABLE_NAME)
QUOTENAME(#LENGTHSIZE) => CAST(#LENGTHSIZE AS NVARCHAR(MAX))
Better than injecting it, parametrise it:
DECLARE #DQ_DIMENSION_RULE VARCHAR(100);
DECLARE #RULE_NO VARCHAR(100);
DECLARE #TABLE_NAME sysname; --Correct data type for object names
DECLARE #DATA_ATTRIBUTE VARCHAR(100);
DECLARE #LENGTH_SIZE INT;
SET #DQ_DIMENSION_RULE = 'Accuracy - Negative Values';
SET #RULE_NO = 'A.4';
SET #TABLE_NAME = 'TRANSACTIONS';
SET #DATA_ATTRIBUTE = 'TRANSACTIONID';
SET #LENGTH_SIZE = 50;
DECLARE #sql nvarchar(max) = N'
SELECT
' + QUOTENAME(#DQ_DIMENSION_RULE, '''') + N' AS [DQ_Dimension_Rule],
' + QUOTENAME(#RULE_NO, '''') + N' AS [Rule_No],
N' + QUOTENAME(#TABLE_NAME, '''') + N' AS [Table Name],
' + QUOTENAME(#DATA_ATTRIBUTE, '''') + N' AS [Column Name],
case when SUM(CASE WHEN LEN(' + QUOTENAME(#DATA_ATTRIBUTE) + N') > #LENGTH_SIZE THEN 1 ELSE 0 END) > 0 then ''Y'' else ''N'' end as [Potential Issue(Y/N)]
FROM ' + QUOTENAME(#TABLE_NAME) + N';';
EXEC sys.sp_executesql #sql, N'#LENGTH_SIZE int', #LENGTH_SIZE;
I've also changed the data type of your dynamic object and ensured that it the literal string is injected with a nvarchar notation character too.

SQL - Dynamic Condition in Where Clause

I have the following stored proc. The issue I'm having is with the "conditions" parameter. Basically each condition is its own column so it it passed in like this-
#Conditions = ' AND hcc_108 = 1 AND ...' etc.
I'm trying to do something like this-
ALTER PROC [dbo].[GetPatientPanelList]
(
#CareProviderId int=null,
#Patient nvarchar(60)=null,
#Conditions varchar=null,
#LocationId int=null
)
AS
if #Conditions is null
SELECT *
FROM vw_patient_attributes t1
INNER JOIN STG_OSHODS_DW.osh_rpt.dim_member_care_measures t2
ON t1.PatientID = t2.emr_id
WHERE
(t1.PreferredServiceLocationID = #LocationId OR #LocationId IS NULL)
AND (t1.CareProviderID = #CareProviderId OR #CareProviderId IS NULL)
AND (t1.FullName like '%' + #Patient + '%' OR #Patient IS NULL)
else
SELECT *
FROM vw_patient_attributes t1
INNER JOIN STG_OSHODS_DW.osh_rpt.dim_member_care_measures t2
ON t1.PatientID = t2.emr_id
WHERE
(t1.PreferredServiceLocationID = #LocationId OR #LocationId IS NULL)
AND (t1.CareProviderID = #CareProviderId OR #CareProviderId IS NULL)
AND (t1.FullName like '%' + #Patient + '%' OR #Patient IS NULL)
+ #Conditions
I just need the last AND condition to populate based off the parameter. I understand that the " + " is the syntax error but I can't seem to figure out a way on how to implement this.
Thanks!
Update
I have tried dynamic sql but it keeps saying "Command(s) completed successfully)"
Here is my current code. I wrote this in a separate window to first get the query to work.
DECLARE #where nvarchar(50) = ' and hcc_18 = 1'
,#sql nvarchar(MAX) ,
#CareProviderId int=null,
#Patient nvarchar(60)=null,
#LocationId int=null
set #sql = 'select *
FROM vw_patient_attributes t1
INNER JOIN STG_OSHODS_DW.osh_rpt.dim_member_care_measures t2
ON t1.PatientID = t2.emr_id
WHERE t1.PreferredServiceLocationID = IsNull('+ convert(varchar,#LocationId) +',t1.PreferredServiceLocationID)
AND (t1.CareProviderID = isnull(' + convert(varchar,#CareProviderId)+ ', t1.CareProviderID)
AND (t1.FullName like %' + #Patient + '% OR ' + #Patient + ' IS NULL)' + #where
exec(#sql)
I fixed the syntax issues in your last updated. This should work...
DECLARE #where nvarchar(50) = ' and hcc_18 = 1'
,#sql nvarchar(MAX) ,
#CareProviderId int=null,
#Patient nvarchar(60)=null,
#LocationId int=null
set #sql = 'select *
FROM vw_patient_attributes t1
INNER JOIN STG_OSHODS_DW.osh_rpt.dim_member_care_measures t2
ON t1.PatientID = t2.emr_id
WHERE t1.PreferredServiceLocationID = case when '+ convert(varchar(8),isnull(#LocationId,0)) +' = 0 then t1.PreferredServiceLocationID else ' + convert(varchar,isnull(#LocationId,0)) + ' end
AND (t1.CareProviderID = case when ' + convert(varchar,isnull(#CareProviderId,0)) + ' = 0 then t1.CareProviderID else ' + convert(varchar,isnull(#CareProviderId,0)) + ' end
AND (t1.FullName like ''%' + isnull(#Patient,'') + '%'' OR ' + isnull(#Patient,0) + '=0)' + #where
print(#sql)
--exec(#sql)
Check my answer at
No need to use ad-hoc query (just execute SP_ExecuteSQL)
Check below logic, you can use N number of dynamic / un-sure parameters / conditions........

Dynamic vs Static SQL with multiple conditions

The "Where" clause of my SQL will vary depending on the values provided. I wrote 2 versions (Dynamic and static). I read that Dynamic is the way to go if we have multiple parameters with a variable where clause. Also, this is just a sample, my real SQL has many more conditions, but something along these lines. Which among the two is the right choice for this scenario?
Dynamic SQL:
DECLARE #SQL NVARCHAR(max)='SELECT ID,Name,sex,street,city,state,zip,phone FROM Test';
DECLARE #whereSql VARCHAR(2000) = 'WHERE city= #City';
DECLARE #OrderBy VARCHAR(2000) = 'order by name';
IF(#Name IS NOT NULL)
BEGIN
SET #Name = #Name + '%'
SET #whereSql = #whereSql + ' ' + 'AND name like #Name';
end
IF(#Gender IS NOT NULL)
BEGIN
SET #whereSql = #whereSql + ' ' + 'AND sex =' + '#Gender';
END
IF(#Address IS NOT NULL)
BEGIN
SET #Address = '%' + #Address + '%'
SET #whereSql = #whereSql + ' ' + 'AND street like ' + '#Address';
END
SET #SQL = #SQL +' ' + #whereSql + ' '+ #OrderBy;
EXEC sp_executesql #SQL, N'#Gender VARCHAR(10), #Name VARCHAR(200), #Address VARCHAR(250)', #Gender,#Name,#Address;
Static SQL:
SELECT ID,Name,sex,street,city,state,zip,phone FROM Test T1 WHERE
(#Name IS NULL OR (T1.Name LIKE +'%'+ #Name + '%'))
AND
(#Gender is null OR (T1.sex = #Gender))
AND
(#Address is null or (T1.street LIKE +'%'+ #Address + '%'))

How to from query escaping comma and other special character in SQL Server stored procedure

I have a function which returns the comma separate values, but when I use
COALESCE(#Jiraids + ', ', '')
I get an error.
ALTER FUNCTION [dbo].[getCommonJiraIds](
#selct varchar(100),
#whereClause varchar(100),
#id varchar(100),
#TEST_RESULT_INFO_ID varchar(20) )
RETURNS varchar(max)
AS
BEGIN
DECLARE #Jiraids VARCHAR(8000)
DECLARE #sql varchar(max)
SET #whereClause = 'dbo.SNSTestResults.JIRA_ID <> '' AND dbo.SNSTestResults.'+#whereClause+ ''+ QUOTENAME(#id,'''') + 'AND dbo.SNSTestResults.Test_result_info_ID_FK LIKE '+QUOTENAME(#TEST_RESULT_INFO_ID,'''')
SET #sql = 'Select #Jiraids = COALESCE(#Jiraids + '', '', '') + case when (#selct LIKE Jira_ID_Maped) then Jira_ID_Maped else Jira_ID end
FROM dbo.TestCaseList INNER JOIN dbo.SNSTestResults ON dbo.TestCaseList.TestCaseListID = dbo.SNSTestResults.TestCaseListID_FK'
set #sql = #sql + #WhereClause
EXEC #sql
RETURN ( select #Jiraids);
END
When I execute the above function I got this error:
Msg 203, Level 16, State 2, Procedure GetDailyCrJiraTable, Line 159
The name 'Select #Jiraids =COALESCE(#Jiraids + ', ', ') + case when (#selct LIKE Jira_ID_Maped) then Jira_ID_Maped else Jira_ID end FROM dbo.TestCaseList INNER JOIN dbo.SNSTestResults ON dbo.TestCaseList.TestCaseListID = dbo.SNSTestResults.TestCaseListID_FKdbo.SNSTestResults.JIRA_ID <> ' AND dbo.SNSTestResults.Jira_ID_Maped'UIBUG-4533'AND dbo.SNSTestResu' is not a valid identifier.
Somebody please help me to fix this issue.
SET #whereClause = 'dbo.SNSTestResults.JIRA_ID <> '''' AND dbo.SNSTestResults.'+#whereClause+ ''+ QUOTENAME(#id,'''') + 'AND dbo.SNSTestResults.Test_result_info_ID_FK LIKE '+QUOTENAME(#TEST_RESULT_INFO_ID,'''')
you need more ' after dbo.SNSTestResults.JIRA_ID <>
You have to add more ' to your COALESCE function as below
Select #Jiraids = COALESCE(#Jiraids + '', '', '''')
and as I said in comment you have to change this dbo.SNSTestResults.JIRA_ID <> ''
to dbo.SNSTestResults.JIRA_ID <> '''' AND
ALTER FUNCTION [dbo].[getCommonJiraIds](
#selct varchar(100),
#whereClause varchar(100),
#id varchar(100),
#TEST_RESULT_INFO_ID varchar(20) )
-- your four inputs
RETURNS varchar(max)
AS
BEGIN
DECLARE #Jiraids VARCHAR(8000)
DECLARE #sql varchar(max)
SET #whereClause = 'dbo.SNSTestResults.JIRA_ID <> ''
AND dbo.SNSTestResults.'+#whereClause+ ''+ QUOTENAME(#id,'''')
+ 'AND dbo.SNSTestResults.Test_result_info_ID_FK LIKE '+QUOTENAME(#TEST_RESULT_INFO_ID,'''')
you do not know it yet, but your Query does not actually have a WHERE clause written in.
I hope you are not actually expecting the programmer to write extra
code in your function everytime it is used.
SET #sql = 'Select #Jiraids = COALESCE(#Jiraids + '', '', '') + case when (#selct LIKE Jira_ID_Maped) then Jira_ID_Maped else Jira_ID end
FROM dbo.TestCaseList INNER JOIN dbo.SNSTestResults ON dbo.TestCaseList.TestCaseListID = dbo.SNSTestResults.TestCaseListID_FK
Your #selct has not been correctly identified. SQL SERVER cannot know
at compile time that it is a #variable.
Also, are you sure your function will only return one row? In some cases, being explicit about the expected occurrence (should someone actually use a '%' in their PREDICATE) can prevent a future breakdown in the code.
set #sql = #sql + #WhereClause
EXEC #sql
Thankfully, SO exists to help people out. :D
A correct version could be like the following:
ALTER FUNCTION [dbo].[getCommonJiraIds](
#selct varchar(100),
#whereClause varchar(100),
#id varchar(100),
#TEST_RESULT_INFO_ID varchar(20) )
-- your four inputs
RETURNS varchar(max)
AS
BEGIN
DECLARE #Jiraids VARCHAR(8000)
DECLARE #sql varchar(max)
SET #sql = '
Select #Jiraids = TOP 1 COALESCE(#Jiraids + '', '', '') + CASE WHEN (' + #selct + ' = Jira_ID_Maped)
THEN Jira_ID_Maped
ELSE Jira_ID END
FROM dbo.TestCaseList
INNER JOIN dbo.SNSTestResults ON dbo.TestCaseList.TestCaseListID = dbo.SNSTestResults.TestCaseListID_FK'
SET #whereClause = 'WHERE dbo.SNSTestResults.JIRA_ID <> ''
AND dbo.SNSTestResults.'+#whereClause+ ''+ QUOTENAME(#id,'''')
+ 'AND dbo.SNSTestResults.Test_result_info_ID_FK LIKE '+QUOTENAME(#TEST_RESULT_INFO_ID, '')
set #sql = #sql + #WhereClause
EXEC #sql
RETURN ( select #Jiraids);
END

best approach to execute a dynamic query inside a SP

I'm having some trouble executing a dynamic query inside my SP, and I thought asking for some help as I can't execute it correctly no matter what I try:
I have tried:
SET #subWorksQuery =
'UPDATE JK_SubscriberWorks SET ' +
'update_date = convert(datetime, ''' + #dateNow + ''', 103), ' +
'challenge_' + convert(nvarchar(2), #challengeDay) + '_q = ''' + #challengeQuestion + ''', ' +
'challenge_' + convert(nvarchar(2), #challengeDay) + '_a = ''' + #challengeAnswer + ''' ' +
'WHERE subscriberwork_id = '' + convert(nvarchar(10), #subscriberWorksId) + '';';
execute #execReturn = #subWorksQuery
but I always get:
Msg 203, Level 16, State 2, Procedure sp_InsertChallengeResponse_test,
Line 112
The name 'UPDATE JK_SubscriberWorks SET update_date = convert(datetime, '23-12-2011 23:35:17', 103), challenge_23_q =
'Hvilket år blev Klasselotteriet omdannet til et aktieselskab? Få hjælp til svaret.',
challenge_23_a = '1992' WHERE subscriberwork_id = ' +
convert(nvarchar(10), #subscriberWorksId) + ';' is not a valid
identifier.
Removing the UPDATE statement from that error and run it independently, it runs and performs the update
If I use sp_executesql like
SET #subWorksQuery =
N'UPDATE JK_SubscriberWorks SET ' +
'update_date = #a, ' +
'challenge_' + convert(nvarchar(2), #challengeDay) + '_q = #b, ' +
'challenge_' + convert(nvarchar(2), #challengeDay) + '_a = #c ' +
'WHERE subscriberwork_id = #d;';
SET #parmDefinition = N'#a datetime, #b nvarchar(250), #c nvarchar(500), #d decimal';
execute sp_executesql
#subWorksQuery,
#parmDefinition,
#a = #CreateDate, #b = #challengeQuestion, #c = #challengeAnswer, #d = #subscriberWorksId;
It never performs the UPDATE, but does not throw any error.
What am I missing here?
Run it like this:
execute (#subWorksQuery)
[you won't be getting anything back from the update statement in the variable, and you can't run like this execute (#execReturn = #subWorksQuery) ]
Without parentheses it seems to be starting parsing, assuming it is a stored procedure name, but failing when it hits the max length for one.
In saying that, it is better to use sp_executesql with parameters.
I am not sure what you are looking for in the return value, but if you just need the count of rows affected, that should be easy to obtain.
Change:
execute #execReturn = #subWorksQuery
to:
execute (#subWorksQuery)
select #execReturn = ##ROWCOUNT
just a thought...your #d parameter is a decimal value. Is your id an int? is there a possible data type conflict?
how are your sp input parameters defined? Could you post the full sp?
Dave