Which one to chose - cursor vs WHILE loop in SQL Server for better performance? - sql-server-2008

I came across below scenario, pseudo code version is
SELECT ProductID
FROM ABC table
WHERE (Some subquery)
For each record
get value1 from DEF table where(some subquery with ProductID)
Insert (ProductID, Value1) into GHI table
Insert (ProductID, Value1) into JKL table
End loop
I have 3 following approaches
Stored procedure with a cursor
Stored procedure with a While loop
a) Stored procedure to Get Product IDs
b) C# Loop
c) Stored procedure to insert data into tables
Which is the best approach in these or Is there any other best approach?
Note: This block code executed only once per day. There will be around 500 ProductIDs on average per day.

Related

MySQL Stored Procedure - Checking if certain conditions are met one by one; if one is not met, exit procedure and return a specific message

I am trying to make a MySQL stored procedure that processes a book purchase and inserts records into other tables about the purchase. However, these insertions can only happen if three conditions are met: the customer is in the system, the book is in the system, and there is enough quantity.
I want to check for each condition individually, and if it passes the first condition, it moves to the next, but if it doesn't, I want it to end the procedure and return a value, and so on for each condition. If it passes all three conditions, the insertions can happen. Here's how I coded it:
DELIMITER //
CREATE PROCEDURE process_purchase(
IN book_key INT,
IN customer_key INT,
IN quantity INT
)
BEGIN
DECLARE book_inventory_key_var INT;
DECLARE purchase_key_var INT;
SELECT book_inventory_key
INTO book_inventory_key_var
FROM book_inventory
WHERE book_key = book_key.book_inventory_key;
SELECT purchase_key
INTO purchase_key_var
FROM purchases
WHERE customer_key = customer_key.purchases;
IF customer_key != customer_key.customers THEN
SELECT '-1';
ELSEIF book_key != book_key.books THEN
SELECT '-2';
ELSEIF quantity < quantity_on_stock(book_key) THEN
SELECT '-3';
ELSE
INSERT INTO purchases VALUES (customer_key, CURDATE());
INSERT INTO purchase_items (book_inventory_key, purchase_key, quantity) VALUES (book_inventory_key_var, purchase_key_var, quantity);
SELECT '1';
END IF;
END//
DELIMITER ;
I compare the customer and book keys to their values in the other tables, and the quantity to the quantity_on_stock stored function I previously made. I use a chain of IF-ELSEIF to go through each condition one by one, and if all of them are passed, the insertions occur. If not, it won't go to the next condition, and will return the SELECT message, correct? The procedure runs without errors, but I am unsure if this is the correct method, or if there's a better way of going about this.
Checking sequentially is subject to race conditions. Breaking this paradigm is key to moving from a procedural to SQL based method. Use the database features of to obtain consistency rather than procedural code.
purchase_items should have foreign key constraints to book_key and customer_key tables. If an insert generates a FK exception then one of these apply depending on the error. DECLARE HANDLER will help catch these errors.
For the quantity:
INSERT INTO purchase_items (book_inventory_key, purchase_key, quantity)
SELECT book_key, purchase_key, quantity
FROM books WHERE book_key = book.id AND book.available >= quantity
If there are no ROW_COUNT for this, then there wasn't sufficient quantity.
You will also need to reduce the amount of books available in the same SQL transaction.
If you don't have to do this in a STORED PROCEDURE, don't. A lot of the constructs here are easier in application code. If this is an assignment, where store procedures are require to get extra marks, get through it, and never write a stored procedure again.

sql refer row on masive insert using a stored procedures - mysql

I have a table task, this table contains information of recurring tasks, fox example daily tasks, so I repeat each task because I want to know the result of each task over time
1/1/2014 Get Pizza OK
1/2/2014 Get Pizza OK
1/3/2014 Get Pizza Error
1/4/2014 Get Pizza OK
For this I made a stored procedure
DELIMITER $$
CREATE DEFINER=`db`#`%` PROCEDURE `SP_repeat_task`()
BEGIN
INSERT INTO Task
(
date_of_assignment,
Some fields
)
SELECT
DATE_ADD(tas.date_of_assignment, INTERVAL 1 DAY),
another fields
FROM Task tas
WHERE tas.date_of_assignment=CURRENT_DATE and many conditions
)
;
END
This procedure is invoked every day 5 minutes before midnight. And produces something like this
The problem is that I have to insert the id of the records added in another table
For example
When I add 4 tasks in insert-select statement i need add these to another table
In my case, there can be multiple records for each task.
I can easily obtain id_person in my select, but not how to use it in the next insert.
I cant change the structure of the tables, I have only my stored procedure to work
I read about mysqli_insert_id, but not how to use it in my case
EDIT
based in b.b3rn4rd answer
When i add the other field in cursor select
DECLARE records_to_clone_cursor CURSOR FOR
SELECT `field1`, `field2`, `field3` FROM `Task` WHERE ... ;
In FETCH return more rows because as there is a one to many relationship in my tables
so the query returns with old fields
DECLARE records_to_clone_cursor CURSOR FOR
SELECT `field1`, `field2` FROM `Task` WHERE ... ;
And i tried change the prepared statement for a classic Insert-Select
SET #NEW_ID = LAST_INSERT_ID();
INSERT INTO Another_table
(
id_task,
id_person
)
SELECT tas.id_task,
pe.id_person
FROM Task tas
INNER JOIN Person pe
ON pe.id_person = tas.id_assigned
WHERE tas.id_task= #NEW_ID;
-- EXECUTE insert_responables USING #NEW_ID, #Var_3;
But does nothing, first prepared works well, and Select-Inser work in nornal query.
that I can do?
EDIT 2
if I need to insert the values​​, but because they are different cause the cursor query returns more records and these are duplicated by the number of records in the field is_person

