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
Related
Below code works fine and convert table to HTML. It gives the results as HTML tables but I want to assign this to a variable
How can we assign the output to a variable in below code.
CREATE PROC dbo.usp_ConvertQuery2HTMLTable (
#SQLQuery NVARCHAR(3000))
AS
BEGIN
DECLARE #columnslist NVARCHAR (1000) = ''
DECLARE #restOfQuery NVARCHAR (2000) = ''
DECLARE #DynTSQL NVARCHAR (3000)
DECLARE #FROMPOS INT
DECLARE #out table
(
out nvarchar(max)
)
SET NOCOUNT ON
SELECT #columnslist += 'ISNULL (' + NAME + ',' + '''' + ' ' + '''' + ')' + ','
FROM sys.dm_exec_describe_first_result_set(#SQLQuery, NULL, 0)
SET #columnslist = left (#columnslist, Len (#columnslist) - 1)
SET #FROMPOS = CHARINDEX ('FROM', #SQLQuery, 1)
SET #restOfQuery = SUBSTRING(#SQLQuery, #FROMPOS, LEN(#SQLQuery) - #FROMPOS + 1)
SET #columnslist = Replace (#columnslist, '),', ') as TD,')
SET #columnslist += ' as TD'
SET #DynTSQL = CONCAT (
'SELECT (SELECT '
, #columnslist
,' '
, #restOfQuery
,' FOR XML RAW (''TR''), ELEMENTS, TYPE) AS ''TBODY'''
,' FOR XML PATH (''''), ROOT (''TABLE'')'
)
PRINT #DynTSQL
EXEC (#DynTSQL)
SET NOCOUNT OFF
END
Generally, you have 2 options.
Via an intermediate temporary table (table variable).
By itself, exec() returns nothing when a literal or variable is executed, but you can use the rowset produced by it as a source for an insert statement:
-- Option 1
declare #t table (X xml);
declare #Ret xml;
insert into #t (X)
exec('select top 1 * from sys.objects o for xml raw(''TR''), elements, type;');
select top (1) #Ret = t.X from #t t;
select #Ret as [Option1];
go
Switching to the sys.sp_executesql
As Peter has suggested in the comments, you can switch from exec to the sp_executesql system stored procedure, which provides an additional functionality of output parameters:
-- Option 2
declare #s nvarchar(max) = N'set #A = (select top 1 * from sys.objects o for xml raw(''TR''), elements, type);';
declare #Ret xml;
exec sys.sp_executesql #s, N'#A xml = null output', #A = #Ret output;
select #Ret as [Option2];
go
I use table type param (#listdraftIds) and split data in table to compare with data in DB but the error is as below. Help me, thank you.
CREATE OR ALTER PROCEDURE [dbo].[sp_sel_contract]
(
#listDraftId nvarchar(max),
#Page int,
#PageNumber int,
#TotalRecord int OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
BEGIN
DECLARE #listdraftIds TABLE (draftIds nvarchar(max))
INSERT INTO #listdraftIds VALUES(#listDraftId)
DECLARE #sql varchar(MAX)
SET #sql= ' ALTER DATABASE '+ quotename(db_name()) + ' SET COMPATIBILITY_LEVEL = 130 ';
EXEC(#sql)
END
DECLARE #query NVARCHAR(MAX)
DECLARE #newquery NVARCHAR(MAX)
DECLARE #RowIndex int
SET #RowIndex = (#Page-1) * #PageNumber
SET #query = ''
SET #query = #query + ' SELECT DISTINCT'
SET #query = #query + ' [d].[draft_id], '
...
SET #query = #query + 'WHERE '
SET #query = #query + ' [d].[del_flg] = ''FALSE'''
SET #query = #query + 'AND '
SET #query = #query + ' [d].[draft_id] '
SET #query = #query + 'IN ('
SET #query = #query + ' SELECT DISTINCT '
SET #query = #query + ' value AS draft_id '
SET #query = #query + 'FROM '
SET #query = #query + ' #listdraftIds '
SET #query = #query + 'CROSS APPLY STRING_SPLIT(draftIds, '','') '
SET #query = #query + 'WHERE '
SET #query = #query + ' RTRIM(value) <> '''' )'
PRINT #query
SET #newquery = ' SET #TotalRecord = (SELECT COUNT(*) FROM (' + #query +') AS t) '
SET #newquery = #newquery + ' ORDER BY '
SET #newquery = #newquery + ' [draft_date] DESC, [d].[draft_id] DESC, [g].[detail_no] ASC'
SET #newquery = #newquery + ' OFFSET #RowIndex ROWS FETCH NEXT #PageNumber ROWS ONLY'
EXECUTE sp_executesql #newquery,
#listDraftId = #listDraftId,
#RowIndex = #RowIndex,
#PageNumber = #PageNumber,
#TotalRecord = #TotalRecord OUTPUT
END
Then Exec proc:
DECLARE #return_value int,
#TotalRecord int
EXEC #return_value = [dbo].[sp_sel_draft_condition_api1]
#listDraftId = N'123,345',
#Page = 1,
#PageNumber = 20,
#TotalRecord = #TotalRecord OUTPUT
SELECT #TotalRecord as N'#TotalRecord'
SELECT 'Return Value' = #return_value
GO
Error:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '30302'.
Msg 1087, Level 15, State 2, Line 3
Must declare the table variable "#listdraftIds".
Msg 137, Level 15, State 2, Line 3
Must declare the scalar variable "#PageNumber".
few issue here with the stored procedure
First, sp_executesql execute in its own context. So variable declared outside of it is not recognized. Which means, if you need to use a variable, you need to pass it into sp_executesql.
Your sp_executesql statement does not defined any variable
it should be
EXECUTE sp_executesql #newquery,
N'#RowIndex int, #PageNumber int, #TotalRecord int OUTPUT',
#RowIndex = #RowIndex,
#PageNumber = #PageNumber,
#TotalRecord = #TotalRecord OUTPUT
Note that I didn't include the #listDraftId. That is because you can't pass a table variable into sp_executesql. One alternative is to use a temp table
So in your sp_sel_contract
create table #listdraftId ( draftIds nvarchar(max) )
And then you can reference the temp table #listdraftId in you dynamic query
Actually looking at your dynamic query, you don't required a table variable or temp table. You only have one value of #listDraftId that is pass into sp_sel_contract and then it is pass into the dynamic query. So you can pass that variable directly into the dynamic query. Example :
EXECUTE sp_executesql #newquery,
N'#listDraftId nvarchar(max), #RowIndex int, #PageNumber int, #TotalRecord int OUTPUT',
#listDraftId = #listDraftId,
#RowIndex = #RowIndex,
#PageNumber = #PageNumber,
#TotalRecord = #TotalRecord OUTPUT
EDIT :
Now i have a closer look at your dynamic query ? I don't see a need to use dynamic query at all. You can achieve what you want with normal query
This is the table creation and insertion query
If not exists(select * from sysobjects where name='hrs')
Create table hrs(hr int)
declare #cnt int =1
while #cnt <= 12
begin
insert into hrs values(#cnt)
set #cnt=#cnt+1
end
The above code gives the output like
but I just want that
declare #cnt1 int = 1
while #cnt1<=12
begin
EXEC('select he'+#cnt1+' = case when hr = 1 then '+#cnt1+' end from hrs')
set #cnt1=#cnt1+1
end
The above code returns the 12 different table but i just want the all records in one table (without creating any new table).
So, how can i do this?
Please help me.
Thanks.
Here the all column are created dynamically through loop
Here are the full query
declare #s varchar(MAX)=''
declare #j int = 1
while #j<=12
begin
if #j = 12
Set #s = #s+'he'+convert(varchar,#j)+'=MAX(case when hr='+convert(varchar,#j)+' then '+convert(varchar,#j)+' end)'
else
set #s = #s+'he'+convert(varchar,#j)+'=MAX(case when hr='+convert(varchar,#j)+' then '+convert(varchar,#j)+' end),'
set #j=#j+1
end
set #s = 'select '+#s+' from hrs'
exec(#s)
Your query doesn't make a lot of sense, but you can build a list of columns and then exec that:
declare #columns nvarchar(max)
declare #cnt int = 1
while #cnt <= 12
begin
set #columns = isnull(#columns + ', ', '') + 'He' + cast(#cnt as nvarchar) +
' = sum(case when hr = ' + cast(#cnt as nvarchar) + ' then hr end)'
end
declare #sql nvarchar(max) = 'select ' + #columns ' + from hr'
exec (#sql)
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
I am trying to print a selected value, is this possible?
Example:
PRINT
SELECT SUM(Amount) FROM Expense
You know, there might be an easier way but the first thing that pops to mind is:
Declare #SumVal int;
Select #SumVal=Sum(Amount) From Expense;
Print #SumVal;
You can, of course, print any number of fields from the table in this way. Of course, if you want to print all of the results from a query that returns multiple rows, you'd just direct your output appropriately (e.g. to Text).
If you're OK with viewing it as XML:
DECLARE #xmltmp xml = (SELECT * FROM table FOR XML AUTO)
PRINT CONVERT(NVARCHAR(MAX), #xmltmp)
While the OP's question as asked doesn't necessarily require this, it's useful if you got here looking to print multiple rows/columns (within reason).
If you want to print multiple rows, you can iterate through the result by using a cursor.
e.g. print all names from sys.database_principals
DECLARE #name nvarchar(128)
DECLARE cur CURSOR FOR
SELECT name FROM sys.database_principals
OPEN cur
FETCH NEXT FROM cur INTO #name;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #name
FETCH NEXT FROM cur INTO #name;
END
CLOSE cur;
DEALLOCATE cur;
set #n = (select sum(Amount) from Expense)
print 'n=' + #n
I wrote this SP to do just what you want, however, you need to use dynamic sql.
This worked for me on SQL Server 2008 R2
ALTER procedure [dbo].[PrintSQLResults]
#query nvarchar(MAX),
#numberToDisplay int = 10,
#padding int = 20
as
SET NOCOUNT ON;
SET ANSI_WARNINGS ON;
declare #cols nvarchar(MAX),
#displayCols nvarchar(MAX),
#sql nvarchar(MAX),
#printableResults nvarchar(MAX),
#NewLineChar AS char(2) = char(13) + char(10),
#Tab AS char(9) = char(9);
if exists (select * from tempdb.sys.tables where name = '##PrintSQLResultsTempTable') drop table ##PrintSQLResultsTempTable
set #query = REPLACE(#query, 'from', ' into ##PrintSQLResultsTempTable from');
--print #query
exec(#query);
select ROW_NUMBER() OVER (ORDER BY (select Null)) AS ID12345XYZ, * into #PrintSQLResultsTempTable
from ##PrintSQLResultsTempTable
drop table ##PrintSQLResultsTempTable
select name
into #PrintSQLResultsTempTableColumns
from tempdb.sys.columns where object_id =
object_id('tempdb..#PrintSQLResultsTempTable');
select #cols =
stuff((
(select ' + space(1) + (LEFT( (CAST([' + name + '] as nvarchar(max)) + space('+ CAST(#padding as nvarchar(4)) +')), '+CAST(#padding as nvarchar(4))+')) ' as [text()]
FROM #PrintSQLResultsTempTableColumns
where name != 'ID12345XYZ'
FOR XML PATH(''), root('str'), type ).value('/str[1]','nvarchar(max)'))
,1,0,'''''');
select #displayCols =
stuff((
(select space(1) + LEFT(name + space(#padding), #padding) as [text()]
FROM #PrintSQLResultsTempTableColumns
where name != 'ID12345XYZ'
FOR XML PATH(''), root('str'), type ).value('/str[1]','nvarchar(max)'))
,1,0,'');
DECLARE
#tableCount int = (select count(*) from #PrintSQLResultsTempTable);
DECLARE
#i int = 1,
#ii int = case when #tableCount < #numberToDisplay then #tableCount else #numberToDisplay end;
print #displayCols -- header
While #i <= #ii
BEGIN
set #sql = N'select #printableResults = ' + #cols + ' + #NewLineChar from #PrintSQLResultsTempTable where ID12345XYZ = ' + CAST(#i as varchar(3)) + '; print #printableResults;'
--print #sql
execute sp_executesql #sql, N'#NewLineChar char(2), #printableResults nvarchar(max) output', #NewLineChar = #NewLineChar, #printableResults = #printableResults output
print #printableResults
SET #i += 1;
END
This worked for me on SQL Server 2012
ALTER procedure [dbo].[PrintSQLResults]
#query nvarchar(MAX),
#numberToDisplay int = 10,
#padding int = 20
as
SET NOCOUNT ON;
SET ANSI_WARNINGS ON;
declare #cols nvarchar(MAX),
#displayCols nvarchar(MAX),
#sql nvarchar(MAX),
#printableResults nvarchar(MAX),
#NewLineChar AS char(2) = char(13) + char(10),
#Tab AS char(9) = char(9);
if exists (select * from tempdb.sys.tables where name = '##PrintSQLResultsTempTable') drop table ##PrintSQLResultsTempTable
set #query = REPLACE(#query, 'from', ' into ##PrintSQLResultsTempTable from');
--print #query
exec(#query);
select ROW_NUMBER() OVER (ORDER BY (select Null)) AS ID12345XYZ, * into #PrintSQLResultsTempTable
from ##PrintSQLResultsTempTable
drop table ##PrintSQLResultsTempTable
select name
into #PrintSQLResultsTempTableColumns
from tempdb.sys.columns where object_id =
object_id('tempdb..#PrintSQLResultsTempTable');
select #cols =
stuff((
(select ' + space(1) + LEFT(CAST([' + name + '] as nvarchar('+CAST(#padding as nvarchar(4))+')) + space('+ CAST(#padding as nvarchar(4)) +'), '+CAST(#padding as nvarchar(4))+') ' as [text()]
FROM #PrintSQLResultsTempTableColumns
where name != 'ID12345XYZ'
FOR XML PATH(''), root('str'), type ).value('/str[1]','nvarchar(max)'))
,1,0,'''''');
select #displayCols =
stuff((
(select space(1) + LEFT(name + space(#padding), #padding) as [text()]
FROM #PrintSQLResultsTempTableColumns
where name != 'ID12345XYZ'
FOR XML PATH(''), root('str'), type ).value('/str[1]','nvarchar(max)'))
,1,0,'');
DECLARE
#tableCount int = (select count(*) from #PrintSQLResultsTempTable);
DECLARE
#i int = 1,
#ii int = case when #tableCount < #numberToDisplay then #tableCount else #numberToDisplay end;
print #displayCols -- header
While #i <= #ii
BEGIN
set #sql = N'select #printableResults = ' + #cols + ' + #NewLineChar from #PrintSQLResultsTempTable where ID12345XYZ = ' + CAST(#i as varchar(3)) + ' '
--print #sql
execute sp_executesql #sql, N'#NewLineChar char(2), #printableResults nvarchar(max) output', #NewLineChar = #NewLineChar, #printableResults = #printableResults output
print #printableResults
SET #i += 1;
END
This worked for me on SQL Server 2014
ALTER procedure [dbo].[PrintSQLResults]
#query nvarchar(MAX),
#numberToDisplay int = 10,
#padding int = 20
as
SET NOCOUNT ON;
SET ANSI_WARNINGS ON;
declare #cols nvarchar(MAX),
#displayCols nvarchar(MAX),
#sql nvarchar(MAX),
#printableResults nvarchar(MAX),
#NewLineChar AS char(2) = char(13) + char(10),
#Tab AS char(9) = char(9);
if exists (select * from tempdb.sys.tables where name = '##PrintSQLResultsTempTable') drop table ##PrintSQLResultsTempTable
set #query = REPLACE(#query, 'from', ' into ##PrintSQLResultsTempTable from');
--print #query
exec(#query);
select ROW_NUMBER() OVER (ORDER BY (select Null)) AS ID12345XYZ, * into #PrintSQLResultsTempTable
from ##PrintSQLResultsTempTable
drop table ##PrintSQLResultsTempTable
select name
into #PrintSQLResultsTempTableColumns
from tempdb.sys.columns where object_id =
object_id('tempdb..#PrintSQLResultsTempTable');
select #cols =
stuff((
(select ' , space(1) + LEFT(CAST([' + name + '] as nvarchar('+CAST(#padding as nvarchar(4))+')) + space('+ CAST(#padding as nvarchar(4)) +'), '+CAST(#padding as nvarchar(4))+') ' as [text()]
FROM #PrintSQLResultsTempTableColumns
where name != 'ID12345XYZ'
FOR XML PATH(''), root('str'), type ).value('/str[1]','nvarchar(max)'))
,1,0,'''''');
select #displayCols =
stuff((
(select space(1) + LEFT(name + space(#padding), #padding) as [text()]
FROM #PrintSQLResultsTempTableColumns
where name != 'ID12345XYZ'
FOR XML PATH(''), root('str'), type ).value('/str[1]','nvarchar(max)'))
,1,0,'');
DECLARE
#tableCount int = (select count(*) from #PrintSQLResultsTempTable);
DECLARE
#i int = 1,
#ii int = case when #tableCount < #numberToDisplay then #tableCount else #numberToDisplay end;
print #displayCols -- header
While #i <= #ii
BEGIN
set #sql = N'select #printableResults = concat(#printableResults, ' + #cols + ', #NewLineChar) from #PrintSQLResultsTempTable where ID12345XYZ = ' + CAST(#i as varchar(3))
--print #sql
execute sp_executesql #sql, N'#NewLineChar char(2), #printableResults nvarchar(max) output', #NewLineChar = #NewLineChar, #printableResults = #printableResults output
print #printableResults
SET #printableResults = null;
SET #i += 1;
END
Example:
exec [dbo].[PrintSQLResults] n'select * from MyTable'
Try this query
DECLARE #PrintVarchar nvarchar(max) = (Select Sum(Amount) From Expense)
PRINT 'Varchar format =' + #PrintVarchar
DECLARE #PrintInt int = (Select Sum(Amount) From Expense)
PRINT #PrintInt
If you want to print more than a single result, just select rows into a temporary table, then select from that temp table into a buffer, then print the buffer:
drop table if exists #temp
-- we just want to see our rows, not how many were inserted
set nocount on
select * into #temp from MyTable
-- note: SSMS will only show 8000 chars
declare #buffer varchar(MAX) = ''
select #buffer = #buffer + Col1 + ' ' + Col2 + CHAR(10) from #temp
print #buffer
Add
PRINT 'Hardcoded table name -' + CAST(##RowCount as varchar(10))
immediately after the query.
You can also use the undocumented sp_MSforeachtable stored procedure as such if you are looking to do this for every table:
sp_MSforeachtable #command1 ="PRINT 'TABLE NAME: ' + '?' DECLARE #RowCount INT SET #RowCount = (SELECT COUNT(*) FROM ?) PRINT #RowCount"
If you wish (like me) to have results containing mulitple rows of various SELECT queries "labelled" and can't manage this within the constraints of the PRINT statement in concert with the Messages tab you could turn it around and simply add messages to the Results tab per the below:
SELECT 'Results from scenario 1'
SELECT
*
FROM tblSample
Try this:
DECLARE #select as nvarchar(max) = ''
SELECT #select = #select + somefield + char(13) FROM sometable
PRINT #select