Get row count of all output of proc in sql server - sql

How can I get rowcount of all outputs in stored procedure?
e.g.
Create Proc Test
AS Begin
select top 10 * from sysobjects
select top 20* from sysobjects
End
##rowcount will return the outputs row count. But in my case there are 2 outputs. ##rowcount will return only last output only.
exec Test
select ##rowcount
This will return only 20. But I need 10, 20
Any way to achieve?

CREATE PROCEDURE TestRowCount
#rowcount1 INT OUTPUT,
#rowcount2 INT OUTPUT
AS
BEGIN
select top 10 * from sysobjects
SET #rowcount1 = ##ROWCOUNT
select top 20* from sysobjects
SET #rowcount2 = ##ROWCOUNT
END
Calling Procedure as follows :
DECLARE #rowcount1 INT,
#rowcount2 INT;
EXEC dbo.TestRowCount #rowcount1 = #rowcount1 OUTPUT, -- int
#rowcount2 = #rowcount2 OUTPUT -- int

Try this way:
Create Proc Test
AS Begin
select top 10 * from sysobjects
select ##rowcount
select top 20* from sysobjects
select ##rowcount
End
Then execute the query:
exec Test

Function ##ROWCOUNT returns the number of rows affected by the last statement, so one possible approach (to get the total row count from all SELECT statements) is to define an output parameter in your stored procedure:
Procedure:
CREATE PROCEDURE TestRowCount
#RowCount int OUTPUT
AS
BEGIN
SET #RowCount = 0
select top 10 * from sysobjects
SET #RowCount = #RowCount + ##ROWCOUNT
select top 20 * from sysobjects
SET #RowCount = #RowCount + ##ROWCOUNT
END
Result:
DECLARE #RC int
DECLARE #RowCount int
EXECUTE #RC = TestRowCount #RowCount OUTPUT
SELECT #RowCount
If you want to get the count of rows from each SELECT statement, use something like this:
CREATE PROCEDURE TestRowCount
AS
BEGIN
CREATE TABLE #Tmp (RC int)
select top 10 * from sysobjects
INSERT INTO #Tmp (RC) VALUES (##ROWCOUNT)
select top 20 * from sysobjects
INSERT INTO #Tmp (RC) VALUES (##ROWCOUNT)
SELECT * FROM #Tmp
DROP TABLE #Tmp
END

Related

Execute Stored Procedure having a query as a parameter

