What is the purpose and how this SQL query functions? - sql

I have unfortunately executed this query and my website is not displaying some values properly from SQL database now. Could anyone explain what this query actually do?
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = CAST(REPLICATE(N'A',3000) AS NVARCHAR(MAX)) + CAST(REPLICATE(N'B',3000) AS NVARCHAR(MAX))
SELECT LEN(#SQL)

Let's break your code:
-- string variable declaration #SQL at this moment it is NULL
DECLARE #SQL NVARCHAR(MAX)
-- assign to variable #SQL concatentation of AAA...AAABBB...BBB
-- 3000 3000
SET #SQL = CAST(REPLICATE(N'A',3000) AS NVARCHAR(MAX)) + CAST(REPLICATE(N'B',3000) AS NVARCHAR(MAX))
--get length of string (6000 = 3000 + 3000)
SELECT LEN(#SQL)
DBFiddle Demo

Related

How to SELECT INTO <a calculated table name>? [duplicate]

I have a problem with treating table name as variable as I need to put the results to different table each month automatically (without using any advanced procedures to make this query dynamic). Can somebody help me to modify this code and make it work?
declare #exp_dte as date;
set #exp_dte='2015-12-31';
print (#exp_dte);
declare #tab_mth as nvarchar(max);
set #tab_mth=year(#exp_dte)*100+month(#exp_dte);
print (#tab_mth);
declare #tab_name as nvarchar(max)
set #tab_name='mis_anl.dbo.BIK_' + #tab_mth
print (#tab_name);
IF OBJECT_ID (N'#tab_name', N'U') IS NOT NULL
begin
drop table #tab_name
end
select distinct
*
into #tab_name
from table_x
You have to use dynamic SQL to set name at runtime:
DECLARE #exp_dte DATE = '2015-12-31';
DECLARE #tab_name SYSNAME = '[dbo].' + QUOTENAME('BIK_' + FORMAT(#exp_dte, 'yyyyMM'));
IF OBJECT_ID (#tab_name, N'U') IS NOT NULL
BEGIN
EXEC('DROP TABLE' + #tab_name);
END
DECLARE #sql NVARCHAR(MAX) = N'SELECT DISTINCT *
INTO #tab_name
FROM table_x';
SET #sql = REPLACE(#sql, '#tab_name', #tab_name);
EXEC [dbo].[sp_executesql] #sql;
LiveDemo
Remarks:
Try to be more conscise
You could use FORMAT to get yyyyMM (SQL Server 2012+)
Always QUOTENAME generated identifiers to avoid SQL Injection attacks
I strongly recommend to read The Curse and Blessings of Dynamic SQL especially CREATE TABLE #tbl.
use dynamic sql ,you cant user table names as variables
declare #exp_dte as date;
set #exp_dte='2015-12-31';
declare #tab_mth as nvarchar(max);
set #tab_mth=year(#exp_dte)*100+month(#exp_dte);
declare #tab_name as nvarchar(max)
set #tab_name='mis_anl.dbo.BIK_' + #tab_mth
declare #sql1 nvarchar(max)
set #sql1='drop table '+#tab_name;
IF exists(select 1 from information_schema.tables where table_name=#tab_name)
begin
exec(#sql1);
end
declare #sql nvarchar(max)
set #sql='
select distinct
*
into '+#tab_name+'
from table_x'
exec (#sql)

Concatenation problem in Dynamic sql query

I'm trying to concatenate the string with multiple variables and go for exec. Unfortunately I'm facing the conversion problem as:
Conversion failed when converting the varchar value 'Select #ExistingIds= CBSE_IX_J from ##tempPivot where EmployeeID=' to data type int.
My query is :
SET #ExecColumn = concat('Select #ExistingIds= '+#TSectionName +' from ##tempPivot where EmployeeID='+CAST(#TUserID as INT),'')
PRINT #ExecColumn
EXEC (#ExecColumn)
The "simple" answer is don't concatenate raw string values into your dynamic statement, and parametrise your code. This is a bit of guesswork, however, is far safer than the SQL Injection hole you have right now:
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SELECT #ExistingIDs = ' + QUOTENAME(#TSectionName) + NCHAR(13) + NCHAR(10)+
N'FROM ##tempPivot' + NCHAR(13) + NCHAR(10) +
N'WHERE EmployeeID = #TUserID;';
PRINT #SQL;
EXEC sp_executesql #SQL,
N'#TUserID int, #ExistingIds int OUTPUT', --guessed datatypes and that #ExistingIds is an OUTPUT
#TUserID = #TUserID,
#ExistingIds = ExistingIds OUTPUT;
Note: the fact that your variable is called #ExistingIDs implies you want to store multiple values in that variable. #ExistingIDs is a scalar value, it will only hold a scalar (single) value. If the query above returns multiple rows, only the value of from the last row will be returned. For example:
DECLARE #i int;
SELECT #i = I
FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9))V(I)
ORDER BY I;
SELECT #i;
Notice that #i has the value 9, not '1,2,3,...,9'.
You would seem to want:
DECLARE #SQL nvarchar(MAX);
DECALRE #ExistingIds NVARCHAR(MAX);
SET #SQL = N'
SELECT #ExistingIDs = STRING_AGG(#TSectionName, '''')
FROM ##tempPivot
WHERE EmployeeID = #TUserID
';
-- Cannot have identifiers as parameters, so use `REPLACE()`
SET #SQL = REPLACE(#SQL, '#TSectionName', QUOTENAME(#TSectionName);
EXEC sp_executesql #SQL,
N'#TUserID int, #ExistingIds NVARCHAR(MAX) OUTPUT', --guessed datatypes and that #ExistingIds is an OUTPUT
#TUserID=#TUserID,
#ExistingIds=#ExistingIds OUTPUT;
In older versions of SQL Server, you need another approach for concatenating strings. For instance
SET #SQL = N'
SELECT #ExistingIDs = (SELECT #TSectionName
FROM ##tempPivot
WHERE EmployeeID = #TUserID
FOR XML PATH ('')
)
';

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

SQL add a variable to a query

How do I create variables that are specified once and then used in queries later in a script? These variables may be used multiple times in a query, and in multiple queries in a script. I use #x as such a variable in the examples below.
What I want to do is something like:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + #x + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Which returns the error mentioned above. I would like it to achieve the equivalent of:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''test'' as [TestCase]
From mytable'
Exec (#Query)
-- Returns e.g.
-- Name TestCase
-- Alice Test
-- Bob Test
I also note that the following doesn't work and returns the same error as the first:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + 'test' + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Based on the error and since I'm not trying to use the #x as a column name, but just as a variable, I assume I'm using an invalid implementation of a variable.
Since you're not trying to use a variable as a column name, you do not need to use dynamic SQL at all. (Which is a Good Thing(TM) since dynamic SQL should only be used with a great deal of caution due to it being a great attack surface.)
A simple:
declare #x nvarchar(40)
set #x = 'test'
select [Name], #x as TestCase
from mytable
will do.
That being said, if you have a use case for dynamic SQL (again the particular query in question here does not but perhaps an ad-hoc query is being passed in to the procedure), the thing to do would be to pass your variable as a parameter to the query via sp_executesql. This is akin to creating a stored procedure with parameters:
declare #x nvarchar(40)
declare #query nvarchar(1000)
set #x = 'test'
set #query = 'select [Name], #x as TestCase from mytable'
exec sp_executesql #query, N'#x nvarchar(1000)', #x
You were missing quotes. Thats it. Try below code.
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''' + #x + ''' as [TestCase]
From mytable'
Exec (#Query)
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name],'++''''+#x+''''+ ' as [TestCase]
From mytable'
print #query
Output:
Select [Name],'test' as [TestCase]
From mytable

Dynamically Create Update SQL In Stored Procedure

I try to create a stored procedure to update a table record whose sql statement is dynamically created. I wrote some codes but am stoped in to run this query dynamically, How can i run this query or is there a better solution for this problem.
How this SP work?=> I send the columns names,values and datatype of the record that need update to SP like below
<e columnName=''PaymentStatus'' value=''99'' type=''nvarchar''/>
<e columnName=''HotelProvider'' value=''GAT2'' type=''nvarchar''/>
Then travel the nodes and create an Update statement, but can't execute it :))
I am giving a part of SP to understand the question better.
DECLARE #UpdateXml xml = '
<xml>
<e columnName=''PaymentStatus'' value=''99'' type=''nvarchar''/>
<e columnName=''HotelProvider'' value=''GAT2'' type=''nvarchar''/>
</xml>';
DROP TABLE ##UpdateFields
SELECT
t.c.value('#columnName', 'varchar(max)') AS ColumnName,
t.c.value('#value', 'varchar(max)') AS Value,
t.c.value('#property', 'varchar(max)') AS PropertyOf,
t.c.value('#type', 'varchar(max)') AS ColumnType
INTO ##UpdateFields
from #UpdateXml.nodes('/xml/e') as t(c)
DECLARE #SQL nvarchar(MAX) = 'UPDATE HotelBooking ';
DECLARE #SQLUpdatePart nvarchar(MAX);
SET #SQLUpdatePart = 'SET ';
SELECT #SQLUpdatePart= #SQLUpdatePart+ColumnName +'='+'#QP_'+ColumnName+',' FROM ##UpdateFields WHERE PropertyOf IS NULL;
DECLARE #SQLWherePart nvarchar(MAX);
SET #SQLWherePart = ' WHERE Id=2';
DECLARE #ParmDefinition nvarchar(MAX)='';
SELECT #ParmDefinition = #ParmDefinition+'#QP_'+ColumnName+' '+ColumnType+',' FROM ##UpdateFields;
SELECT #ParmDefinition
SELECT #SQL + #SQLUpdatePart + #SQLWHerePart;
Last two select statements results are:
#QP_PaymentStatus nvarchar,#QP_HotelProvider nvarchar,#QP_TransactionId uniqueidentifier,#QP_UpdatedDate datetime
and
UPDATE HotelBooking SET PaymentStatus=#QP_PaymentStatus,HotelProvider=#QP_HotelProvider,UpdatedDate=#QP_UpdatedDate,TransactionId=#QP_TransactionId WHERE Id=2
Now How can I give the #QP parameters to sp_executesql() method dynamically?
You can do it by wrapping sp_executesql call in another exec:
declare #updateStr nvarchar(1000)
-- #updateStr = N'select * from ATable where ID = #p1'
set #updateStr = N'N''select * from ATable where ID = #p1'''
declare #paramStr nvarchar(100)
-- #paramStr = N'#p1 int'
set #paramStr = N'N''#p1 int'''
declare #actualParameters nvarchar(100)
set #actualParameters = N'#p1 = 10'
-- Concatenate parts of query into a variable
declare #sql nvarchar(max)
set #sql = N'sp_executesql ' + #updateStr + ',' + #paramStr + ', ' + #actualParameters
-- And voila!
exec (#sql)