Dynamic query variable error - sql-server

I have a table #months as below
MONTH_ID FISCAL_YEAR_MONTH MIN_DATE MAX_DATE
1 FSA201510 20151001 20151031
2 FSA201511 20151101 20151130
3 FSA201512 20151201 20151204
I am using below dynamic query to update a column SCCount in table mastercount(has 3 rows)-
DECLARE #sql VARCHAR(8000), #fym varchar(6)
DECLARE #I INT, #ROWS INT
SET #ROWS=(SELECT count(*) from #MONTHS)
SET #I=1
WHILE #I<=#ROWS
BEGIN
SET #fym=(SELECT RIGHT(FISCAL_YEAR_MONTH,6) from #MONTHS where month_id=#I)
SET #sql = 'UPDATE mastercount'
SET #sql += ' SET SCCount = (SELECT count(*) from '
SET #sql += ' dw_extract.dbo.dw_fsa_' + cast(#fym as varchar(6))+ ') WHERE row=#I'
EXEC (#sql)
SET #I=#I+1
END
This gives an error Must declare the scalar variable "#I".
Why is this happening?

You need to change this
SET #sql += ' dw_extract.dbo.dw_fsa_' + cast(#fym as varchar(6))+ ') WHERE row=#I'
to this
SET #sql += ' dw_extract.dbo.dw_fsa_' + cast(#fym as varchar(6))+ ') WHERE row=' + CAST(#I AS NVARCHAR(10))

That's because #I is not recognized by your dynamic query. You should parameterized #I instead and use sp_executesql to run your query:
DECLARE #sql NVARCHAR(8000), #fym VARCHAR(6)
DECLARE #I INT, #ROWS INT
SET #ROWS = (SELECT COUNT(*) FROM #MONTHS)
SET #I = 1
WHILE #I <= #ROWS
BEGIN
SET #fym = (SELECT RIGHT(FISCAL_YEAR_MONTH,6) FROM #MONTHS WHERE month_id = #I)
SET #sql = N'UPDATE mastercount'
SET #sql += N' SET SCCount = (SELECT count(*) from '
SET #sql += N' dw_extract.dbo.dw_fsa_' + cast(#fym as varchar(6))+ N') WHERE row=#I'
EXEC sp_executesql #sql, N'#I INT', #I
SET #I = #I + 1
END

Related

get value into output variable when executing stored procedure through dynamic query

i am using sql server 2008 r2, I have created a dynamic stored procedure because this is my requirement to implement to filteration of data based on certain conditions. I am not able to get value into #RecordCount
ALTER PROCEDURE [dbo].[sp_getAssetListAudit]
#type nvarchar(20),
#typeid nvarchar(5),
#clientId nvarchar(5),
#PageIndex nvarchar(5),
#PageSize nvarchar(5),
#RecordCount nvarchar(5) output
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL nvarchar(max)
SET #SQL ='
select ROW_NUMBER() OVER ( ORDER BY ad.arid ASC )
AS rownum, ad.arid,ad.ast_code,ad.ast_descp,isnull(cat.name,'''') ''cat'',ISNULL(loc.name,'''') ''loc'',isnull(gp.name,'''') ''grp'',
isnull(cc.name,'''') ''cc'' ,
ad.ast_qty ''qty'' into #Results
from tbl_AssetDetails ad
left join tbl_Category cat on ad.ast_cat = cat.catid
left join tbl_Subcategory scat on ad.ast_subcat = scat.subcatid
left join tbl_Location loc on loc.lid = ad.ast_loc
left join tbl_Group gp on gp.gid = ad.ast_grp
left join tbl_CostCenter cc on cc.ccid = ad.ast_costcen
where ad.ast_status not in (3,-1) AND ad.clientId = '+#clientId+' AND '
IF(#type='cat')
SET #SQL = #SQL +' ad.ast_cat='+#typeid+' AND '
IF(#type='subcat')
SET #SQL = #SQL +' ad.ast_subcat='+#typeid+' AND '
IF(#type='loc')
SET #SQL = #SQL +' ad.ast_loc='+#typeid+' AND '
IF(#type='grp')
SET #SQL = #SQL +' ad.ast_grp='+#typeid+' AND '
IF(#type='cc')
SET #SQL = #SQL +' ad.ast_costcen='+#typeid+' AND '
IF(#type='ast')
SET #SQL = #SQL +' ad.arid='+#typeid+' AND '
SET #SQL = #SQL +' 1=1 '
SET #SQL =#SQL + ' SELECT '+#RecordCount+' = count(*) FROM #Results '
SET #SQL = #SQL +' SELECT * FROM #Results WHERE rownum
BETWEEN('+#PageIndex+' -1) * '+#PageSize+' + 1 AND((('+#PageIndex+' -1) * '+#PageSize+'+ 1) + '+#PageSize+') - 1 '
SET #SQL = #SQL + ' drop table #Results '
EXEC sp_executesql #SQL, #RecordCount OUTPUT
END
I am not able to get value into #RecordCount and subsequently no result set.
You need to assign the value to the OUTPUT parameter:
SET #SQL =#SQL + ' SELECT #RecordCount = count(*) FROM #Results; '
You also need to pass the parameter definitions to sp_executesql as in #wannuanguo's answer. You should use also use parameters for #typeid, #pageindex, etc. too instead of literals in the query.
Add the second parameter for sp_executesql:
EXEC sp_executesql #SQL, N'#RecordCount nvarchar(5) output',#RecordCount OUTPUT

Update a declared tabled dynamic column name

I am running a SQL loop to update a declared table. Please have a look at the following
DECLARE #tblResults TABLE ( [idx] INT IDENTITY(0,1)
,[cityCode] VARCHAR(3)
,[month_1_perc] INT
,[month_2_perc] INT
,[month_3_perc] INT
,[month_4_perc] INT
,[month_5_perc] INT
,[month_6_perc] INT
,[month_7_perc] INT
,[month_8_perc] INT
,[month_9_perc] INT
,[month_10_perc] INT
,[month_11_perc] INT
,[month_12_perc] INT)
loop will start here
DECLARE #colName VARCHAR(15)
DECLARE #sqlExec VARCHAR(500) = CONACT('UPDATE #tblResults SET [month_', #colName, '_perc] = 9;
EXECUTE(#sql)
loop
This obviously doesn't work - I am trying to find a work around if any -
Open to suggestions
DECLARE #colName VARCHAR(15)
DECLARE #sqlExec VARCHAR(500)
SET #colName = '1'
SET #sqlExec = 'UPDATE #tblResults SET [month_' + #colName + '_perc] = 9'
EXECUTE( #sqlExec)
I am a bit confused with your request, but if you really want to use a loop
declare #i int = 1;
declare #sqlUpdate nvarchar(max) = 'UPDATE tblResults SET ';
declare #sql;
while #i <= 12
BEGIN
set #sql = #sqlUpdate + '[month_' + cast(#i as nvarchar(5)) + '_perc] = 9;' -- value?
print (#sql)
-- execute (#sql)
set #i = #i + 1;
END
Or you want to set same value to all columns in one go
declare #cols nvarchar(max)
select #cols = STUFF((SELECT ',' + QUOTENAME(col.name) + ' = 9' -- value?
from tempdb.sys.columns col
join tempdb.sys.tables tab on col.object_id = tab.object_id
where tempdb.tab.name = 'tblResults'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
declare #sql nvarchar(max) = 'UPDATE tblResults SET ' + #cols;
print (#sql)
-- execute (#sql)
Note, none of scripts are tested

SQL Stored Procedure select statement

I have another field in my database table called FileName, I want the record to be selected by FileName. What should I add to the code.
ALTER PROCEDURE [dbo].[spx_Pager]
#PageNo int = 1,
#ItemsPerPage int = 2,
#TotalRows int out,
#f_name nvarchar(50)
AS
BEGIN
SET NOCOUNT ON
DECLARE
#StartIdx int,
#SQL nvarchar(max),
#SQL_Conditions nvarchar(max),
#EndIdx int
IF #PageNo < 1 SET #PageNo = 1
IF #ItemsPerPage < 1 SET #ItemsPerPage = 10
SET #StartIdx = (#PageNo -1) * #ItemsPerPage + 1
SET #EndIdx = (#StartIdx + #ItemsPerPage) - 1
SET #f_name = (#f_name)
SET #SQL = 'SELECT FilePath
FROM (
SELECT ROW_NUMBER() OVER(ORDER BY ID) AS Row, *
FROM tblFiles ) AS tbl WHERE Row >= '
+ CONVERT(varchar(9), #StartIdx) + ' AND
Row <= ' + CONVERT(varchar(9), #EndIdx)
EXEC sp_executesql #SQL
SET #SQL = 'SELECT #TotalRows=COUNT(*) FROM tblFiles'
EXEC sp_executesql
#query = #SQL,
#params = N'#TotalRows INT OUTPUT',
#TotalRows = #TotalRows OUTPUT
END
You didn't give me much to go on. But is this what you need?
ALTER PROCEDURE [dbo].[spx_Pager]
#PageNo int = 1,
#ItemsPerPage int = 2,
#TotalRows int out,
#f_name nvarchar(50)
AS
BEGIN
SET NOCOUNT ON
DECLARE
#StartIdx int,
#SQL nvarchar(max),
#SQL_Conditions nvarchar(max),
#EndIdx int
IF #PageNo < 1 SET #PageNo = 1
IF #ItemsPerPage < 1 SET #ItemsPerPage = 10
SET #StartIdx = (#PageNo -1) * #ItemsPerPage + 1
SET #EndIdx = (#StartIdx + #ItemsPerPage) - 1
SET #f_name = (#f_name)
SET #SQL = 'SELECT FilePath
FROM (
SELECT ROW_NUMBER() OVER(ORDER BY ID) AS Row, *
FROM tblFiles ) AS tbl WHERE Row >= '
+ CONVERT(varchar(9), #StartIdx) + ' AND
Row <= ' + CONVERT(varchar(9), #EndIdx) + ' AND
FileName = #file_name'
EXEC sp_executesql #SQL
SET #SQL = 'SELECT #TotalRows=COUNT(*) FROM tblFiles'
EXEC sp_executesql
#query = #SQL,
#params = N'#TotalRows INT OUTPUT',
#TotalRows = #TotalRows OUTPUT,
#file_name = #f_name
END

How to display no Data message in Stored procedre

If #MeasureRuleTrendId value has no data i need to display either empty table or No Data message.. Can you please help what we need to add in the below code... Thanks in Advance
ALTER PROCEDURE [dbo].[uspRptDQMeasureDetail] (#MeasureRuleTrendId INT)
AS
BEGIN
SET NOCOUNT ON
truncate table dq.tt
IF OBJECT_ID('tempdb..#columns') IS NOT NULL
DROP TABLE #columns
IF OBJECT_ID('tempdb..##Tmp') IS NOT NULL
DROP TABLE ##Tmp
CREATE TABLE #Columns (
Id INT IDENTITY
,Col VARCHAR(500)
)
DECLARE #RowsToProcess AS INT
DECLARE #CurrentRow AS INT
DECLARE #SQL AS VARCHAR(MAX)
DECLARE #xml AS XML
DECLARE #Col AS VARCHAR(100)
DECLARE #SQLUnpivot AS VARCHAR(MAX)
DECLARE #SQLTempTable AS VARCHAR(MAX)
SELECT #xml = DetailCSV
FROM DQ.MeasureRuleDtl
WHERE [MeasureRuleTrendId] = #MeasureRuleTrendId
SET #SQL = 'DECLARE #xml AS XML; SELECT #xml = DetailCSV
FROM DQ.MeasureRuleDtl where[MeasureRuleTrendId] = ' + Convert(VARCHAR(100), #MeasureRuleTrendId) + '; INSERT INTO ##Tmp Select '
SET #SQLUnpivot = 'SELECT ID, ColName, VAL FROM (SELECT * from ##Tmp ) p UNPIVOT (VAL FOR ColName IN ('
SET #SQLTempTable = ''
SET #SQLTempTable = 'CREATE Table ##Tmp ( ID INT Identity ,'
INSERT INTO #Columns (col)
SELECT DISTINCT C.value('local-name(.)', 'varchar(50)') AS NodeName
FROM #xml.nodes('/row/*') AS T(C)
SET #RowsToProcess = ##ROWCOUNT
SET #CurrentRow = 0
WHILE #CurrentRow < #RowsToProcess
BEGIN
SET #CurrentRow = #CurrentRow + 1
SELECT #Col = Col
FROM #Columns
WHERE ID = #CurrentRow
SET #sql = #SQL + #col + ' = Events.value(' + '''' + '(' + #col + ')[1]' + '''' + ',' + '''' + 'varchar(max)' + '''' + ')'
SET #SQLTempTable = #SQLTempTable + #Col + ' VARCHAR(max)'
SET #SQLUnpivot = #SQLUnpivot + #Col
IF #CurrentRow = #RowsToProcess
BEGIN
SET #sql = #sql + ' '
SET #SQLTempTable = #SQLTempTable + ' '
SET #SQLUnpivot = #SQLUnpivot + ' '
END
ELSE
BEGIN
SET #sql = #sql + ' , '
SET #SQLTempTable = #SQLTempTable + ' , '
SET #SQLUnpivot = #SQLUnpivot + ' , '
END
END
SET #SQL = #sql + + ' FROM #xml.nodes(''/row'') AS XTbl(Events)'
SET #SQLUnpivot = #SQLUnpivot + '))AS unpvt'
set #SQLUnpivot = 'insert into dq.tt ' + #SQLUnpivot
SET #SQLTempTable = #SQLTempTable + ')'
EXECUTE (#SQLTempTable)
EXECUTE (#SQL)
Print #sqlunpivot
EXECUTE (#SQLUnpivot)
SELECT * from dq.tt
SET NOCOUNT OFF
END
It should be enough to add this in your final WHERE, if this is a question of performance, you could add the WHERE to your dynamic SQL too:
ALTER PROCEDURE [dbo].[uspRptDQMeasureDetail] (#MeasureRuleTrendId INT)
AS
BEGIN
SET NOCOUNT ON
truncate table dq.tt
IF OBJECT_ID('tempdb..#columns') IS NOT NULL
DROP TABLE #columns
IF OBJECT_ID('tempdb..##Tmp') IS NOT NULL
DROP TABLE ##Tmp
CREATE TABLE #Columns (
Id INT IDENTITY
,Col VARCHAR(500)
)
DECLARE #RowsToProcess AS INT
DECLARE #CurrentRow AS INT
DECLARE #SQL AS VARCHAR(MAX)
DECLARE #xml AS XML
DECLARE #Col AS VARCHAR(100)
DECLARE #SQLUnpivot AS VARCHAR(MAX)
DECLARE #SQLTempTable AS VARCHAR(MAX)
SELECT #xml = DetailCSV
FROM DQ.MeasureRuleDtl
WHERE [MeasureRuleTrendId] = #MeasureRuleTrendId
SET #SQL = 'DECLARE #xml AS XML; SELECT #xml = DetailCSV
FROM DQ.MeasureRuleDtl where[MeasureRuleTrendId] = ' + Convert(VARCHAR(100), #MeasureRuleTrendId) + '; INSERT INTO ##Tmp Select '
SET #SQLUnpivot = 'SELECT ID, ColName, VAL FROM (SELECT * from ##Tmp ) p UNPIVOT (VAL FOR ColName IN ('
SET #SQLTempTable = ''
SET #SQLTempTable = 'CREATE Table ##Tmp ( ID INT Identity ,'
INSERT INTO #Columns (col)
SELECT DISTINCT C.value('local-name(.)', 'varchar(50)') AS NodeName
FROM #xml.nodes('/row/*') AS T(C)
SET #RowsToProcess = ##ROWCOUNT
SET #CurrentRow = 0
WHILE #CurrentRow < #RowsToProcess
BEGIN
SET #CurrentRow = #CurrentRow + 1
SELECT #Col = Col
FROM #Columns
WHERE ID = #CurrentRow
SET #sql = #SQL + #col + ' = Events.value(' + '''' + '(' + #col + ')[1]' + '''' + ',' + '''' + 'varchar(max)' + '''' + ')'
SET #SQLTempTable = #SQLTempTable + #Col + ' VARCHAR(max)'
SET #SQLUnpivot = #SQLUnpivot + #Col
IF #CurrentRow = #RowsToProcess
BEGIN
SET #sql = #sql + ' '
SET #SQLTempTable = #SQLTempTable + ' '
SET #SQLUnpivot = #SQLUnpivot + ' '
END
ELSE
BEGIN
SET #sql = #sql + ' , '
SET #SQLTempTable = #SQLTempTable + ' , '
SET #SQLUnpivot = #SQLUnpivot + ' , '
END
END
SET #SQL = #sql + + ' FROM #xml.nodes(''/row'') AS XTbl(Events)'
SET #SQLUnpivot = #SQLUnpivot + '))AS unpvt'
set #SQLUnpivot = 'insert into dq.tt ' + #SQLUnpivot
SET #SQLTempTable = #SQLTempTable + ')'
EXECUTE (#SQLTempTable)
EXECUTE (#SQL)
Print #sqlunpivot
EXECUTE (#SQLUnpivot)
--Added your parameter with WHERE...
SELECT * from dq.tt WHERE #MeasureRuleTrendId IS NOT NULL
SET NOCOUNT OFF
END

SQL Server 2012 Dynamic Query calling from Functions return

I have a scalar-valued [return type nvarchar] function that returns a dynamic Query String.
Let my Function is like following …
CREATE FUNCTION ABC
(
)
RETURNS nvarchar(MAX)
AS
BEGIN
return 'Select * from Table1'
END
I want to Execute it like following …
Select * from dbo.ABC()
Or
Select * from EXEC(dbo.ABC())
Is That possible in SQL Server 2012?
I have to do it without using openquery.
-- My Actual Function --
ALTER FUNCTION [dbo].[RowToColumn]
(
-- Add the parameters for the function here
)
RETURNS nvarchar(MAX)
AS
BEGIN
DECLARE #PunchList nvarchar(MAX)
DECLARE #PunchListTOP nvarchar(MAX)
DECLARE #SQL nvarchar(MAX)
DECLARE #Flag INT
SET #PunchList = ''
SET #PunchListTOP = ''
DECLARE #I INT
SET #Flag = (select MAX(X) as MMAX from (select Employee_ID,Date_Of_Working, count(Date_Of_Working) as X from DataInOneRowStep3 group by Date_Of_Working ,Employee_ID ) A)
Set #I =1
WHILE (#I<= #Flag)
BEGIN
if (#PunchList = '' )
BEGIN
Set #PunchList = 'Punch_' + CONVERT(varchar, #I)
Set #PunchListTOP = ' MAX(Punch_' + CONVERT(varchar, #I) +') Punch_' + CONVERT(varchar, #I)
END
else
BEGIN
Set #PunchList = #PunchList + ',' + 'Punch_' + CONVERT(varchar, #I)
Set #PunchListTOP =#PunchListTOP +','+ ' MAX(Punch_' + CONVERT(varchar, #I) +') Punch_' + CONVERT(varchar, #I)
END
SET #I = #I + 1
END
SET #SQL ='SELECT Employee_Id,Date_OF_Working,Shift_Id,'+#PunchListTOP+' FROM (
SELECT * from DataInOneRowStep4
) as s
PIVOT
(
MAX(EntryTime)
FOR Punch IN ('+#PunchList+')
)AS piv group by Employee_Id,Date_OF_Working,Shift_Id'
RETURN #SQL
END

Resources