How can I execute the sp_1 for every ProductId and get a result set?
EXEC sp_1 (SELECT ID FROM Products)
Try this way. No direct query it seems.
execute sp for each row
or try this , make small changes if needed.Use temp table to get values out of sp. Use the below inside a sp if needed.
begin
declare #ID int
declare #temp table (col1 int)
declare cur cursor for select distinct ID from products
open cur
fetch next from cur into #ID
truncate table #temp
while(##FETCH_STATUS=0)
begin
insert into #temp (<'cols/output from procedure'>) exec (#ID)
end
select * from #temp
end
I would store the id's in a temp table and use a WHILE loop (AVOID CURSORS!)
DECLARE #prodid INT
SELECT prodid, 0 as Processed INTO #prod_ids FROM Products
WHILE EXISTS (SELECT prodid FROM #prod_ids WHERE Processed = 0)
BEGIN
SELECT TOP 1 #prodid = prodid FROM #prod_ids WHERE Processed = 0
EXEC sp_1(#prodid)
UPDATE #prod_ids SET Processed = 1 WHERE prodid = #prodid
END
With dynamic query in SQL Server:
declare #cadena varchar(max) = ''
select #cadena = #cadena + 'exec sp_1 ' + ltrim(ID) + ';'
from Products;
exec(#cadena);

How do I loop through a set of records in SQL Server?

How do I loop through a set of records from a select statement?
Say I have a few records that I wish to loop through and do something with each record. Here's a primitive version of my select statement:
select top 1000 * from dbo.table
where StatusID = 7
By using T-SQL and cursors like this :
DECLARE #MyCursor CURSOR;
DECLARE #MyField YourFieldDataType;
BEGIN
SET #MyCursor = CURSOR FOR
select top 1000 YourField from dbo.table
where StatusID = 7
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #MyField
WHILE ##FETCH_STATUS = 0
BEGIN
/*
YOUR ALGORITHM GOES HERE
*/
FETCH NEXT FROM #MyCursor
INTO #MyField
END;
CLOSE #MyCursor ;
DEALLOCATE #MyCursor;
END;
This is what I've been doing if you need to do something iterative... but it would be wise to look for set operations first. Also, do not do this because you don't want to learn cursors.
select top 1000 TableID
into #ControlTable
from dbo.table
where StatusID = 7
declare #TableID int
while exists (select * from #ControlTable)
begin
select top 1 #TableID = TableID
from #ControlTable
order by TableID asc
-- Do something with your TableID
delete #ControlTable
where TableID = #TableID
end
drop table #ControlTable
Small change to sam yi's answer (for better readability):
select top 1000 TableID
into #ControlTable
from dbo.table
where StatusID = 7
declare #TableID int
while exists (select * from #ControlTable)
begin
select #TableID = (select top 1 TableID
from #ControlTable
order by TableID asc)
-- Do something with your TableID
delete #ControlTable
where TableID = #TableID
end
drop table #ControlTable
By using cursor you can easily iterate through records individually and print records separately or as a single message including all the records.
DECLARE #CustomerID as INT;
declare #msg varchar(max)
DECLARE #BusinessCursor as CURSOR;
SET #BusinessCursor = CURSOR FOR
SELECT CustomerID FROM Customer WHERE CustomerID IN ('3908745','3911122','3911128','3911421')
OPEN #BusinessCursor;
FETCH NEXT FROM #BusinessCursor INTO #CustomerID;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #msg = '{
"CustomerID": "'+CONVERT(varchar(10), #CustomerID)+'",
"Customer": {
"LastName": "LastName-'+CONVERT(varchar(10), #CustomerID) +'",
"FirstName": "FirstName-'+CONVERT(varchar(10), #CustomerID)+'",
}
}|'
print #msg
FETCH NEXT FROM #BusinessCursor INTO #CustomerID;
END
Just another approach if you are fine using temp tables.I have personally tested this and it will not cause any exception (even if temp table does not have any data.)
CREATE TABLE #TempTable
(
ROWID int identity(1,1) primary key,
HIERARCHY_ID_TO_UPDATE int,
)
--create some testing data
--INSERT INTO #TempTable VALUES(1)
--INSERT INTO #TempTable VALUES(2)
--INSERT INTO #TempTable VALUES(4)
--INSERT INTO #TempTable VALUES(6)
--INSERT INTO #TempTable VALUES(8)
DECLARE #MAXID INT, #Counter INT
SET #COUNTER = 1
SELECT #MAXID = COUNT(*) FROM #TempTable
WHILE (#COUNTER <= #MAXID)
BEGIN
--DO THE PROCESSING HERE
SELECT #HIERARCHY_ID_TO_UPDATE = PT.HIERARCHY_ID_TO_UPDATE
FROM #TempTable AS PT
WHERE ROWID = #COUNTER
SET #COUNTER = #COUNTER + 1
END
IF (OBJECT_ID('tempdb..#TempTable') IS NOT NULL)
BEGIN
DROP TABLE #TempTable
END
You could choose to rank your data and add a ROW_NUMBER and count down to zero while iterate your dataset.
-- Get your dataset and rank your dataset by adding a new row_number
SELECT TOP 1000 A.*, ROW_NUMBER() OVER(ORDER BY A.ID DESC) AS ROW
INTO #TEMPTABLE
FROM DBO.TABLE AS A
WHERE STATUSID = 7;
--Find the highest number to start with
DECLARE #COUNTER INT = (SELECT MAX(ROW) FROM #TEMPTABLE);
DECLARE #ROW INT;
-- Loop true your data until you hit 0
WHILE (#COUNTER != 0)
BEGIN
SELECT #ROW = ROW
FROM #TEMPTABLE
WHERE ROW = #COUNTER
ORDER BY ROW DESC
--DO SOMTHING COOL
-- SET your counter to -1
SET #COUNTER = #ROW -1
END
DROP TABLE #TEMPTABLE
this way we can iterate into table data.
DECLARE #_MinJobID INT
DECLARE #_MaxJobID INT
CREATE TABLE #Temp (JobID INT)
INSERT INTO #Temp SELECT * FROM DBO.STRINGTOTABLE(#JobID,',')
SELECT #_MinJID = MIN(JobID),#_MaxJID = MAX(JobID) FROM #Temp
WHILE #_MinJID <= #_MaxJID
BEGIN
INSERT INTO Mytable
(
JobID,
)
VALUES
(
#_MinJobID,
)
SET #_MinJID = #_MinJID + 1;
END
DROP TABLE #Temp
STRINGTOTABLE is user define function which will parse comma separated data and return table. thanks
I think this is the easy way example to iterate item.
declare #cateid int
select CateID into [#TempTable] from Category where GroupID = 'STOCKLIST'
while (select count(*) from #TempTable) > 0
begin
select top 1 #cateid = CateID from #TempTable
print(#cateid)
--DO SOMETHING HERE
delete #TempTable where CateID = #cateid
end
drop table #TempTable

Unable to do the union in stored procedure for selected queries

ALTER PROC [dbo].[Usp_SelectQuestion]
#NoOfQuestion int
AS
BEGIN
Declare #CNT int
Declare #test int
Declare #x int
Declare #y int
set #x = 1;
set #y = 1;
set #CNT=(Select Count(*) from (select Distinct(setno)from onlin) AS A)
set #test=#NoOfQuestion/#CNT
while (#x <= #CNT)
begin
select top (#test) * from onlin where setno = #x order by NEWID()
set #x = #x + 1
end
END
In this stored procedure I am getting output as single table for every loop so I am getting multiple tables as output but I want all rows in a single table I think through union we can achieve but I do not know how to use.
Use this:
CREATE TEMPORARY TABLE tmp SELECT * FROM tableName;
then insert to table
INSERT INTO tableName SELECT * FROM tmp;
declare #temptable as table(col1 int, col2 varchar(50),... etc)
while (#x <= #CNT)
begin
insert into #temptable 'temptable columns need to match columns in the SELECT statement
select top (#test) * from onlin where setno = #x order by NEWID()
set #x = #x + 1
end
select * from #temptable
Create a temp table and insert into that in the loop and then the result will be the:
SELECT * FROM tempTable

How to control returning value / table of a stored procedure

ALTER PROC SP_SampleInner
AS
SELECT COUNT(*) FROM TB_Whatever
Other procedure
ALTER RPROC SP_SampleOuter
AS
DECLARE #count int
EXEC #count = SP_SampleInner
IF #count > 0
BEGIN
SELECT 1
END
ELSE
BEGIN
SELECT 0
END
What I want is SP_SampleOuter returns more than one table because of EXEC SP_SampleInner (I think). How could I control returning tables/values?
Try this approach:
ALTER PROC SP_SampleOuter
AS
DECLARE #count int
EXEC #count = SP_SampleInner
IF #count > 0
BEGIN
SELECT #count as Ctr,1
END
ELSE
BEGIN
SELECT #count as Ctr,0
END
Simply add the count variable as the first field you return
Use an output variable to send the count back.

Return value from exec(#sql)

I want get the value from Exec(#sql) and assign to #Rowcount(int)
Here is my query:
'SET #RowCount = (select count(*)
FROM dbo.Comm_Services
WHERE CompanyId = '+cast(#CompanyId as char)+' and '+#condition+')'
On the one hand you could use sp_executesql:
exec sp_executesql N'select #rowcount=count(*) from anytable',
N'#rowcount int output', #rowcount output;
On the other hand you could use a temporary table:
declare #result table ([rowcount] int);
insert into #result ([rowcount])
exec (N'select count(*) from anytable');
declare #rowcount int = (select top (1) [rowcount] from #result);
DECLARE #nReturn int = 0
EXEC #nReturn = Stored Procedure
Was playing with this today... I believe you can also use ##ROWCOUNT, like this:
DECLARE #SQL VARCHAR(50)
DECLARE #Rowcount INT
SET #SQL = 'SELECT 1 UNION SELECT 2'
EXEC(#SQL)
SET #Rowcount = ##ROWCOUNT
SELECT #Rowcount
Then replace the SELECT 1 UNION SELECT 2 with your actual select without the count. I'd suggest just putting 1 in your select, like this:
SELECT 1
FROM dbo.Comm_Services
WHERE....
....
(as opposed to putting SELECT *)
Hope that helps.
that's my procedure
CREATE PROC sp_count
#CompanyId sysname,
#codition sysname
AS
SET NOCOUNT ON
CREATE TABLE #ctr
( NumRows int )
DECLARE #intCount int
, #vcSQL varchar(255)
SELECT #vcSQL = ' INSERT #ctr FROM dbo.Comm_Services
WHERE CompanyId = '+#CompanyId+' and '+#condition+')'
EXEC (#vcSQL)
IF ##ERROR = 0
BEGIN
SELECT #intCount = NumRows
FROM #ctr
DROP TABLE #ctr
RETURN #intCount
END
ELSE
BEGIN
DROP TABLE #ctr
RETURN -1
END
GO
If i understand you correctly, (i probably don't)
'SELECT #RowCount = COUNT(*)
FROM dbo.Comm_Services
WHERE CompanyId = ' + CAST(#CompanyId AS CHAR) + '
AND ' + #condition