Stored procedure used to insert datas in two tables

I am using a stored procedure to insert data into two tables. But when I insert the datas the total number of rows in the first table and the second table is different, so it means that sometimes it only inserted the datas in the first table but failed to insert it in the second table. But this case should not happen in my case as the Id of the two tables is related to each other. How can I solve this problem? So that when it will insert datas in both tables or no table if an error occurs so that the number of datas are the same in both the table. My stored procedure is as follows:
Begin
insert into base_table(imgPath,store,apparelType) values (imgPath,store,apparelType);
insert into data_table(cvID,color) values
(LAST_INSERT_ID(),color);
END
To make sure that the 1st query has been successfully executed, the best way would be to add an Identity column in your base_table, then proceed as follows;
DECLARE #LAST_INSERT_ID INT
DECLARE #EXECUTION_OK char(1)
SET #EXECUTION_OK = 1
insert into base_table(imgPath,store,apparelType) values (imgPath,store,apparelType)
SELECT #LAST_INSERT_ID = SCOPE_IDENTITY()
insert into data_table(cvID,color) values (#LAST_INSERT_ID, color)
GO
If exists( Select cvID from data_table where cvID= #LAST_INSERT_ID)
Begin
#EXECUTION_OK = 0
End
SCOPE_IDENTITY: Returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.
You can also use the mysql_affected_rows() function to verify that the query has been successful.

can i run a group by statement within stored procedure and return the output as variable

Hi All,
i am a nub to mysql and i am experimenting with stored procedure, i have written a script to calculate count of Respondent id, for now stored procedure returns a cumulative number however i would like resultant grouped by each city. when i attempt that i get an error message stating "Result consisted of more than one row error"
Note: i am aware that i can query using where statement for each city however that method is in-efficient as i have to manually key in each distinct city name hence i am looking for alternatives to efficiently tackle this
any help would be greatly appreciated
regards
Sri
Stored Procedure code
DROP PROCEDURE IF EXISTS `Total_grpby`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE
`total_grpby
`(
OUT ex_total INT
)
BEGIN
SELECT COUNT(rsp_id) As total INTO ex_total
FROM test.`jnk_test`
GROUP BY Dmc_Cty;
END$$
desired output
dmc_cty Total
Chennai 337
Delhi 263
Gurgaon 53
Hyderabad 406
Mumbai 482
Noida 464
Pune 522
No, it's not possible in MySql.
OUT ex_total INT declares a variable of type INT.
The type Int can hold one - and only one value - it is a scalar variable.
However your query returns many values, not one.
To store many values you need something like an array, or a collection.
Unfortunately, MySql doesn't support array nor collection datatypes, so in MySql you cannot store many values in one variable and return them as OUT parameter from the procedure.
This is possible in other databases, like PostgreSQL, Oracle, SQL-Server, they support collection datatypes.
In MySql, an ordinary SELECT (without INTO clause), which is execuded in the procedure, creates a resultset and returns it from the procedure to the client.
Unfortunately MySql is not able to read this resultset - for example if you call a procedura A, that returns a resultset, from another procedure B, then the procedure B is not able to retrieve data from the resultset returned by the procedure A.
This resultset can be read only by some clients, for example JDBC or ODBC connectors, SQLPlus or MySQLWorkbench etc.

How to call a stored procedure and alter the database table in 1 go

I'm really struggeling with this for some time now.
I have a MySQL database and a lot of data. It is a formula1 website i have to create for college.
Right now the j_tracks_rounds_results table is filled with data but one column is not filled out. It's the rank column.
I created a stored procedure as the following:
DROP PROCEDURE `sp_rank`//
delimiter ##
PROCEDURE `sp_rank`(sid INT)
begin
set #i = 0;
SELECT `performance`, subround_id, #i:=#i+1 as rank
FROM `j_tracks_rounds_results`
where subround_id = sid
order by `subround_id`,`performance`;
end
delimiter ;
The output is like the following:
rec.ID PERFORMANCE SUBROUND_ID RANK
87766 100,349114516829 1 1
93040 101,075635087628 1 2
88851 101,664302543497 1 3
It gets the results and ads a rank to it, sorted on performance so the lowest performance gets rank1 etc...
What i am trying to achieve is to put the rank back into the table. Like an ALTER command for the column "rank".
How would i be able to accomplish this?
Basically don't...
Create table to hold the key (rec.id ?) and the rank. Truncate it to get rid of the previous results then use insert into ... with your query and then join to it.
You really don't want to be altering tables in your normal running, guaranteed some one will use the column when it isn't there, and then when you look at the fault it will be...
People just don't look for table structures changing through the application lifetime, it's a screw up waiting to happen.
You are misapplying your SQL statements. You want the UPDATE command, not ALTER.
eg.
UPDATE table SET rank=#i WHERE subround_id=#id