SQL ' ' do not get escaped - sql-server

I am trying to run a query in SQL 2008 by doing:
#query varchar(max)
SET #query = 'SELECT * FROM Table WHERE [Name] = ' 'Karl' ' '
EXEC(#query)
The problem is that for some reason the apostrophes around 'Karl' don't get escaped, i.e. the query executes as ...WHERE [Name] = Karl and fails.
Anyone has a suggestion?

There are several ways that you can escape character data in SQL Server, some people even advocate the use of the QUOTENAME() functions.
If you really want to develop of solid understanding of this subject area then may I recommend that you take a look at what experienced SQL Server Developers consider to be essential reading with regard to the different methods you can use to incorporate Dynamic T-SQL into your coding.
The Curse and Blessings of Dynamic SQL

Try:
DECLARE #query varchar(max)
SET #query = 'SELECT * FROM Table WHERE [Name] = ''Karl'''
PRINT 'when in doubt, print the query out: '+ISNULL(#query,'')
EXEC(#query)
To have a single quote appear, you need to have two adjacent single quotes. You escape a single quote with a single quote, for example:
PRINT '''' --will print a one single quote
PRINT '''''' --will print two single quotes
PRINT 'can''t' --will print can't

This works on my machine from SQL Server Management Studio:
#query varchar(max)
SET #query = 'SELECT * FROM Table WHERE [Name] = ''''''Karl'''''''
EXEC(#query)

A double single ('') quote will act like a single single quote when inside a string literal.
Have you tried using a variable?
declare #karl_name varchar(10);
set #karl_name = '''Karl''';
SELECT * FROM Table WHERE [Name] = #karl_name

do like this
SET #query = 'SELECT * FROM Table WHERE [Name] = ''''Karl'''''

This works:
create table #demo([Name] varchar(max))
insert into #demo([Name]) values('''Karl''')
insert into #demo([Name]) values('Karl')
declare #query varchar(max)
set #query = 'SELECT * FROM #demo WHERE [Name] = ''''''Karl'''''''
EXEC(#query)
Output:
'Karl'
But if 'Karl' is variable text, it's highly recommended to use something like this instead:
declare #query nvarchar(max)
declare #param varchar(max)
set #param = N'''Karl'''
set #query = N'SELECT * FROM #demo WHERE [Name] = #param'
exec sp_executesql #query, N'#param varchar(max)', #param

Simply escape the apostrophes by using the escaping bar \ like this 'SELECT * FROM Table WHERE [Name] = ' \'Karl\' ' '
Hope it helps

Related

How to use like operator in SQL query string? I got 'Incorrect syntax near 'A''

Statement:
declare #Searchkey varchar(50)='a'
declare #Sql nvarchar(max) =''
set #Sql = #Sql +
'select * from products where upper(ProductName) like %' + upper(#Searchkey) + '%'
execute sp_executesql #Sql
Error message:
Msg 102 Level 15 State 1 Line 1
Incorrect syntax near 'A'.
You do not require a dynamic query for such case, you can use below simple query to get the desired result.
declare #Searchkey varchar(50)= 'a'
select * from products where upper(ProductName) like '%' + upper(#Searchkey) + '%'
If you still want to go with Dynamic query then below are the connect syntax.
declare #Searchkey varchar(50)='a'
declare #Sql nvarchar(max) =''
set #Sql =#Sql+'select * from products where upper(ProductName) like ''%' +upper(#Searchkey)+'%'''
--print #Sql
execute sp_executesql #Sql
Note: Whenever you will get an error with a dynamic query then the best way is to print the query using print statement that will help to identify the error easily. In your case, a single quote was missing.
The reason for this error is that you need to add quotes around the search pattern, when you build the dynamic statement. But I think that your should use parameter in this dynamically built statement to prevent SQL injection issues:
DECLARE #Searchkey varchar(50) = 'a'
DECLARE #Sql nvarchar(max) = N''
SET #Sql =
#Sql +
N'SELECT * FROM products WHERE UPPER(ProductName) LIKE CONCAT(''%'', UPPER(#Searchkey), ''%'')'
PRINT #Sql
EXEC sp_executesql #Sql, N'#Searchkey varchar(50)', #Searchkey
You're not placing quotes around your search term, so the literal query that's being sent is:
select * from products where upper(ProductName) like %A%
You need to wrap the search term in quotes, like so:
set #Sql =#Sql+'select * from products where upper(ProductName) like ''%'+upper(#Searchkey)+'%'''
This will create the following query:
select * from products where upper(ProductName) like '%A%'

Table name placeholder - TSQL

Is there a way to do something like this? People is the name of the table.
declare #placeholder varchar(20) = 'People'
select * from #placeholder
Or something like this where the table name is People_Backup.
declare #placeholder varchar(20) = '_Backup'
select * from People#placeholder
And is there a way to add in dynamic sql the value of a variable?
something like this:
declare #placeholder nvarchar(20) = 'people'
declare #name nvarchar(30) = 'antony'
declare #query nvarchar(1000) = 'select * from ' + #placeholder + ' where
first_name=' + #name
exec sp_executesql #query
I mean: without do this
exec sp_executesql #query, N'#name varchar(30)', #name
Thank you for the answers.
Not without dynamic SQL.
Parameters in SQL are placeholders for data, and can't be used as placeholders for anything else (which includes commands such as select, update etc' and identifiers such as database name, schema name, table name, column name etc').
The only way to parameterize table names is to use dynamic SQL - meaning you must build a string containing the SQL you want to execute, and then execute it.
Beware - dynamic SQL might be an open door for SQL injection attacks - so you must do it wisely - here are some ground rules:
Always white-list your identifiers (using system tables or views such as sys.Tables or Information_schema.Columns)
Always use sysname as the datatype for identifiers.
The sysname data type is used for table columns, variables, and stored procedure parameters that store object names. The exact definition of sysname is related to the rules for identifiers. Therefore, it can vary between instances of SQL Server.
Never pass SQL commands or clauses in parameters - set #placeholder = 'select a, b, c' or set #placeholder = 'where x = y' is a security hazard!
Always use parameters for data. Never concatenate parameters into your sql string: set #sql = 'select * from table where x = '+ #x is a security hazard. Always create your dynamic SQL to use parameters as parameters: set #sql = 'select * from table where x = #x'
Always use sp_executeSql to execute your dynamic SQL statement, not EXEC(#SQL).
For more information, read Kimberly Tripp's EXEC and sp_executesql – how are they different?
Always wrap identifiers with QUOTENAME() to ensure correct query even when identifiers include chars like white-spaces
To recap - a safe version of what you are asking for (with an additional dynamic where clause to illustrate the other points) is something like this:
#DECLARE #TableName sysname = 'People',
#ColumnName sysname = 'FirstName'
#Search varchar(10) = 'Zohar';
IF EXISTS(
SELECT 1
FROM Information_Schema.Columns
WHERE TABLE_NAME = #TableName
AND COLUMN_NAME = #ColumnName
)
BEGIN
DECLARE #Sql nvarchar(4000) =
'SELECT * FROM +' QUOTENAME(#TableName) +' WHERE '+ QUOTENAME(#ColumnName) +' LIKE ''%''+ #Search +''%'';'
EXEC sp_executesql #Sql, N'#Search varchar(10)', #Search
END
-- you might want to raise an error if not
To answer your question after edited directly:
I mean: without do this exec sp_executesql #query, N'#name varchar(30)', #name
Yes, you can do it without using sp_executeSql, but it's dangerous - it will enable an attacker to use something like '';DROP TABLE People;-- as the value of #name, so that when you execute the sql, your People table will be dropped.
To do that, you will need to wrap the #name with ' -
declare #placeholder nvarchar(20) = 'people'
declare #name nvarchar(30) = 'antony'
declare #query nvarchar(1000) = 'select * from ' + QUOTENAME(#placeholder) + ' where
first_name=''' + #name +''''
exec(#query)
I mean: without do this exec sp_executesql #query, N'#name varchar(30)', #name
Yes, you can do that as
--Use MAX instead of 1000
DECLARE #SQL nvarchar(MAX) = N'SELECT * FROM ' + #placeholder + ' WHERE first_name = '''+#name +'''';
EXECUTE sp_executesql #SQL;

Dynamic SQL in SQL Server: Executing a string through sp_sqlexec #string VS using a pure SQL query - why does stored string not work?

DECLARE #Description NVARCHAR(128) = N'MS_Description'
--Just for good measure
SET #Description = N'MS_Description'
The first statement is me trying to use sp_sqlexec by storing my SQL with dynamic parameters in a string:
SELECT #query = #query + 'SELECT * FROM TABLE
WHERE COLUMN = ' + #Description
EXEC sp_sqlexec #query
The above doesn't work, I get the following error:
Invalid column name 'MS_Description'
When I debug through this, the statement is exactly the same as the below query, that works and returns the results that I want.
SELECT *
FROM table
WHERE column = #Description
Could someone please explain the difference and why the below works if it is the exact same thing that's stored in #query? Thank you
The issue with the first query is that you're not adding your quotes back in. It treats the + as a concat, so your statement ends up being
SELECT * FROM TABLE
WHERE COLUMN = MS_Description
We know this won't work, as MS_Description should be 'MS_Description'
What you need to do for the top one to work is
SELECT #query = #query + 'SELECT * FROM TABLE
WHERE COLUMN = ''' + #Description + ''''

How to use isnull() in a varchar query sql server

I build a query within a variable of type varchar I want to make test with isnull()
example:
declare #sql varchar(max)
set #sql = '
Select top (100) id
FROM RIGHT R inner join RIGHT_TYPE RT on
R.RIGHT_TYPE_CODE = RT.CODE
WHERE R.RIGHT_TYPE_CODE = isnull('+#rightType+', R.RIGHT_TYPE_CODE)
'
exec (#sql)
go
#rightType is a parameter of my stored procedure.
The problem that when I have #rightType equals to null nothings works
Thank you.
To have optional parameters in dynamic SQL, this is usually the best option:
DECLARE #rightType nvarchar(50)
DECLARE #sql nvarchar(max);
set #sql = '
Select top (100) id
FROM RIGHT R inner join RIGHT_TYPE RT on
R.RIGHT_TYPE_CODE = RT.CODE
WHERE 1=1'
if (#rightType is not NULL) set #sql = #sql + ' and R.RIGHT_TYPE_CODE = #rightType'
EXEC sp_executesql #sql, N'#rightType nvarchar(50)', #rightType
This way you're not concatenating the input string with the SQL, so there's no chance of SQL injection happening, and the optimizer likes this a lot more, because the parameter is in the SQL only when it's actually given.
The 1=1 is in the SQL so that you can append any number (or none) criteria to the SQL without having to worry to have correct amount of ands.

Handling IS NULL inside string in SQL

I have a SQL query which is written in string and then executed using command Exec(string) like the following :
Declare #TestId bigint = null
Declare #Query nvarchar(max)
set #Query = 'SELECT * from Registrations where RegistrationId = 15 AND (' + CAST(#TestId AS NVARCHAR) + ' IS NULL OR TestId = ' + CAST(#TestId AS NVARCHAR) + ') '
EXEC(#Query)
The problem now that the IS NULL is not parsed correctly inside the string but when i remove the IS NULL from the string it works correctly and when the #TestId takes a value other than null it works correctly where the problem now is in the casting of the IS NULL inside the #Query string.
Note : #TestId is a procedure parameter
I need to know how to make the SQL feel with the IS NULL and parse it correctly
Thanks in advance
If you really do need to use dynamic sql for this, use sp_executesql like this:
Declare #TestId bigint = null
Declare #Query nvarchar(max)
set #Query = 'SELECT * from Registrations where RegistrationId = 15 AND (#TestId IS NULL OR TestId = #TestId)'
EXECUTE sp_executesql #Query, N'#TestId BIG INT', #TestId
You don't need dynamic SQL for this. Also if you were to generate dynamic SQL one of the benefits of doing so is so that your queries do not need to have this sort of WHERE TestId =#TestId OR #TestId IS NULL construct which causes problems with plan caching and unnecessary table scans.
Declare #TestId bigint = null
Declare #Query nvarchar(max)
IF #TestId IS NULL
SELECT * from Registrations where RegistrationId = 15
ELSE
SELECT * from Registrations where RegistrationId = 15 AND TestId =#TestId
Edit
Following comment if you do need dynamic SQL then use sp_executesql and generate different strings for the case where #TestId is null. Don't shoehorn both cases into the same query.
The other answers provide the solutions. Here is why your solution didn't work. When #TestId is null, you are concatenating a null to your #Query string, and that assigns null to #Query. If you print your #Query in place of the the exec, you will see the query that would run.
Declare #TestId bigint = 10--null
Declare #Query nvarchar(max)
set #Query = 'SELECT * from Registrations where RegistrationId = 15 AND (' + CAST(#TestId AS NVARCHAR) + ' IS NULL OR TestId = ' + CAST(#TestId AS NVARCHAR) + ') '
--EXEC(#Query)
print #Query
Building dynamic queries is bad, m'kay...that said, you can fix it by moving the null check outside of the dynamic query and handling it there:
set #Query = 'select * from registrations where registrationId = 15 and
CAST(TestId AS NVARCHAR) = ' + ISNULL(CAST(#TestId AS NVARCHAR), '')
On another note, why are you using a dynamically built query for something as simple as this? It could be a regular SELECT statement which would make things much less complicated.
select * from registrations where registrationId = 15 and TestId = #TestId
From your code I suspect what you want to is to filter the results from Registrations by the TestId, given that it is not null. Why not do this programatically instead of in the SQL query? Something along those lines (syntax my be wrong):
Declare #TestId bigint = null
Declare #Query nvarchar(max)
if(#TestId IS NULL)
set #Query = 'SELECT * from Registrations where RegistrationId = 15'
else
set #Query = 'SELECT * from Registrations where RegistrationId = 15 AND (TestId = ' + CAST(#TestId AS NVARCHAR) + ') '
EXEC(#Query)
Also, Justin Niessner is right, dynamic SQL is to be avoided if possible (this could be done without dynamic SQL).

Resources