how to create a dynamic update query with variables? - sql

I am trying to create the below dynamic update query with some variables and for some reason, it's not working inside the stored procedure. Can someone suggest to me where I am doing wrong and what's the best practice by avoiding the SQL Injection as well?
DECLARE #SQL NVARCHAR(MAX)
DECLARE #COLUMN1 NVARCHAR(10)
DECLARE #COLUMN2 NVARCHAR(10)
DECLARE #TABLENAME NVARCHAR(10)
SET #SQL = 'UPDATE TL
SET '+ #COLUMN1 + '= AB.COLUMN1,'
+ #COLUMN2 + '= AB.COLUMN2
FROM' + #TABLENAME + ' TL
JOIN ABACUS AB
ON TL.REF = AB.REF
AND TL.SUBS = AB.SUBS
WHERE ' + #COLUMN1 + ' IS NULL
AND ' + #COLUMN2 +' IS NULL';
SET #COLUMN1 = (SELECT CONCAT('USER_ID', '8'))
SET #COLUMN2 = (SELECT CONCAT('USER_ID', '6'))
SET #TABLENAME = 'POLICYREF';
EXEC sys.sp_executesql #SQL, #TABLENAME, #COLUMN1, #COLUMN2;
SET #TABLENAME = 'USERREF';
EXEC sys.sp_executesql #SQL, #TABLENAME, #COLUMN1, #COLUMN2;

