Syntax error escaping string in SQL Server stored procedure - sql-server

I am new to SQL Server 2012 and have read in lots of places that we only need to escape the single-quote character, by doubling it up. In most cases this seems to work for me, but I am having particular trouble with the following simple stored procedure:
DECLARE #SQLStr nvarchar(max)
DECLARE #SQLParam nvarchar(max)
DECLARE #SQLParamValues nvarchar(max)
SET #SQLStr = 'UPDATE test_data SET name=#1,name_reservation_date=#2 WHERE id=#3'
SET #SQLParam = '#1 nvarchar(50),#2 datetime2(0),#3 bigint'
SET #SQLParamValues = '#1=N''b''1'',#2=''2014-4-25 12:09:39'',#3=12345'
EXEC( 'EXECUTE sp_executesql N''' + #SQLStr + ''', N''' + #SQLParam + ''', ' + #SQLParamValues)
The error that I am getting is this:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '1'.
Msg 105, Level 15, State 1, Line 1
Unclosed quotation mark after the character string ',#3=12345'.
And the problem is that I am trying to write the value b'1, which I have escaped as b''1. If I write just b1 then there is no problem.
The syntax error is on the last line - i.e. when trying to use the #SQLParamValues string as an argument to my EXEC call.
But I can't see any unclosed quotation mark, can someone help me out? Is there a better approach that I should be taking, to avoid all of these doubling-up of quotes? I've inherited this system from someone else so I'm not entirely convinced at this stage.

You don't need to wrap sp_executesql in another EXEC. Use the syntax below. Note that the parameters' values are passed without a variable:
DECLARE #SQLStr nvarchar(max)
DECLARE #SQLParam nvarchar(max)
SET #SQLStr = N'UPDATE test_data SET name=#1,name_reservation_date=#2 WHERE id=#3'
SET #SQLParam = N'#1 nvarchar(50),#2 datetime2(0),#3 bigint'
EXECUTE sp_executesql #SQLStr, #SQLParam,
#1=N'b''1',#2='2014-4-25 12:09:39',#3=12345

Related

Executing large SQL Queries

I am trying to execute a dynamically created query using FORMATMESSAGE SQL function, and when I do that I get an error
Incorrect syntax near '.'
which I am assuming is because of the trimmed SQL query created.
set #sql = FORMATMESSAGE('insert into %s (imported_on, source_filename, md5_hash %s) select GETDATE(), ''%s'', ''%s'' %s from %s',
#target_tablename, #columns, #source_filename, 'TODO', #columns, #source_table);
exec (#sql);
There is a long list of columns that #columns variable holds ~ 300 (columns) and length goes beyond 4000. Variables #columns and #sql both are of type nvarchar(max).
I have seen other posts that recommend splitting to multiple variables, but also mention nvarchar(max) should work. I am clueless on how to proceed if I was not to split the string.
Thanks
Perform the string concatenation yourself.
declare #sql nvarchar(max);
set #sql = convert(nvarchar(max), '')
+ 'insert into ' + #target_tablename + '(imported_on, ....
exec (#sql);

Msg 102, Level 15, State 1, Line 3 Incorrect syntax near ' ' with sp_executesql

I am dynamically building a SQL statement based on operations from a couple of different tables. The salient part of the SQL is below.
DECLARE #SQL NVARCHAR(MAX) = NULL
...
SELECT #sql = 'TRIM(CAST(' + STRING_AGG(EXPORT_COL, ' AS VARCHAR)) + '','' + TRIM(CAST(') FROM #TEMP_TABLE
SET #sql = 'SELECT''(''+'+#sql+' AS VARCHAR))+'')'''+'FROM '+'[mydatabase].[dbo].['+#TABLENAME+']'
SET #sql = REPLACE(#sql,'''','''''')
When I call the code using sp_executesql
EXEC sp_executesql #sql
I get this error
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near ''
If I query #sql or print the value to the messages window in SSMS I get:
SELECT''(''+TRIM(CAST(COL1 AS VARCHAR)) + '','' + TRIM(CAST(COL2 AS VARCHAR))+'')''FROM [mydatabase].[dbo].[DATA_TABLE]
which is the output I would expect.
Copying the text and calling sp_executesql using a quoted version of the output string, the query succeeds with no error.
EXEC sp_executesql N'SELECT''(''+TRIM(CAST(COL1 AS VARCHAR)) + '','' + TRIM(CAST(COL2 AS VARCHAR))+'')''FROM [mydatabase].[dbo].[DATA_TABLE]'
I have already checked for the presence of non-printable characters as indicated in this post
I have also implemented a function that "should" strip out any non printable characters per this post. Yet the problem persists.
SQL Server 2017 Express (v14.0.1000.169) on Windows Server 2019 standard.
You need to be really careful about when and what parts need single quotes vs which parts need doubled quotes.
If you are writing the string to assign it to a variable, it needs the doubled quotes. If, however, the string already has the quote inside, it doesn't need to be doubled again.
Here's a simplified example showing the issues/approach
CREATE TABLE #Test (TestVal varchar(100));
INSERT INTO #Test (TestVal) VALUES ('abcde');
Now, when running the process with doubled quotes (similar to yours), here are the results
DECLARE #SQL2 nvarchar(max) = 'SELECT ''''('''' + TestVal + '''')'''' FROM #Test;'
PRINT #SQL2;
/* -- Result
SELECT ''('' + TestVal + '')'' FROM #Test;
*/
EXEC sp_executesql #SQL2;
/* -- Result
Msg 102, Level 15, State 1, Line 12
Incorrect syntax near ''.
*/
EXEC sp_executesql N'SELECT ''('' + TestVal + '')'' FROM #Test;';
/* -- Result
(abcde)
*/
Note that in the bottom command, the doubled quotes were needed so that the string would contain single quotes - and therefore works. However, when already in the string, it made the command fail.
Now, if we make the variable just have single quotes, it works
DECLARE #SQL3 nvarchar(max) = 'SELECT ''('' + TestVal + '')'' FROM #Test;'
PRINT #SQL3;
/* -- Result
SELECT '(' + TestVal + ')' FROM #Test;
*/
EXEC sp_executesql #SQL3;
/* -- Result
(abcde)
*/

Issues encountered with dynamic SQL

ALTER PROCEDURE [dbo].[Create_Subjects]
#Subj_ID nvarchar(9)
AS
DECLARE #First3Digits nvarchar(3);
DECLARE #Result int;
DECLARE #Sql nvarchar(max)
-- Fetching the fiest 3 digits of the subject
SET #First3Digits = SUBSTRING(#Subj_ID,1,3);
-- Check if view is present or not
IF EXISTS (SELECT 1 FROM sys.views WHERE Name = #First3Digits)
BEGIN
SET #Sql = 'select #Result = case when exists (select 1 from dbo.' + quotename(#First3Digits) + ' where SubjectName = ''' + #Subj_ID + ''') then 1 else 0 end';
EXECUTE sp_executesql #Sql, N'#Subj_ID nvarchar(9), #Result bit out', #Subj_ID = #Subj_ID, #Result = #Result out;
-- checking if the subject is present in the view
END
ELSE
BEGIN
-- Create a view as view doesn't exist
SET #Sql = 'create view ' + #First3Digits
+ ' as
(select SubjectName from dbo.Subjects where SubjectName like '+#First3Digits+'%'+');';
EXECUTE sp_executesql #Sql, N'#First3Digits nvarchar(3)', #First3Digits= #First3Digits;
SET #Result = 0;
END
RETURN #Result
GO
This is the code for executing the stored procedure:
EXEC [dbo].[Create_Subjects] '1234567890'
Error encountered:
Msg 156, Level 15, State 1, Line 28
Incorrect syntax near the keyword 'view'
Msg 102, Level 15, State 1, Line 29
Incorrect syntax near ')'
There are a number of issues with your SQL. But firstly the way to debug them is to print the SQL without executing it, then its normal SQL and you can easily identify what is wrong with it.
No brackets are allowed around the SQL making up the view.
You have to quote your strings as per normal, which means doubling up the quotes in the dynamic string.
Use quotename again as suggested in the comments.
There is no need to pass the parameter #First3Digits into sp_executesql because by that point you've used its value - which you have to do given you are creating a view.
set #Sql = 'create view dbo.' + quotename(#First3Digits)
+ ' as'
+ ' select SubjectName'
+ ' from dbo.Subjects'
+ ' where SubjectName like ''' + #First3Digits + ''' + ''%'';';
-- This is how you debug dynamic SQL
print(#Sql);
execute sp_executesql #Sql;
Note: As I mentioned in your previous question, with the information provided, this seems to be a really bad design. There is almost certainly a better way to solve your bigger picture problem. As commented by Martin Smith an Inline Table Valued Function might be worth investigating.

declare variable in a table in SQL

I have a below query that requires help
Declare #DB varchar(3)
set #DB = 'C01'
SELECT * FROM SVBNORD+#DB WHERE ORDER_DATE = ''
But I get a message
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '+'.
Can you please help me correct my statement.
You should use execute to dynamically call the query:
Declare #DB varchar(3)
set #DB = 'C01'
execute ('SELECT * FROM SVBNORD'+#DB+' WHERE ORDER_DATE = '''' ')
You can't do this in normal sql. You can however build up sql dynamically and execute it, like so:
DECLARE #sql NVARCHAR(MAX);
SET #sql =
'SELECT * FROM SVBNORD' + #DB + N'WHERE ORDER_DATE = ''''';
EXEC(#sql);
You'll need to double up any single quotes in the query.

Msg 102, Level 15, State 1, Line 3 Incorrect syntax near ' '

I wrote the following code:
Declare #DaataBaseName2 varchar(50)
set #DaataBaseName2 = 'LUNDB14644A01' -- #DaataBaseName
USE #DaataBaseName2 --LUNDB14644A01
GO
I received following error:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '#DaataBaseName2'.
Why?
You will have to execute your code via dynamic SQL. You have to be careful with dynamic sql as it can lead to sql injection attack.
Here is a small scale sample of how to use a dynamic database.
Declare #DaataBaseName2 varchar(50),
#sql nvarchar(Max)
set #DaataBaseName2 = 'master' -- #DaataBaseName
set #sql = 'USE ' + #DaataBaseName2 + ';' + CHAR(13)
SET #sql = #sql + 'SELECT db_name()'
exec sp_executesql #sql
GO

Resources