nvarchar limits to 8000 characters within stored procedure - sql

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...

Related

how to create a dynamic update query with variables?

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';

Dynamic SQL - parametrized query

I use dynamic sql with parameters and have problem :)
In block of code it works, but when I call procedure I have error that I need to declare scalar variable #name_dummy
So:
DECLARE #START_TIME DATETIME = GETDATE()
DECLARE #TMP_NAMES TABLE (
SCHEMA_N VARCHAR(500),
TABLE_N VARCHAR(500),
CONDITION VARCHAR(MAX),
TARGETDB VARCHAR(500),
SOURCEDB VARCHAR(500),
COLUMN_LIST VARCHAR(MAX)
)
DECLARE #SCHEMA_N VARCHAR(500)
DECLARE #TABLE_N VARCHAR(500)
DECLARE #CONDITION VARCHAR(MAX)
DECLARE #COLUMN_LIST VARCHAR(MAX)
DECLARE #TARGETDB VARCHAR(500)
DECLARE #SOURCEDB VARCHAR(500)
INSERT INTO #TMP_NAMES
SELECT
o.SCHEMA_N
,o.TABLE_N
,o.Condition
,o.TargetDB
,o.SourceDB
,STUFF((SELECT
', ' + c.name
FROM sys.columns c
WHERE c.object_id = o.object_id
AND c.system_type_id <> 189 /* Pomijam timestamp*/
ORDER BY c.column_id
FOR XML PATH (''))
, 1, 1, '')
FROM Table_A o
ORDER BY 1,
2
SELECT
SCHEMA_N
,TABLE_N
,CONDITION
,TARGETDB
,SOURCEDB
,COLUMN_LIST
FROM #TMP_NAMES
DECLARE KUR CURSOR
FOR
SELECT
SCHEMA_N
,TABLE_N
,CONDITION
,TARGETDB
,SOURCEDB
,COLUMN_LIST
FROM #TMP_NAMES
OPEN KUR
FETCH NEXT
FROM KUR
INTO #SCHEMA_N,
#TABLE_N,
#CONDITION,
#TARGETDB,
#SOURCEDB,
#COLUMN_LIST
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #TOP VARCHAR(100)
SET #TOP = ( SELECT CAST(Wartosc AS VARCHAR) FROM Table_B WHERE Id = 3 )
IF #TOP < 40000
SET #TOP = 40000
WHILE ( 1 = 1 )
BEGIN
DECLARE #CHECK BIT = 0
DECLARE #sqlCMD NVARCHAR(MAX) = 'SELECT TOP 1 #check_exists = 1 FROM '
+ #SOURCEDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ' WHERE ' + #CONDITION
exec sp_executesql #sqlCMD, N'#check_exists bit OUTPUT, #START_TIME DATE', #check_exists = #CHECK OUTPUT, #START_TIME = #START_TIME;
SELECT #sqlCMD , #CHECK
END
END
FETCH NEXT
FROM KUR
INTO #SCHEMA_N,
#TABLE_N,
#CONDITION,
#TARGETDB,
#SOURCEDB,
#COLUMN_LIST
CLOSE KUR;
DEALLOCATE KUR
And when I execute this it's compiling and works ( returns values ) for example sql which I want to execute.
SELECT TOP 1 #check_exists = 1 FROM MSSF15_WarstwaPosrednia.KatalogZdarzen.MSSF_RaportZdarzenPLKB2CS2K WHERE StatusPrzetwarzania = 4 AND DataWpisu < DATEADD(MONTH, -3, #START_TIME)
Parameters work here ( #check_exists which is output and #START_TIME condition param ) , but when I execute this in procedure I'm getting error
Must declare the scalar variable "#START_TIME". 137
SP definition:
USE xxxx
/****** Object: StoredProcedure dbo.dummy Script Date: 06/09/2018 13:40:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE dbo.dummy
AS
BEGIN
/*
PRZENIESIENIE DANYCH
*/
DECLARE #START_TIME DATETIME = GETDATE()
DECLARE #TMP_NAMES TABLE (
SCHEMA_N VARCHAR(500),
TABLE_N VARCHAR(500),
CONDITION VARCHAR(MAX),
TARGETDB VARCHAR(500),
SOURCEDB VARCHAR(500),
COLUMN_LIST VARCHAR(MAX)
)
DECLARE #SCHEMA_N VARCHAR(500)
DECLARE #TABLE_N VARCHAR(500)
DECLARE #CONDITION VARCHAR(MAX)
DECLARE #COLUMN_LIST VARCHAR(MAX)
DECLARE #TARGETDB VARCHAR(500)
DECLARE #SOURCEDB VARCHAR(500)
INSERT INTO #TMP_NAMES
SELECT o.SCHEMA_N,
o.TABLE_N,
o.Condition,
o.TargetDB,
o.SourceDB,
STUFF((
SELECT ', ' + c.NAME
FROM sys.columns c
WHERE c.object_id = o.object_id
AND c.system_type_id <> 189 /* Pomijam timestamp*/
ORDER BY c.column_id
FOR XML PATH('')
), 1, 1, '')
FROM dbo.Table_A o
ORDER BY 1,
2
SELECT SCHEMA_N,
TABLE_N,
CONDITION,
TARGETDB,
SOURCEDB,
COLUMN_LIST
FROM #TMP_NAMES
DECLARE KUR CURSOR
FOR
SELECT SCHEMA_N,
TABLE_N,
CONDITION,
TARGETDB,
SOURCEDB,
COLUMN_LIST
FROM #TMP_NAMES
OPEN KUR
FETCH NEXT
FROM KUR
INTO #SCHEMA_N,
#TABLE_N,
#CONDITION,
#TARGETDB,
#SOURCEDB,
#COLUMN_LIST
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #TOP VARCHAR(100)
SET #TOP = (
SELECT CAST(Wartosc AS VARCHAR)
FROM dbo.Table_B
WHERE Id = 3
)
IF #TOP < 40000
SET #TOP = 40000
WHILE (1 = 1)
BEGIN
BEGIN TRY
BEGIN TRANSACTION T_TEST
DECLARE #CHECK BIT = 0
DECLARE #START_TIME_P DATE = GETDATE()
DECLARE #sqlCMD NVARCHAR(MAX) = 'SELECT TOP 1 #check_exists = 1 FROM ' + #SOURCEDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ' WHERE ' + #CONDITION
SELECT #CHECK,
#START_TIME_P,
#sqlCMD
EXEC sp_executesql #sqlCMD,
N'#check_exists bit OUTPUT, #START_TIME DATE',
#check_exists = #CHECK OUTPUT,
#START_TIME = #START_TIME_P;
IF OBJECT_ID('tempdb..#TMP_ID') IS NOT NULL
DROP TABLE #TMP_ID
CREATE TABLE #TMP_ID (Id INT)
EXEC (
'INSERT INTO #TMP_ID
SELECT TOP ' + #TOP + ' Id
FROM ' + #SOURCEDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ' WHERE ' + #CONDITION
)
DECLARE #sqlCMD_Ins NVARCHAR(MAX)
SET #sqlCMD_Ins = 'INSERT INTO ' + #TARGETDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ' '
SET #sqlCMD_Ins = #sqlCMD_Ins + 'SELECT ' + #COLUMN_LIST + ' FROM ' + #SOURCEDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ' WHERE Id IN ( SELECT Id FROM #TMP_ID )'
IF #sqlCMD_Ins IS NULL
RAISERROR (
'Brak polecenia insert #sqlCMD_Ins',
16,
1
)
EXEC (#sqlCMD_Ins)
DECLARE #sqlCMD_Del NVARCHAR(MAX)
SET #sqlCMD_Del = 'DELETE FROM ' + #SOURCEDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ' WHERE Id IN ( SELECT Id FROM #TMP_ID )'
IF #sqlCMD_Del IS NULL
RAISERROR (
'Brak polecenia insert #sqlCMD_Ins',
16,
1
)
EXEC (#sqlCMD_Del)
DROP TABLE #TMP_ID
COMMIT TRANSACTION T_TEST
END TRY
BEGIN CATCH
IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRANSACTION T_TEST
PRINT 'Wycofanie zmian'
PRINT ERROR_MESSAGE() + ' ' + CAST(ERROR_NUMBER() AS VARCHAR(256))
END
END CATCH
IF #CHECK = 0
BREAK
END
EXEC ('SELECT ''' + #SOURCEDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ''' AS DB ,COUNT(1) AS ILOSC FROM ' + #SOURCEDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ' UNION ALL ' + 'SELECT ''' + #TARGETDB + '.' + #SCHEMA_N + '.' + #TABLE_N + ''' AS DB ,COUNT(1) AS ILOSC FROM ' + #TARGETDB + '.' + #SCHEMA_N + '.' + #TABLE_N)
FETCH NEXT
FROM KUR
INTO #SCHEMA_N,
#TABLE_N,
#CONDITION,
#TARGETDB,
#SOURCEDB,
#COLUMN_LIST
END
CLOSE KUR;
DEALLOCATE KUR;
DECLARE #END_TIME DATETIME = GETDATE()
SELECT 'Daty przetworzenia',
#START_TIME_P AS 'START',
#END_TIME AS 'END'
SELECT 'Czas (min)',
DATEDIFF(MINUTE, #START_TIME_P, #END_TIME)
END
Guys, maybe u have similar situation and can help.
Error msg
Wycofanie zmian
Must declare the scalar variable "#START_TIME". 137
Thanks
Instead of
exec sp_executesql #sqlCMD, N'#check_exists bit OUTPUT, #START_TIME DATE', #check_exists = #CHECK OUTPUT, #START_TIME = #START_TIME;
try
declare #date_in DATE = GETDATE()
exec sp_executesql #sqlCMD, N'#check_exists bit OUTPUT, #START_TIME DATE', #check_exists = #CHECK OUTPUT, #START_TIME = #date_in;

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);

Declare Scalar variable

I am writing a dynamic SQL statement that is failing with the error
Must declare the scalar variable "##config"
I have tried to break the code down and can confirm that the following code does return results:
Declare ##sql as nvarchar(max);
Declare #SourceDatabase as nvarchar(10);
Declare #DestDatabase as nvarchar(10);
Declare ##Harray as nvarchar(max) ;
Set #SourceDatabase = 'D_EXP_CPM';
Set #DestDatabase = 'T_EXP_CPM';
set ##sql = 'SELECT B.Hierarchy_SKey AS ''NEW'', A.Hierarchy_SKey AS ''OLD''
INTO ##TEMPHCONVERT
FROM ' + #SourceDatabase + '.[dbo].[DIM_HIERARCHY] A
INNER JOIN ' + #DestDatabase + '.[dbo].[DIM_HIERARCHY] B
ON A.Hierarchy_Desc = B.Hierarchy_Desc
WHERE A.Hierarchy_SKey in (' + ##Harray + ');'
exec (##sql);
Declare ##config as NVARCHAR(MAX);
SELECT ##config = COALESCE(##config + ', H' + cast(A.[NEW] as nvarchar), 'H' + cast(A.[NEW] as nvarchar))
FROM ##TEMPHCONVERT A;
Print ##config
Which returns the value: "H15, H16, H17, H18"
When this is plugged into the dynamic SQL statement though I get the error...
Declare #SourceDatabase as nvarchar(10)
Declare #DestDatabase as nvarchar(10)
Declare ##sql as nvarchar(max) --variable to hold sql statements for this stored proc
Declare ##Harray as nvarchar(max) -- variable to hold hierarchy array elements from source
Set #SourceDatabase = 'D_EXP_CPM';
Set #DestDatabase = 'T_EXP_CPM';
Declare ##config as NVARCHAR(MAX);
set ##sql =
'SELECT
B.Hierarchy_SKey AS ''NEW'', A.Hierarchy_SKey AS ''OLD''
INTO ##TEMPHCONVERT
FROM ' + #SourceDatabase + '.[dbo].[DIM_HIERARCHY] A
INNER JOIN ' + #DestDatabase + '.[dbo].[DIM_HIERARCHY] B
ON A.Hierarchy_Desc = B.Hierarchy_Desc
WHERE A.Hierarchy_SKey in (' + ##Harray + ');'
exec (##sql);
set ##sql = '
UPDATE A SET A.[Value_Text] = (SELECT ##config = COALESCE(##config + '', H'' + cast(A.[NEW] as nvarchar), ''H'' + cast(A.[NEW] as nvarchar))
FROM ##TEMPHCONVERT A)
FROM ' + #DestDatabase + '.[dbo].[DIM_CONFIG] A ON A.[Config_Desc] = ''JBCODE FTE Map Hierarchy List'' ;'
exec (##sql);
Note I've cut quite a bit of code out of the middle here to make the post as short as possible. Can anybody explain why I'm getting the error?
I've tried declaring the variable inside the dynamic SQL statement in two places but neither allowed the code to run. I'm thinking maybe the variable needs passing somehow but I'm not sure how to do that through to the sub query.
Put the ##config Declaration in the ##sql string:
Declare #SourceDatabase as nvarchar(10)
Declare #DestDatabase as nvarchar(10)
Declare ##sql as nvarchar(max) --variable to hold sql statements for this stored proc
Declare ##Harray as nvarchar(max) -- variable to hold hierarchy array elements from source
Set #SourceDatabase = 'D_EXP_CPM';
Set #DestDatabase = 'T_EXP_CPM';
set ##sql =
'SELECT
B.Hierarchy_SKey AS ''NEW'', A.Hierarchy_SKey AS ''OLD''
INTO ##TEMPHCONVERT
FROM ' + #SourceDatabase + '.[dbo].[DIM_HIERARCHY] A
INNER JOIN ' + #DestDatabase + '.[dbo].[DIM_HIERARCHY] B
ON A.Hierarchy_Desc = B.Hierarchy_Desc
WHERE A.Hierarchy_SKey in (' + ##Harray + ');'
exec (##sql);
set ##sql = 'Declare ##config as NVARCHAR(MAX)
UPDATE A SET A.[Value_Text] = (SELECT COALESCE(##config + '', H'' + cast(A.[NEW] as nvarchar), ''H'' + cast(A.[NEW] as nvarchar))
FROM ##TEMPHCONVERT A)
FROM ' + #DestDatabase + '.[dbo].[DIM_CONFIG] A ON A.[Config_Desc] = ''JBCODE FTE Map Hierarchy List'' ;'
exec (##sql);
I'm not sure why you are getting the error, but this is a slight rewrite from what you have. Rather than concatenating a long string, I like to declare a template and then replace the parameters before executing. It just makes it more readable to me. I moved all of the related code into ##sql and just return the results in a temp table.
Declare ##sql as nvarchar(max);
Declare #SourceDatabase as nvarchar(10);
Declare #DestDatabase as nvarchar(10);
Declare ##Harray as nvarchar(max) ;
Set #SourceDatabase = 'D_EXP_CPM';
Set #DestDatabase = 'T_EXP_CPM';
set ##Harray = '1,2,3';
set ##sql = '
SELECT B.Hierarchy_SKey AS ''NEW'', A.Hierarchy_SKey AS ''OLD''
INTO #TEMPHCONVERT
FROM [[source]].[dbo].[DIM_HIERARCHY] A
INNER JOIN [[dest]].[dbo].[DIM_HIERARCHY] B
ON A.Hierarchy_Desc = B.Hierarchy_Desc
WHERE A.Hierarchy_SKey in ([Harray]);
Declare ##config as NVARCHAR(MAX);
SELECT ##config = COALESCE(##config + '', H'' + cast(A.[NEW] as nvarchar), ''H'' + cast(A.[NEW] as nvarchar))
FROM #TEMPHCONVERT A;
select [config] = ##config into ##config
'
set ##sql = replace(##sql, '[source]', #SourceDatabase)
set ##sql = replace(##sql, '[dest]', #DestDatabase)
set ##sql = replace(##sql, '[Harray]', ##Harray)
exec (##sql);
select * from ##config
drop table ##config
Declare #config as NVARCHAR(MAX);
SELECT #config = COALESCE(#config + ', H' + cast(A.[NEW] as nvarchar), 'H' + cast(A.[NEW] as nvarchar))
FROM #TEMPHCONVERT A;
set #sql = 'UPDATE A SET A.[Value_Text] = (#config )
FROM ' + #DestDatabase + '.[dbo].[DIM_CONFIG] A WHERE A.[Config_Desc] = ''JBCODE FTE Map Hierarchy List'' ;'
PRINT 'STEP 15 COMPLETE';

Best practise custom paging SQL server 2005

I'm got trouble with paging on SQL server 2005 which run query 2 times (get data and total rows). My demo proc below which base on Northwind database. Please help me to how to get total rows without query again.
CREATE PROCEDURE [dbo].[SearchEmployees]
#search nvarchar(4000)
,#orderBy varchar(200)
,#PageSize int
,#PageIndex int
,#TotalRowsNumber int output
AS
DECLARE #PageLowerBound int
DECLARE #PageUpperBound int
SET #PageLowerBound = #PageSize * #PageIndex
SET #PageUpperBound = #PageSize + #PageLowerBound
--Default order by to first column
IF (#OrderBy is null or LEN(#OrderBy) < 1)
BEGIN
SET #OrderBy = 'EmployeeID DESC'
END
-- SQL Server 2005 Paging
declare #SQL as nvarchar(4000)
declare #SQLCOUNT as nvarchar(4000)
declare #Param as nvarchar(500)
SET #SQL = 'WITH PageIndex AS ('
SET #SQL = #SQL + ' SELECT '
IF #PageSize > 0
BEGIN
SET #SQL = #SQL + ' TOP ' + convert(nvarchar, #PageUpperBound)
END
SET #SQL = #SQL + ' ROW_NUMBER() OVER (ORDER BY ' + #OrderBy + ') as RowIndex '
SET #SQL = #SQL + ' ,EmployeeID'
SET #SQL = #SQL + ', LastName'
SET #SQL = #SQL + ', FirstName'
SET #SQL = #SQL + ', Title'
SET #SQL = #SQL + ' FROM employees'
IF Len(#Search) > 0
BEGIN
SET #SQL = #SQL + ' ' + #Search
END
SET #SQL = #SQL + ') SELECT '
SET #SQL = #SQL + ' EmployeeID'
SET #SQL = #SQL + ', LastName'
SET #SQL = #SQL + ', FirstName'
SET #SQL = #SQL + ', Title'
SET #SQL = #SQL + ' FROM PageIndex '
SET #SQL = #SQL + ' WHERE RowIndex > ' + convert(nvarchar, #PageLowerBound)
IF #PageSize > 0
BEGIN
SET #SQL = #SQL + ' AND RowIndex <= ' + convert(nvarchar, #PageUpperBound)
END
--Get Row Count
SET #SQLCOUNT = 'SELECT #TotalRowsNumber = count(EmployeeID)
FROM employees'
SET #Param = N'#Search nvarchar(2000),#TotalRowsNumber INT OUTPUT'
IF LEN(#Search) > 0
BEGIN
SET #SQLCOUNT = #SQLCOUNT + #Search
END
exec sp_executesql #SQL
exec sp_executesql #SQLCOUNT, #Param,#Search=#Search,#TotalRowsNumber = #TotalRowsNumber OUT
Thanks in advance!
Try Like this, See it as an example
CREATE Procedure usp_GetBookings
#pageIndex int,
#pageSize tinyint
as
;with CTE as
(
Select Distinct ROW_NUMBER() over( order by ssi.SSItineraryID desc) as seq ,Count(*) over() as TotalRow,ssi.SSItineraryID
from SightSeeingItinerary as ssi
)
select * from CTE
where cte.seq between (#pageIndex-1) * #pageSize+1 and ((#pageIndex-1) * #pageSize +(#pageSize))