Building insert statement with quotes in SQL - sql

I am trying to understand how the single quotes work in SQL.
All I want to achieve is
INSERT INTO LOGTABLE
(ID,
ROLLNO)
VALUES ('E8645F55-A18C-43EA-9D68-1F9068F8A9FB',
28)
Here ID is a uniqueidentifier field and rollNo is an int.
So I have this sample test code:
set #query = '
insert into fileLog
(
id,
rollNo
)
values
('+
'''' + NEWID() + '''' + ',' + 28 +
')'
print #query
I have tried several combination of single quotes left and right but nothing works. I would really appreciate if someone could solve this. But in particular I wanted to know how many single quotes are required on both sides of a string to get something like 'SQL'.
Thanks

My question is: Why are you using dynamic SQL? It's one of those techniques that is useful in some situations, but can be abused easily.
As for the answer to your question, I use a technique to help minimize the flipping in and out of SQL construction:
DECLARE #query VARCHAR(MAX)
SET #query = '
insert into fileLog
(
id,
rollNo
)
values
(''|NEWID|'', |INT|)'
SET #query = REPLACE(#query, '|NEWID|', NEWID())
SET #query = REPLACE(#query, '|INT|', 28)
PRINT #query

(I'm going to assume you need dynamic SQL for reasons not obvious in the question, since this doesn't seem to require dynamic SQL at all.)
As #Gidil suggested, the problem here is trying to treat a uniqueidentifier as a string. In this case, there really isn't any reason to declare NEWID() in the outer scope, since you can simply say:
SET #query = 'INSERT ... VALUES(NEWID(), 28);';
PRINT #query;
Now, you should be using NVARCHAR(MAX) as your parameter, because ultimately you should be executing this using sp_executesql, not EXEC().
If you need to have a literal you can double up the quotes:
DECLARE #string VARCHAR(32);
SET #string = 'foo';
SET #query = N'INSERT ... VALUES(''' + #string + ''', 28);';
However I find it more readable to use CHAR(39):
SET #query = N'INSERT ... VALUES(' + CHAR(39) + #string + CHAR(39) + ', 28);';
And even better is to not append these variables to a string anyway. You should be using properly typed parameters where possible.
DECLARE #query NVARCHAR(MAX);
DECLARE #string VARCHAR(32), #newid UNIQUEIDENTIFIER, #id INT;
SELECT #string = 'foo', #newid = NEWID(), #id = 28;
SET #query = N'INSERT ... VALUES(#string, #newid, #id);';
EXEC sp_executesql #query,
N'#string VARCHAR(32), #newid UNIQUEIDENTIFIER, #id INT',
#string, #newid, #id;
It's bulkier, sure, but it's much safer from SQL injection and it lets you stop trying to figure out and deal with the hassle of embedding single quotes into the string...

Try this:
DECLARE #query VARCHAR(MAX)
SET #query = ' insert into fileLog ( id, rollNo ) values (' + '''' + Cast(Newid() AS VARCHAR(100)) + ''''
+ ',28)'
PRINT #query
The problem isn't the quotes, but the data types.
NEWID isn't a string and neither is the number 28.
Good luck!

Unless you need dynamic SQL for some reason, you can probably just do this:
insert into fileLog
(
id,
rollNo
)
values
(
NEWID(),
28
)

Related

Use SQL Statement With String

I have a products table and i need to concat my string and my sql statements. Is there any way?
My purpose is that i want to define column names just one time in a string variable and i will use it alot of times. Otherwise my sql statements has alot of column name and it complex my code.
For example, i use this
DECLARE #MyStr NVARCHAR(MAX) = 'ProdId,ProdName'
SELECT TOP 10 #MyStr FROM Products
Result is here
But i need the result as this.
You'll need to use dynamic SQL here. I also suggest you fix your design and don't store delimited data, and ideally use a table type parameter. This would look like the following:
DECLARE #Columns table (ColumnName sysname);
INSERT INTO #Columns (ColumnName)
VALUES(N'Column1'),(N'Column2');
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = N'SELECT ' + STRING_AGG(QUOTENAME(ColumnName),N',') + #CRLF +
N'FROM dbo.Products;'
FROM #Columns;
PRINT #SQL; --Your best friend
EXEC sys.sp_executesql #SQL;
If you don't want to use a table type, you can use STRING_SPLIT:
SELECT #SQL = N'SELECT ' + STRING_AGG(QUOTENAME([Value]),N',') + #CRLF +
N'FROM dbo.Products;'
FROM STRING_SPLIT(#Columns,',');

How to use a dynamic WHERE clause in my SQL CTE query?

I've a question about my SQL CTE construction. I'm working with Azure Data Factory and a Stored Procedure in my database. What I want to do is:
Return my data from my view to Azure Data Factory in JSON format.
Return the data filtered dynamically in the WHERE clause based on my ObjectCode in my view in JSON format.
-> To test step 2 I tried with a statical declared ObjectCode
But the single quote does not work right in the WHERE clause. I tried some things with REPLACE, CHAR(39) and double the quotes. Like they said here, here and here
Step 1 I've finished succesfull with this code:
BEGIN
DECLARE #TABLE TABLE(RESULT NVARCHAR(MAX))
DECLARE #QUERY NVARCHAR(MAX) = '
;WITH x(Params) as
(
SELECT * FROM [Schema].[View] FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
Select * from x
'
Insert #TABLE
EXEC (#QUERY)
Select ',"pipelineParameters": ' + LEFT(RESULT,LEN(RESULT)-1) + '}' as Params from #TABLE;
END
This query above gave me the right result. But, now I need to make a change for Step 2. I need to filter with the WHERE clause in the query.
So, I tried:
DECLARE #TABLE TABLE(RESULT NVARCHAR(MAX))
DECLARE #ObjectCode NVARCHAR(MAX) = 'Objectname'
DECLARE #QUERY NVARCHAR(MAX) = '
;WITH x(Params) as
(
SELECT * FROM [Schema].[View]
WHERE Objectcode = REPLACE(#ObjectCode, '''', '')
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
Select * from x
'
Insert #TABLE
EXEC (#QUERY)
Select ',"pipelineParameters": ' + LEFT(RESULT,LEN(RESULT)-1) + '}' as Params from #TABLE;
But when I run these query I get this error:
Does anyone know what I can improve here so I can get it working?
Does this do what you want?
Insert #TABLE
exec sp_executesql #QUERY, N'#ObjectCode nvarchar(max)', #ObjectCode=#ObjectCode;
As written, I would expect a syntax error when the query is run because of this WHERE clause:
WHERE Objectcode = REPLACE(#ObjectCode, '', ')
I think you intend:
DECLARE #QUERY NVARCHAR(MAX) = '
WITH x(Params) as (
SELECT *
FROM [Schema].[View]
WHERE Objectcode = REPLACE(#ObjectCode, '''''''', '''')
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
Select *
from x';
Quoting things in dynamic SQL is always verbose. You can print out #Query to see if it is really what you intend.
'
Thanks Gordon, the first one works for me:
Insert #TABLE
exec sp_executesql #QUERY, N'#ObjectCode nvarchar(max)', #ObjectCode=#ObjectCode;

Conversion failed when converting the varchar value '<b>' to data type float

Here, What I am trying to do is to display the data in BOLD and did for name column at backend and there isn't any issue but when applying same to the salary it's raising an error even using conversion functions. So, I am looking for your suggestions OR solutions :
The case is same but data and query is different and I must go through the dynamic query as below because it's huge with various conditions.
CREATE TABLE #test(name VARCHAR(50), salary FLOAT)
INSERT INTO #test VALUES
('a', 1000),
('b', 5000)
DECLARE #sql VARCHAR(8000)
SET #sql = 'SELECT
''<b>'' + name + ''</b>'',
''<b>'' + salary + ''</b>''
FROM #test'
EXEC(#sql)
Thank You.
CREATE TABLE #test(name VARCHAR(50), salary INT)
INSERT INTO #test VALUES
('a', 1000),
('b', 5000)
DECLARE #sql VARCHAR(8000)
SET #sql = 'SELECT
''<b>'' + name + ''<b>'',
''<b>'' + CAST(salary AS VARCHAR(20)) + ''<b>''
FROM #test'
EXEC(#sql)
Cast your salary to varchar(100) explicitly
SET #sql = 'SELECT
''<b>'' + name + ''<b>'',
''<b>'' + cast(salary as varchar(100)) + ''<b>''
FROM #test'
I don't understand why dynamic SQL is necessary. However, I often approach such problems using replace():
SET #sql = '
SELECT ''<b>''[name]''</b>'', ''<b>''[salary]''</b>''
FROM #test
';
SET #sql = REPLACE(#sql, '[name]', 'name');
SET #sql = REPLACE(#sql, '[salary]', 'salary');
EXEC sp_executesql #sql;
I also recommend sp_executesql over exec() -- it is more flexible and allows you to pass parameters in and out of the statement (this functionality is not needed for this query).

Dynamic SELECT checking for records with apostrophe [duplicate]

I was trying to execute the below statement to escape single quotes (i.e. using two single quotes):
declare #year varchar(max)
set #year = '111,11';
exec ('SELECT * FROM SplitValues(' + #year + ','','')');
I even tried to use char(39) instead of quotes:
declare #year varchar(max)
set #year = '111,11';
exec ('SELECT * FROM SplitValues(' + #year + ',' + char(39) + ',' + char(39) + ')');
But it didn't help. These are the only two solutions that I found on this site. Any help?
This is the simplified query to clear up all your questions:
declare #year varchar(max)
set #year = '111,11';
SELECT * FROM SplitValues(#year , ',')
I want to achieve this, but using a dynamic query.
A word of advice. When testing a dynamic script, first just display it instead of executing it. That way you will be able to see it exactly as it would be seen by the EXEC statement.
Now to the issue. You should keep in mind that you are not passing the variable to SplitValues but are instead concatenating the variable's value into the script. Since the value is varchar, it should be concatenated with quotation marks around it. The absence of them is the only problem really.
The quotes around the second argument, the comma, are escaped correctly in both cases. So, just use either of the methods to add the quotes around the first argument:
repetition of the quotation mark:
DECLARE #year varchar(max), #sql varchar(max);
SET #year = '111,11';
SET #sql = 'SELECT * FROM SplitValues(''' + #year + ''','','')';
SELECT #sql;
using CHAR(39):
DECLARE #year varchar(max), #sql varchar(max);
SET #year = '111,11';
SET #sql = 'SELECT * FROM SplitValues(' + CHAR(39) + #year + CHAR(39) + ',' + CHAR(39) + ',' + CHAR(39) + ')';
SELECT #sql;
Obviously, the first method is more compact, but, like I said, both work well, as this SQL Fiddle demo clearly shows.
Note, however, that you could easily escape this issue in the first place, if you pardon the pun. Instead of EXEC (), you could use EXEC sp_executesql, which allows you to use parameters. Here's the same script rewritten to use sp_executesql:
DECLARE #year varchar(max), #delim char(1);
SET #year = '111,11';
SET #delim = ',';
EXEC sp_executesql
N'SELECT * FROM SplitValues(#year_param,#delim_param)',
N'#year_param varchar(max), #delim_param char(1)',
#year,#delim;
As you can see, no need to worry about escaping the quotes: SQL Server takes the trouble of substituting the values correctly, not you.
Just type single quote two times:
select 'that''s it'
Ok... you want to take this string:
SELECT * FROM SplitValues(#year , ',')
And make it a string like this:
'SELECT * FROM SplitValues('111,11' , '','')'
So, your final code would be:
declare #year varchar(max), #sql varchar(max)
set #year = '111,11';
set #sql = 'SELECT * FROM SplitValues(''' + #year + ''' , '''','''')'
select #sql
Actually, finally select you would use exec() instead. However you really should probably use sp_sqlexecute for stuff like this since you can use paramaterized queries.
declare #var1 varchar(100)
declare #var3 varchar(100)
declare #var4 varchar(100)
declare #var2 nvarchar(MAX)
set #var1 = ‘anil’
set #var4 = ‘1019518594’
set #var2 = N’select
a.*
from card b
join log a on a.Cust = b.ID
where a.c = ”’ + #var1 + ”’ and b.s =”’+ #var4 +””
print(#var2)
exec sp_executesql #var2

Executing dynamic SQL in a SQLServer 2005 function

I will preface this question by saying, I do not think it is solvable. I also have a workaround, I can create a stored procedure with an OUTPUT to accomplish this, it is just easier to code the sections where I need this checksum using a function.
This code will not work because of the Exec SP_ExecuteSQL #SQL calls. Anyone know how to execute dynamic SQL in a function? (and once again, I do not think it is possible. If it is though, I'd love to know how to get around it!)
Create Function Get_Checksum
(
#DatabaseName varchar(100),
#TableName varchar(100)
)
RETURNS FLOAT
AS
BEGIN
Declare #SQL nvarchar(4000)
Declare #ColumnName varchar(100)
Declare #i int
Declare #Checksum float
Declare #intColumns table (idRecord int identity(1,1), ColumnName varchar(255))
Declare #CS table (MyCheckSum bigint)
Set #SQL =
'Insert Into #IntColumns(ColumnName)' + Char(13) +
'Select Column_Name' + Char(13) +
'From ' + #DatabaseName + '.Information_Schema.Columns (NOLOCK)' + Char(13) +
'Where Table_Name = ''' + #TableName + '''' + Char(13) +
' and Data_Type = ''int'''
-- print #SQL
exec sp_executeSql #SQL
Set #SQL =
'Insert Into #CS(MyChecksum)' + Char(13) +
'Select '
Set #i = 1
While Exists(
Select 1
From #IntColumns
Where IdRecord = #i)
begin
Select #ColumnName = ColumnName
From #IntColumns
Where IdRecord = #i
Set #SQL = #SQL + Char(13) +
CASE WHEN #i = 1 THEN
' Sum(Cast(IsNull(' + #ColumnName + ',0) as bigint))'
ELSE
' + Sum(Cast(IsNull(' + #ColumnName + ',0) as bigint))'
END
Set #i = #i + 1
end
Set #SQL = #SQL + Char(13) +
'From ' + #DatabaseName + '..' + #TableName + ' (NOLOCK)'
-- print #SQL
exec sp_executeSql #SQL
Set #Checksum = (Select Top 1 MyChecksum From #CS)
Return isnull(#Checksum,0)
END
GO
It "ordinarily" can't be done as SQL Server treats functions as deterministic, which means that for a given set of inputs, it should always return the same outputs. A stored procedure or dynamic sql can be non-deterministic because it can change external state, such as a table, which is relied on.
Given that in SQL server functions are always deterministic, it would be a bad idea from a future maintenance perspective to attempt to circumvent this as it could cause fairly major confusion for anyone who has to support the code in future.
Here is the solution
Solution 1:
Return the dynamic string from Function then
Declare #SQLStr varchar(max)
DECLARE #tmptable table (<columns>)
set #SQLStr=dbo.function(<parameters>)
insert into #tmptable
Exec (#SQLStr)
select * from #tmptable
Solution 2:
call nested functions by passing parameters.
You can get around this by calling an extended stored procedure, with all the attendant hassle and security problems.
http://decipherinfosys.wordpress.com/2008/07/16/udf-limitations-in-sql-server/
http://decipherinfosys.wordpress.com/2007/02/27/using-getdate-in-a-udf/
Because functions have to play nicely with the query optimiser there are quite a few restrictions on them. This link refers to an article that discusses the limitations of UDF's in depth.
Thank you all for the replies.
Ron: FYI, Using that will throw an error.
I agree that not doing what I originally intended is the best solution, I decided to go a different route. My two choices were to use sum(cast(BINARY_CHECKSUM(*) as float)) or an output parameter in a stored procedure. After unit testing speed of each, I decided to go with sum(cast(BINARY_CHECKSUM(*) as float)) to get a comparable checksum value for each table's data.