You need dynamic SQL, not parameters. You can't parameterize column names or table names. So something like:
DECLARE #SQL NVARCHAR(MAX)
DECLARE #COLUMN1 NVARCHAR(10) = 'USER_ID8'
DECLARE #COLUMN2 NVARCHAR(10) = 'USER_ID6'
DECLARE #TABLENAME NVARCHAR(10) = 'POLICYREF'
SET #SQL = 'UPDATE TL
SET '+ quotename(#COLUMN1) + '= AB.COLUMN1,'
+ quotename(#COLUMN2) + '= AB.COLUMN2
FROM ' + quotename(#TABLENAME) + ' TL
JOIN ABACUS AB
ON TL.REF = AB.REF
AND TL.SUBS = AB.SUBS
WHERE ' + quotename(#COLUMN1) + ' IS NULL
AND ' + quotename(#COLUMN2) +' IS NULL';
EXEC (#SQL)
SET #TABLENAME NVARCHAR(10) = 'USERREF'
SET #SQL = 'UPDATE TL
SET '+ quotename(#COLUMN1) + '= AB.COLUMN1,'
+ quotename(#COLUMN2) + '= AB.COLUMN2
FROM ' + quotename(#TABLENAME) + ' TL
JOIN ABACUS AB
ON TL.REF = AB.REF
AND TL.SUBS = AB.SUBS
WHERE ' + quotename(#COLUMN1) + ' IS NULL
AND ' + quotename(#COLUMN2) +' IS NULL';
EXEC (#SQL)

Not a huge fan of this but, given that, create a stored procedure OR re-arrange to execute each after updating the #SQL, here is the stored procedure example:
Note this is missing production level things like a transaction, TRY CATCH etc. and is only for an basic UNTESTED example
CREATE PROCEDURE dbo.MyFunQuery
#SQL NVARCHAR(MAX),
#COLUMN1 NVARCHAR(10),
#COLUMN2 NVARCHAR(10),
#TABLENAME NVARCHAR(10)
AS
BEGIN
SET #SQL = 'UPDATE TL
SET '+ #COLUMN1 + '= AB.COLUMN1,'
+ #COLUMN2 + '= AB.COLUMN2
FROM ' + #TABLENAME + ' AS TL
JOIN ABACUS AS AB
ON TL.REF = AB.REF
AND TL.SUBS = AB.SUBS
WHERE ' + #COLUMN1 + ' IS NULL
AND ' + #COLUMN2 + ' IS NULL;';
EXECUTE ( #SQL );
END
--Now to call it:
DECLARE #COLUMN1 NVARCHAR(10) = 'USER_ID8',
#COLUMN2 NVARCHAR(10) = 'USER_ID6';
EXECUTE dbo.MyFunQuery #COLUMN1, #COLUMN2, #TABLENAME='POLICYREF';
EXECUTE dbo.MyFunQuery #COLUMN1, #COLUMN2, #TABLENAME='USERREF';

Related

SQL Server Dynamic insert script JSON For

43/5000
First of all I apologize for my bad english...
I am trying to write the insert procedures of all tables with a single procedure. But I have a problem like this.
DECLARE #jsondata varchar(MAX)
Set #jsondata='[{"RecordId":1,"CreatedUser":0,"CreatedDate":"2020-03-26T14:49:21.210","UpdatedDate":"2020-03-26T14:57:33.420","UpdatedUser":0,"Status":true,"IsDeleted":false,"Name":"Oyun Konsolları","Icon":"videogame_asset","Description":"Oyun Konsolları","Order":1}]';
DECLARE #cn nvarchar(50)
DECLARE #dt nvarchar(50)
DECLARE #ml nvarchar(50)
DECLARE #inserttext varchar(MAX)
DECLARE #selecttext varchar(MAX)
DECLARE #jsoncol varchar(MAX)
DECLARE #tablename varchar(50)
SET #tablename = 'Categories'
SET #inserttext = ' INSERT INTO '+#tablename+' ( ';
SET #selecttext = ' SELECT ';
SET #jsoncol = ') WITH (';
DECLARE #schema nvarchar(max) = N''
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT
c.name 'Column Name',
t.Name 'Data type',
c.max_length 'Max Length'
FROM
sys.columns c
INNER JOIN
sys.types t ON c.user_type_id = t.user_type_id
WHERE
c.object_id = OBJECT_ID(#tablename)
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO #cn,#dt,#ml
WHILE ##FETCH_STATUS = 0
BEGIN
IF(#cn NOT IN('CreatedUser','CreatedDate','UpdatedDate','UpdatedUser','Status','IsDeleted','RecordId','Status','IsDeleted'))
BEGIN
--Do something with Id here
SET #inserttext = #inserttext + '['+#cn + '], ';
SET #selecttext = #selecttext + '['+ #cn + '], ';
IF(#dt = 'varchar' OR #dt='nvarchar' )
BEGIN
SET #jsoncol = #jsoncol + '['+#cn + '] ' + #dt + ' (' +#ml + '), '
END
ELSE
BEGIN
SET #jsoncol = #jsoncol + '['+#cn + '] ' + #dt +', '
END
END
FETCH NEXT FROM MY_CURSOR INTO #cn,#dt,#ml
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
SET #jsoncol = LEFT(#jsoncol, LEN(#jsoncol) - 1)
SET #inserttext = LEFT(#inserttext, LEN(#inserttext) - 1)
SET #selecttext = LEFT(#selecttext, LEN(#selecttext) - 1)
SET #inserttext =#inserttext + ' )';
SET #jsoncol = #jsoncol + ' )';
EXEC( #inserttext + ' '+ #selecttext + ' ' +' FROM OPENJSON('+#jsondata+ #jsoncol);
Error i get after running :
Msg 103, Level 15, State 4, Line 1 The identifier that
starts with
'{"RecordId":1,"CreatedUser":0,"CreatedDate":"2020-03-26T14:49:21.210","UpdatedDate":"2020-03-26T14:57:33.420","UpdatedUser":0,"S'
is too long. Maximum length is 128.
Completion time: 2020-09-25T10:42:41.2474477+03:00
29/5000
Is it possible ?
in short, is it possible to insert into tables from json as dynamic exec
declare #sql nvarchar(max) = #inserttext + ' '+ #selecttext + ' ' +' FROM OPENJSON(#thejsondata'+ #jsoncol;
exec sp_executesql #stmt=#sql, #params=N'#thejsondata nvarchar(max)', #thejsondata = #jsondata;

Declare temp table and insert into in query

I try to call declare temp table in my query but it say
"Must declare the table variable "#MDLTable"."
Here my coding:
DECLARE #dbname AS NVARCHAR(50);
SELECT #dbname = DB_NAME();
PRINT #dbname;
DECLARE #sql NVARCHAR(1000) ;
DECLARE #MDLTable AS TABLE(MDLID BIGINT, MDLRLVR INT)
SET #sql = 'INSERT INTO ' + #MDLTable + ' (MDLID, MDLRLVR)
SELECT DISTINCT a.MDLID, a.MDLRLVR FROM ' + #dbname + '.dbo.EUSYSRSRRL a
INNER JOIN ' + #dbname + '.dbo.EUSYSIROE b ON a.MDLID = b.MDLID
INNER JOIN ' + #dbname + '.dbo.EUSYSEAPML c ON b.EAPMLID = c.EAPMLID
WHERE c.REEID = ' + CONVERT(nvarchar(50),6) + ''
exec (#sql);
You can do this by using insert . . . exec:
SET #sql = '
SELECT DISTINCT a.MDLID, a.MDLRLVR
FROM ' + #dbname + '.dbo.EUSYSRSRRL a JOIN
' + #dbname + '.dbo.EUSYSIROE b
ON a.MDLID = b.MDLID JOIN
' + #dbname + '.dbo.EUSYSEAPML c
ON b.EAPMLID = c.EAPMLID
WHERE c.REEID = ' + CONVERT(nvarchar(50), 6) + '';
INSERT INTO #MDLTable (MDLID, MDLRLVR)
exec(#sql);

How to pass Server Name dynamically in SQL Server

SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX),
#servername NVARCHAR(255)
SET #servername = '[s-printstream]'
--Drop Table #Actual
CREATE TABLE #Actual
(
jobnumber INT,
firstNameCounts VARCHAR(25),
lastNameCounts VARCHAR(25),
address1Counts VARCHAR(25),
address2Counts VARCHAR(25),
cityCounts VARCHAR(25),
stateCounts VARCHAR(25),
zipCounts VARCHAR(25),
inHomeDateCounts VARCHAR(25)
)
SET #sql = 'INSERT INTO #actual (jobnumber,firstNameCounts,lastNameCounts , address1Counts, address2Counts, cityCounts, stateCounts, zipCounts, inHomeDateCounts) '
SET #sql = #sql + ' Select s.jobnumber, count(s.firstName) AS [firstNameCounts], Count (s.lastName) AS [lastNameCounts], Count (s.Address1) As [address1Counts], Count (s.address2)-Count (address2) AS '
SET #sql = #sql + ' [address2Counts], Count (s.City) AS [cityCounts], Count (s.State) AS [stateCounts], Count (s.Zip) AS [zipCounts], Count (jb.inHomeDate) AS [inHomeDateCounts] '
SET #sql = #sql + ' From' + ' #servername ' + '.[tdis_417133]' + '.[dbo].[tblStandardFinal] s '
SET #sql = #sql + ' INNER JOIN [s-printstream].[tdSchedule2].[dbo].[tblJobTicketActions] jb '
SET #sql = #sql + ' ON jb.psFlagJobNumber = s.jobNumber '
SET #sql = #sql + ' where jobNumber = #jobNumber '
SET #sql = #sql + ' group by jobNumber '
PRINT #SQL
EXEC sp_executesql #sql
,N'#JobNumber Varchar(25)'
,#JobNumber = 417133
Could anyone please help me find out how I would pass my server name dynamically as well as the database name? When I try to do it, I get this error:
Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "#servername"
Any help is appreciated.
Thanks
or pass #servername value into sql command
EXEC sp_executesql #sql
,N'#JobNumber Varchar(25),#servername nvarchar(255)'
,#JobNumber = 417133,#servername=#servername

nvarchar limits to 8000 characters within stored procedure

I have a problem with my stored procedure :
ALTER PROCEDURE [dbo].[Sp_Calculate_TimeSheet_Global_Info]
#DateDebut date,
#DateFin date,
#UserId int,
#CA varchar(10)
AS
BEGIN
DECLARE #TaskQuery nvarchar(MAX) ;
DECLARE #OPENQUERY nvarchar(MAX),#TSQL nvarchar(MAX), #LinkedServer nvarchar(MAX);
DECLARE #DateDebut1 date;
DECLARE #DateFin1 date;
DECLARE #UserId1 int;
DECLARE #Query nvarchar(MAX);
DECLARE #cond1 nvarchar(MAX);
DECLARE #cond2 nvarchar(MAX);
DECLARE #cond3 nvarchar(MAX);
DECLARE #cond4 nvarchar(MAX);
DECLARE #cond5 nvarchar(MAX);
DECLARE #cond6 nvarchar(MAX);
DECLARE #cond7 nvarchar(MAX);
DECLARE #cond8 nvarchar(MAX);
DECLARE #cond9 nvarchar(MAX);
DECLARE #cond10 nvarchar(MAX);
DECLARE #cond11 nvarchar(MAX);
DECLARE #cond12 nvarchar(MAX);
DECLARE #cond13 nvarchar(MAX);
DECLARE #op nvarchar(MAX);
DECLARE #where nvarchar(MAX);
DECLARE #exec nvarchar(MAX);
SET NOCOUNT ON;
SET #LinkedServer = 'TASK'
SET #OPENQUERY = 'SELECT * FROM OPENQUERY('+ #LinkedServer + ','''
SET #DateDebut1 = #DateDebut;
SET #DateFin1 = #DateFin;
SET #UserId1 = #UserId;
set #op = ' UNION ';
set #where = ' where 1=1 ';
set #cond1 = ' LEFT OUTER JOIN tickets tkt ON tkt.ttick_id = h.ttick_id ';
set #cond2 = ' RIGHT OUTER JOIN tickets tkt ON tkt.ttick_id = h.ttick_id ';
set #cond3 = ' LEFT OUTER JOIN ptasks tsk ON h.ptask_id = tsk.ptask_id ';
set #cond4 = ' RIGHT OUTER JOIN tasks tsk ON h.ptask_id = tsk.ptask_id ';
set #cond5 = ' LEFT OUTER JOIN phases ph ON tsk.phase_id = ph.phase_id ';
set #cond6 = ' RIGHT OUTER JOIN tasks tsk ON h.ptask_id = tsk.ptask_id ';
set #cond7 = ' LEFT OUTER JOIN projects p ON ph.proj_id = p.proj_id ';
set #cond8 = ' RIGHT OUTER JOIN projects p ON ph.proj_id = p.proj_id ';
set #cond9 = ' and h.hours_spent >= str_to_date(''''' + convert(varchar,#DateDebut,103) + ''''', ''''%d/%m/%Y'''')';
set #cond10 = ' and h.hours_spent <= str_to_date(''''' + convert(varchar,#DateFin,103) + ''''', ''''%d/%m/%Y'''')';
set #cond11 = ' and h.user_id=' + cast(#UserId as varchar);
set #cond12 = ' and
( ph.phase_name like ''''' + '%' + #CA +'%' +''''' and (p.proj_name not like ''''' + '%' + #CA +'%' +''''' or p.proj_name is null) ) or
( (ph.phase_name not like ''''' + '%' + #CA +'%' +''''' or ph.phase_name is null) and (p.proj_name not like ''''' + '%' + #CA +'%' +''''' or p.proj_name is null) and tsk.ptask_name like ''''' + '%' + #CA +'%' +''''') or
( (ph.phase_name not like ''''' + '%' + #CA +'%' +''''' or ph.phase_name is null) and (p.proj_name not like ''''' + '%' + #CA +'%' +''''' or p.proj_name is null) and (tsk.ptask_name not like ''''' + '%' + #CA +'%' +''''' or tsk.ptask_name is null) and tkt.ttick_name like ''''' + '%' + #CA +'%' +''''') or
( (p.proj_name not like ''''' + '%' + #CA +'%' +''''' or p.proj_name is null) and tsk.ptask_name like ''''' + '%' + #CA +'%' +''''' and (tsk.phase_id is null or tsk.phase_id =-1) ) or
( (p.proj_name not like ''''' + '%' + #CA +'%' +''''' or p.proj_name is null) and tkt.ttick_name like ''''' + '%' + #CA +'%' +''''')
';
set #cond13 = ''') src';
SET #TaskQuery =N' SELECT h.hours_id , h.hours_spent as TimeSheet_Date, h.hours_hours as Hour_Number,h.hours_note as Hour_Note,(case when h.ttick_id is null or h.ttick_id=-1 then tsk.ptask_name else tkt.ttick_name end) as Task_Ticket_Libelle,(case when h.ttick_id is null or h.ttick_id=-1 then h.ptask_id else h.ttick_id end) as Task_Ticket_Id,h.proj_id as Project_Id,(case when h.ttick_id is null or h.ttick_id=-1 then 1 else 0 end) as Is_Task,h.user_id as User_Id,p.proj_name as Project_Name, u.user_uname as User_Name from users u RIGHT OUTER JOIN user_hours h on u.user_id=h.user_id ' ;
SET #Query = #TaskQuery ;
SET #TaskQuery = #Query+ #cond1 ;
SET #TaskQuery = #TaskQuery + #op + #Query + #cond2 ;
SET #Query = #TaskQuery ;
SET #TaskQuery = #Query + #cond3 ;
SET #TaskQuery =#TaskQuery + #op + #Query + #cond4 ;
SET #Query = #TaskLandQuery ;
SET #TaskQuery = #Query + #cond5 ;
SET #TaskQuery =#TaskQuery + #op + #Query + #cond6 ;
SET #Query = #TaskQuery ;
SET #TaskQuery = #Query + #cond7 ;
SET #TaskQuery =#TaskQuery + #op + #Query + #cond8 ;
SET #TaskQuery = #TaskQuery + #where ;
IF(#DateDebut is not null)
BEGIN
SET #TaskQuery = #TaskQuery + #cond9 ;
END
IF(#DateFin is not null)
BEGIN
SET #TaskQuery =#TaskQuery + #cond10 ;
END
IF(#UserId is not null)
BEGIN
SET #TaskQuery = #TaskQuery + #cond11 ;
END
IF(#CA is not null)
BEGIN
SET #TaskQuery = #TaskQuery + #cond12 ;
END
set #TaskQuery = #TaskQuery + #cond13 ;
set #exec = #OPENQUERY+#TaskQuery;
delete from [dbo].[Timesheet_Global_Info];
insert into [dbo].[Timesheet_Global_Info](
[hours_id]
,[TimeSheet_Date]
,[Hour_Number]
,[Hour_Note]
,[Task_Ticket_Libelle]
,[Task_Ticket_Id]
,[Project_Id]
,[Is_Task]
,[User_Id]
,[Project_Name]
,[User_Name]
)
EXEC (#exec) ;
END
When I execute this procedure, I get this error:
Msg 103, Level 15, State 1, Line 3
The string that starts with SELECT h.hours_id, h.hours_spent have TimeSheet_Date, h.hours_hours have Hour_Number, h.hours_note have Hour_Note, (CASE WHEN h.ttick 'is too long. The maximum length is 8000.
the exception is due to this line EXEC (#exec) ; .
So I need to know
What is the reason of this error?
How can I fix it?
You are using OPENQUERY and as per MSDN, the max size for query is 8KB i.e. 8000 characters which is exceeding in your query.
OPENQUERY ( linked_server ,'query' )
' query ' Is the query string executed in the linked server. The
maximum length of the string is 8 KB.
Why not use sp_executesql?
EXEC sp_executesql #exec
As I can see #exec is nvarchar(max), you can pass it without a problem.
On 64-bit servers, the size of the string is limited to 2 GB, the maximum size of nvarchar(max).
EDIT
Use sp_executesql INSTEAD of OPENQUERY
DECLARE #paramDef nvarchar(max) = '#TaskQuery nvarchar(max)'
SELECT #exec = 'INSERT INTO [dbo].[Timesheet_Global_Info] EXEC '+QUOTENAME(#LinkedServer)+'.database.dbo.sp_executesql #TaskQuery',
EXEC sp_executesql #exec, #paramDef, #TaskQuery=#TaskQuery
You exceed the max length character, in this type of case you have to split your dynamic query in multiple part and execute by combine.
Declare #Query1 VARCHAR(MAX),#Query2 VARCHAR(MAX)
SET #Query1='SELECT * FROM'
SET #Query2=' Employee'
EXEC (#Query1+#Query2)
In your case may be
EXEC (#OPENQUERY+#TaskQuery);
If you still got same error, please split your variables into more...

the name is not a valid identifier. error in dynamic stored procudure

my stored procudure is :
ALTER PROCEDURE [dbo].[Asbabbazi_A]
#name_product nvarchar(50),
#first_price int,
#final_price int,
#collection_1 nvarchar(30),
#id_state tinyint
AS
BEGIN
DECLARE #SQLstring nvarchar(1000)
DECLARE #PARAMS nvarchar(1000)
set #SQLstring = 'SELECT IDproduct,name_product,first_price,final_price,max_registered_price,
date_record_shamsi,final_date_view_shamsi,
count_views,image_1,collection_1 from Table_asbabbazi where active=0 '
if(#name_product != 'no name')
set #SQLstring = #SQLstring + ' AND (name_product LIKE %#name_product%)'
if (#final_price != 0)
set #SQLstring = #SQLstring + ' AND ( first_price between #first_price AND #final_price )'
if (#collection_1 != 'انتخاب کنید')
set #SQLstring = #SQLstring + ' AND (collection_1 = #collection_1 )'
if (#id_state != 0)
set #SQLstring = #SQLstring + ' AND (id_state = #id_state )'
execute #SQLstring
END
when execute show this error:
The name 'SELECT IDproduct,name_product,first_price,final_price,max_registered_price,
date_record_shamsi,final_date_view_shamsi,
count_views,image_1,collection_1 from Table_asbabbazi where active=0 AND (name_product LIKE %#name_product%) AND (collection_1 = #collection_1 )' is not a valid identifier.
please help
Some parameters in a query string are not parsed correctly, and you are using dynamic sql it must be executed by EXECUTE sp_executesql statement. This is the correct way to execute dynamic sql:
ALTER PROCEDURE [dbo].[Asbabbazi_A]
#name_product nvarchar(50),
#first_price int,
#final_price int,
#collection_1 nvarchar(30),
#id_state tinyint
AS
BEGIN
DECLARE #SQLstring nvarchar(1000)
DECLARE #PARAMS nvarchar(1000)
set #SQLstring = 'SELECT IDproduct,name_product,first_price,final_price,max_registered_price,
date_record_shamsi,final_date_view_shamsi,
count_views,image_1,collection_1 from Table_asbabbazi where active=0 '
if(#name_product != 'no name')
set #SQLstring = #SQLstring + ' AND name_product LIKE ''%' + #name_product + '%''' + ' '
if (#final_price != 0)
set #SQLstring = #SQLstring + ' AND first_price between ' + CONVERT(nvarchar(1000), #first_price) + ' AND ' + CONVERT(nvarchar(1000), #final_price) + ' '
if (#collection_1 != 'انتخاب کنید')
set #SQLstring = #SQLstring + ' AND collection_1 = ''' + #collection_1 + ''' '
if (#id_state != 0)
set #SQLstring = #SQLstring + ' AND id_state = ' + CONVERT(nvarchar(1000), #id_state) + ' '
EXECUTE sp_executesql #SQLstring
END
In brief,
put declared SQLstring inside Parenthesis when execute stored procedure like this
👉 EXECUTE usp_executeSql (#SQLstring)
Example:
False ❌
EXECUTE usp_executeSql #SQLstring
True ✔
EXECUTE usp_executeSql (#SQLstring)
You have your variables inside quotes thus making them string literals. Instead of this sort of thing:
set #SQLstring = #SQLstring + ' AND (collection_1 = #collection_1 )'
you need this sort of thing:
set #SQLstring = #SQLstring + ' AND (collection_1 = '
+ #collection_1 + ' )'