How can one iterate over stored procedure results from within another stored procedure....without cursors?
This may not be the most efficient, but I would create a temp table to hold the results of the stored proc and then use that in a join against the target table. For example:
CREATE TABLE #t (uniqueid int)
INSERT INTO #t EXEC p_YourStoredProc
UPDATE TargetTable
SET a.FlagColumn = 1
FROM TargetTable a JOIN #t b
ON a.uniqueid = b.uniqueid
DROP TABLE #t
Stored Procedure - loop through results without cursor
I ended up using a WHILE loop that I can pass each ProductID into a series of checks!!
declare @counter int
declare @productKey varchar(20)
SET @counter = (select COUNT(*) from ##Magento)
while (1=1)
begin
SET @productKey = (select top 1 ProductKey from ##Magento)
print @productKey;
delete from ##Magento Where ProductKey = @productKey
SET @counter-=1;
IF (@counter=0) BREAK;
end
go
Stored Procedure - loop through results without cursor
I ended up using a WHILE loop that I can pass each ProductID into a series of checks!!
declare @counter int
declare @productKey varchar(20)
SET @counter = (select COUNT(*) from ##Magento)
while (1=1)
begin
SET @productKey = (select top 1 ProductKey from ##Magento)
print @productKey;
delete from ##Magento Where ProductKey = @productKey
SET @counter-=1;
IF (@counter=0) BREAK;
end
go
How can I iterate over a recordset within a stored procedure?
You need to create a cursor to loop through the record set.
Example Table:
CREATE TABLE Customers
(
CustomerId INT NOT NULL PRIMARY KEY IDENTITY(1,1)
,FirstName Varchar(50)
,LastName VARCHAR(40)
)
INSERT INTO Customers VALUES('jane', 'doe')
INSERT INTO Customers VALUES('bob', 'smith')
Cursor:
DECLARE @CustomerId INT, @FirstName VARCHAR(30), @LastName VARCHAR(50)
DECLARE @MessageOutput VARCHAR(100)
DECLARE Customer_Cursor CURSOR FOR
SELECT CustomerId, FirstName, LastName FROM Customers
OPEN Customer_Cursor
FETCH NEXT FROM Customer_Cursor INTO
@CustomerId, @FirstName, @LastName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @MessageOutput = @FirstName + ' ' + @LastName
RAISERROR(@MessageOutput,0,1) WITH NOWAIT
FETCH NEXT FROM Customer_Cursor INTO
@CustomerId, @FirstName, @LastName
END
CLOSE Customer_Cursor
DEALLOCATE Customer_Cursor
Here is a link to MSDN on how to create them.
http://msdn.microsoft.com/en-us/library/ms180169.aspx
This is why I used Raise Error instead of PRINT for output.
http://structuredsight.com/2014/11/24/wait-wait-dont-tell-me-on-second-thought/
Call procedure for each row without using cursors and loops?
I am not sure of your exact logic to split the string, but if possible you can make your split function an inline TVF (Heres one I made earlier):
CREATE FUNCTION dbo.Split(@StringToSplit NVARCHAR(MAX), @Delimiter NCHAR(1))
RETURNS TABLE
AS
RETURN
(
SELECT Position = Number,
Value = SUBSTRING(@StringToSplit, Number, CHARINDEX(@Delimiter, @StringToSplit + @Delimiter, Number) - Number)
FROM ( SELECT TOP (LEN(@StringToSplit) + 1) Number = ROW_NUMBER() OVER(ORDER BY a.object_id)
FROM sys.all_objects a
) n
WHERE SUBSTRING(@Delimiter + @StringToSplit + @Delimiter, n.Number, 1) = @Delimiter
);
Then you can simply use this in your insert statement by using cross apply with the TVF:
DECLARE @T1 TABLE (ID INT IDENTITY, TextToSplit NVARCHAR(MAX) NOT NULL);
DECLARE @T2 TABLE (T1ID INT NOT NULL, Position INT NOT NULL, SplitText NVARCHAR(MAX) NOT NULL);
INSERT @T1 (TextToSplit)
VALUES ('This is a test'), ('This is Another Test');
INSERT @T2 (T1ID, Position, SplitText)
SELECT t1.ID, s.Position, s.Value
FROM @T1 t1
CROSS APPLY dbo.Split(t1.TextToSplit, N' ') s;
SELECT *
FROM @T2;
Looping through records to execute a stored procedure and store the result
You have a few misunderstandings here.
First, you will need to understand that when you use the form insert into table (columns...) exec procedure
, the thing that gets inserted is the result set of the stored procedure. In other words, whatever comes out of a select statement inside the procedure. If your stored procedure has no result set, there is nothing to insert. Note that output parameters are not the same as a result set. Observe what happens if you run the following batches:
create table t(result varchar(30))
go
create procedure p (@result varchar(30) = null output) as
begin
set @result = 'this is the output parameter';
select 'this is the result set';
end
go
declare @param varchar(30);
insert t (result) exec p @param output;
select * from t;
select @param;
At the end of the execution of this script, the table t
will have a single row with the value '"this is the result set". The value of the @param
variable will be "this is the output parameter".
OK, now let's look at what's going on in your procedure.
You use the insert ... exec
pattern, so the result set from the stored procedure will be inserted as new rows into your @orderInfo
table.
But from what you have written, it seems like you intend the price to be provided as an output
parameter value to be consumed by your @orderPrice
variable. It won't actually do this, because you haven't used it as an output parameter. You left off the output
keyword.
I expect your stored procedure has no result set at all. Which means nothing gets inserted into the table.
Even if the stored procedure did return a result set, you are doing an insert
. An insert
will create new rows, it won't update the value of the OrderPrice
column for an existing row.
What you probably intend to be doing is this:
While @ID IS NOT NULL
BEGIN
Select @OrderNumber = OrderNumber;
From @orderInfo Where ID = @ID;
Exec sp_OrderPrice_Calc
@Order_Number = @OrderNumber,
@Order_Price = @OrderPrice output; -- output keyword is required both here and in the procedure definition
update @orderInfo set OrderPrice = @orderPrice where ID = @ID; -- update, not insert.
Select @ID = MIN(ID) From @OrderInfo where ID > @ID;
END
There might be an even better solution to use here. If your stored procedure can be rewritten as a user defined function, you wouldn't need a loop at all:
select CompanyName, OrderNumber, DeliveryType, OrderPrice = myOrderPriceFunction(...)
From OrderData;
Iterating without using cursor in MYSQL
Without the use of Cursor, you could iterate using a temporary table and a While..Do statement.
Let's say you have two tables
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
And
CREATE TABLE `tmp_user` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
Create the following routine, and adjust the validation process:
DELIMITER $$
USE `routines_sample`$$
CREATE PROCEDURE `nocursor`()
BEGIN
Declare validId int;
Declare validName varchar(45);
-- drop the temporary table if exists
Drop table if exists `routines_sample`.tmp_validation;
-- create the temporary table, here you could use Engine=Memory
Create table `routines_sample`.tmp_validation (`id` int not null, `name` varchar(45) not null, `valid` bit(1) not null) Engine=MyISAM;
-- insert into the temporary table with a valid flag = 0 (false)
Insert into `routines_sample`.tmp_validation (`id`, `name`, `valid`)
Select tu.id, tu.name, 0
From `routines_sample`.tmp_user tu;
-- while exists data to validate on temporary table do something
While exists(Select `id` From `tmp_validation` Where `valid` = 0) Do
Select `id`, `name` Into @validId, @validName From tmp_validation Where `valid` = 0 Limit 1;
-- do your validation
Select @validId, @validName;
-- don't forget to update your validation table, otherwise you get an endless loop
Update `tmp_validation`
Set `valid` = 1
Where `id` = @validId;
END WHILE;
-- insert only valid rows to your destination table
Insert into `routines_sample`.`user` (`name`)
Select `name` From `tmp_validation`
Where `valid` = 1;
-- drop the temporary table
DROP TABLE tmp_validation;
END$$
DELIMITER ;
Related Topics
Find the Date/Time a Table's Column Was Created
In SQL, What Is the Letter After a Table Name in a Select Statement
If It Is Not Allowed to Rollback a Truncate Statement Then How How to Use It in a Transaction
How to Optimize This SQL Query (Using Indexes)
T-SQL Looping Through Xml Data Column to Derive Unique Set of Paths
How to Escape Double Quotes Inside a SQL Fulltext 'Contains' Function
How to Strip the Date Off of a Datetime String in SQL Ssis
SQL Select Where Column Begins with \
No Value Given for the Required Parameter
How to Select a Column in SQL Server with a Special Character in the Column Name
Inserting Default Value as Current Date + 30 Days in MySQL
Derby's Handling of Null Values
Varchar Requires a Length When Rendered on MySQL
Split String Oracle into a Single Column and Insert into a Table
Ms Access Query with Case Statement