Table acc
If I Edit "A" Amount to 100 then Total amount change
whole table need to update...
So What Will be the mysql query for updating whole table by adding (credit) or subtracting (debit) from previous total amount...
As commented by #Gordon Linoff, you can archive your goal using AFTER UPDATE trigger and a loop. I wrote up the idea as below for example.
DELIMITER //
CREATE TRIGGER acc_after_update
AFTER UPDATE
ON acc FOR EACH ROW
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE type varchar(10);
DECLARE total_amount DEFAULT 0;
DECLARE name varchar(10)
DECLARE amount INT;
DECLARE cur1 CURSOR FOR SELECT name, type, amount FROM acc;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
REPEAT
FETCH cur1 INTO name, type, amount;
IF NOT done THEN
CASE type
WHEN 'credit' THEN = total_amount + amount;
WHEN 'debit' THEN total_amount = total_amount - amount
END CASE
UPDATE acc
SET amount = total_amount
WHERE name = #name --not sure about this syntax
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
END; //
DELIMITER ;
Hope this helps.
CREATE VIEW [dbo].[vSales]
AS
SELECT ROW_NUMBER() OVER(ORDER BY s.[Name] ) AS 'RowNo',
s.*
, CASE WHEN Type = 'Credit' THEN Amount ELSE - 1 * Amount END As NewAmount
FROM dbo.Sales AS s
GO
SELECT a.[RowNo],
a.[Name],
SUM(b.[NewAmount])
FROM dbo.vSales AS a INNER JOIN dbo.vSales AS b ON a.[RowNo] >= b.[RowNo]
GROUP BY a.[RowNo], a.[Name]
dbo.Sales is the table that holds all the values
Related
I have a mysql function which will change records accordingly . But loop only execute for one time and leaves loop with this condition. "IF v_finished =1 THEN
LEAVE get_stock;
END IF;"
However its is supposed to execute multiple time. Like in my test case 3 times
BEGIN
DECLARE P_stock int(11);
DECLARE P_product int(11);
DECLARE V_From_warehouse int(11);
DECLARE V_To_warehouse int(11);
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE V_To_warehouse_stock int(11);
DECLARE V_From_warehouse_stock int(11);
declare cur1 cursor for
SELECT material_transfer_details.product_id , material_transfer_details.quantity FROM
material_transfers,
material_transfer_details
WHERE
material_transfers.id = material_transfer_details.mtm_id
AND
material_transfers.status = 'Y'
AND
material_transfers.id = V_MTM_id;
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
SELECT warehouse_from INTO V_From_warehouse FROM material_transfers WHERE id =V_MTM_id;
SELECT warehouse_to INTO V_To_warehouse FROM material_transfers WHERE id =V_MTM_id;
OPEN cur1;
get_stock: LOOP
IF v_finished =1 THEN
LEAVE get_stock;
END IF;
fetch cur1 into P_product , P_stock;
SELECT quantity INTO V_To_warehouse_stock from stocks where warehouse_id = V_To_warehouse and product_id = P_product;
SELECT quantity INTO V_From_warehouse_stock from stocks where warehouse_id = V_From_warehouse and product_id = P_product;
IF (V_To_warehouse_stock IS NOT NULL)
THEN
UPDATE
stocks SET quantity = quantity - P_stock
WHERE
warehouse_id = V_to_warehouse
AND
product_id = P_product;
ELSE
INSERT INTO stocks(product_id , warehouse_id , quantity ,status, created_datetime , updated_datetime) values
(P_product , V_to_warehouse , 0-P_stock , 'Y', sysdate() , sysdate());
END IF;
IF (V_From_warehouse_stock IS NOT NULL)
THEN
UPDATE
stocks SET quantity = quantity + P_stock
WHERE
warehouse_id = V_from_warehouse
AND
product_id = P_product;
ELSE
INSERT INTO stocks(product_id , warehouse_id , quantity ,status, created_datetime , updated_datetime) values
(P_product , V_from_warehouse , P_stock , 'Y', sysdate() , sysdate());
END IF;
SET P_stock = 0;
SET P_product = 0;
END LOOP get_stock;
CLOSE cur1;
UPDATE material_transfers SET Status = 'N' WHERE id= V_MTM_id;
UPDATE material_transfer_details SET Status = 'N' WHERE mtm_id = V_MTM_id;
return '00000';
END
Two things:
First, change your code.
get_stock: LOOP
SET v_finished = FALSE;
fetch cur1 into P_product , P_stock;
IF v_finished =1 THEN
LEAVE get_stock;
END IF;
Since you are doing other things that could trip the handler, reset v_finished, then fetch from the cursor, and only then test whether to leave the loop.
As written, if you hadn't tripped the handler prematurely, you would have been testing in entirely the wrong place and would have stayed in the loop too long.
Next... be sure you understand SELECT ... INTO. I don't think it does quite what you think it does.
A scalar subquery is a much safer solution:
SET V_To_warehouse_stock = (SELECT quantity from stocks where warehouse_id = V_To_warehouse and product_id = P_product);
If SELECT ... INTO returns no rows, the variable's value does not change. It retains its former value, if one exists, and that is rarely what you expect.
Spooky action at a distance like this is best avoided, and it's an easy trap to fall into, in a loop.
See examples of this effect at https://dba.stackexchange.com/a/35207/11651.
I have a medium sized stored procedure going on here below. My problem is that it doesn't do anything and I have no idea why.
1.) First of all, the code:
DROP PROCEDURE IF EXISTS deleteabundant_fixshared_shiftResources;
DELIMITER //
CREATE PROCEDURE deleteabundant_fixshared_shiftResources ()
BEGIN
DECLARE finish_flag BOOLEAN DEFAULT FALSE;
DECLARE id INT(11);
DECLARE startTime DATETIME;
DECLARE endTime DATETIME;
DECLARE shid INT(11);
DECLARE resid INT(11);
DECLARE id_inner INT(11);
DECLARE startTime_inner DATETIME;
DECLARE endTime_inner DATETIME;
DECLARE shid_inner INT(11);
DECLARE resid_inner INT(11);
DECLARE cr130 CURSOR FOR SELECT shift_resource_id, start_date, end_date, shift_id, resource_id FROM temp_shift_resource;
DECLARE cr131 CURSOR FOR SELECT shift_resource_id, start_date, end_date, shift_id, resource_id FROM temp_shift_resource;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finish_flag = TRUE;
START TRANSACTION;
OPEN cr130;
OPEN cr131;
OUTERLOOP: LOOP
FETCH cr130 into id, startTime, endTime, shid, resid;
IF finish_flag THEN LEAVE OUTERLOOP; END IF;
INNERLOOP: LOOP
FETCH cr131 INTO id_inner, startTime_inner, endTime_inner, shid_inner, resid_inner;
IF finish_flag THEN LEAVE INNERLOOP; END IF;
IF (id!=id_inner) THEN
IF (resid=resid_inner AND shid_inner!=9) THEN
-- logic to determine if the dates are wrong:
IF (startTime<=startTime_inner AND endTime>=endTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FD", shid_inner, resid_inner, startTime_inner, endTime_inner );
DELETE FROM temp_shift_resource WHERE shift_resource_id = id_inner;
ELSEIF (endTime>=endTime_inner AND startTime<=endTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FU", shid_inner, resid_inner, startTime_inner, endTime_inner );
UPDATE temp_shift_resource set endTime_inner=(startTime - INTERVAL 1 DAY) where shift_resource_id = id_inner;
ELSEIF (startTime<=startTime_inner AND endTime>=startTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FU", shid_inner, resid_inner, startTime_inner, endTime_inner );
UPDATE temp_shift_resource set startTime_inner=(endTime + INTERVAL 1 DAY) where shift_resource_id = id_inner;
END IF;
END IF;
END IF;
END LOOP INNERLOOP;
SET finish_flag = FALSE;
END LOOP OUTERLOOP;
CLOSE cr130;
CLOSE cr131;
COMMIT;
END //
DELIMITER ;
call deleteabundant_fixshared_shiftResources();
2.) Description of what I want to do:
Basically, I have a table full of workshifts. Due to code bugs, some of these shifts have a wrong date assigned to them, and I have to fix the database.
I have to run through the whole table, and compare the rows that are assigned to the same resource_id, which represents a person. So if a person has two shifts that look like (2016-05-10 to 2016-05-20) and (2016-05-15 to 2016-05-23) for example, I have to fix it so that one of them will be trimmed to (2016-05-10 to 2016-05-14) and (2016-05-15 to 2016-05-23).
A shift that is a nightshift, marked as shift_id=9, must not be modified at all.
I insert rows into the repairchange table if a change or a deletion has been made
3.) The procedure runs, but does nothing. I have examples in the database for wrong rows, one example is the one I wrote above. I suspect it is the nested loop, because I want to loop and fetch through the same table, but I haven't found anything on that.
I got the message
0 row(s) affected, 1 warning(s): 1329 No data - zero rows fetched, selected, or processed
but I have seen this before and my stored procedures have worked even though they output this warning.
Any ideas or tips are welcome. Thank you for your time!
I figured it out, after quite some debugging:
I opened the cursors before both of the loops. This meant that after the first walk-through of the inner loop, the cursor was standing at +1 of the LAST row of the table, and when the new outer loop iteration started the second inner loop iteration, the cursor was still at the end position.
Thus it did not run. I replaced the inner-cursor opening and closing into the outer loop, and now it works properly.
could you please give me an advice how to CALL prcd with SELECT results? Or advice me pls better solution.. I am open minded to all working solution
I have a procedure to control inserting data ...
CREATE PROCEDURE control_insert (
)
And I need to pass data from SELECT results to procedure ...
SELECT t.c1, t.c2
FROM table t1
LEFT JOIN other_table t2
ON t1.id = t2.id
WHERE 1=1
The point is, I need to get some data via SELECT (around 6 tables joined to the base table) and I need to do control for each row before insert.. each row should meet some conditions .. if it doesn't meet them, it should just skip it and process next one ...
The procedure should look like:
CREATE PROCEDURE control_insert (
IN v_c1 INT,
IN v_c2 INT
)
BEGIN
IF v_c1 > 1 THEN
INSERT INTO controlled_table (id, type) VALUES (v_c1, v_c2);
ELSE
/* do nothing */
END IF;
END;
CALL control_insert ( SELECT .... );
Could you help me with that? Is there any possibility to do this via MySQL? I can write a PERL skript, but I want to avoid this type of solution ... I just one to do it only in MySQL way
Thank you
EDIT1: I need to check if ID of the SELECT result and LABEL is already in this table for specific date ... this code above is only an example to demonstrate the situation
SOLUTION
I've found the solution ... so for the other visitors:
calling procedure:
CALL controlInsert();
procedure body:
CREATE PROCEDURE controlInsert()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE v_id INT;
DECLARE v_id_dupl INT;
DECLARE v_label INT;
DECLARE v_date DATE;
DECLARE v_type VARCHAR(100);
DECLARE v_category VARCHAR(255);
DECLARE v_user VARCHAR(255);
DECLARE v_country VARCHAR(255);
DECLARE c1 CURSOR FOR SELECT id, label, date, type, category, user, country FROM t1 LEFT JOIN ... /* whole select with 6 joins ended by ; */
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
## open cursor
OPEN c1;
## loop through the cursor
read_loop: LOOP
## fetch cursor into variables
FETCH c1 INTO v_id , v_label, v_date, v_type, v_category, v_user, v_country;
## check if there is any record
IF done THEN
LEAVE read_loop;
END IF;
## get count of existing records
SELECT count(*) INTO v_id_dupl
FROM
WHERE 1=1
AND id = v_id
AND label= v_label
AND date = v_date;
## if v_id_dupl = 0 => no rows found (ok to load)
IF (v_id_dupl = 0) THEN
INSERT INTO target_table (id, label, date, type, category, user, country)
VALUES (v_id , v_label, v_date, v_type, v_category, v_user, v_country);
END IF;
END LOOP;
CLOSE c1;
END
If that is all your stored procedure is doing, then you don't actually need it. You can do the whole thing in a single statement:
INSERT INTO controlled_table (id, type)
SELECT t.c1, t.c2
FROM table t1
LEFT JOIN other_table t2 ON t1.id = t2.id
WHERE something = somethingElse
AND t.c1 > 1
Essentially, I've just combined your original query with the INSERT statement in your procedure.
If your procedure is more complex and needs to do multiple operations on each row, then you should look into using a cursor.
I have a stored procedure which uses temporary tables so that I can summarize the sales of all the products within a certain product category. When I tried to run the code it failed. I search on google and here on stackoverflow but couldn't find what I had done wrong. I'm using MySQL server 5.5 on Windows Server.
CREATE PROCEDURE `getStatistics`(IN `startDate` date,IN `endDate` date,IN `categoryName` varchar)
BEGIN
CREATE TEMPORARY TABLE procResult(productName VARCHAR, amount INT);
CREATE TEMPORARY TABLE tblProductID(SELECT ID, `name` FROM product WHERE categoryID = (SELECT ID FROM category WHERE `name` = categoryName));
DECLARE done_amt, done_PID INT DEFAULT FALSE;
DECLARE amount, productID INT DEFAULT 0;
DECLARE pidCursor CURSOR FOR SELECT ID, `name` FROM tblProductID;
DECLARE amtCursor CURSOR FOR SELECT orderlines.amount FROM orderlines WHERE orderlines.productID = productID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done_amt = TRUE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done_PID = TRUE;
OPEN pidCursor;
pid_loop:LOOP
DECLARE productName VARCHAR;
FETCH pidCursor INTO productID, productName;
IF done_PID THEN
LEAVE pid_LOOP;
END IF;
OPEN amtCursor;
amt_loop:LOOP
DECLARE tmpAmount INT DEFAULT 0;
FETCH amtCursor INTO tmpAmount;
IF done_amt THEN
LEAVE amt_loop;
END IF;
amount = amount + tmpAmount;
END LOOP;
CLOSE amtCursor;
IF amount > 0 THEN
INSERT INTO procResult VALUES (productName, amount);
amount = 0;
END IF;
END LOOP;
CLOSE pidCursor;
END;
You must define the length of VARCHAR type variables, such as the categoryName parameter to your stored procedure;
You must DECLARE all local variables at the very start of a BEGIN ... END compound statement block, before any other commands;
Your syntax for CREATE TABLE ... SELECT is incorrect;
You have declared two handlers for the same SQL condition, only one of which will be executed (indeterminately);
You will need to change your client's statement delimiter in order for it to understand that the semicolons appearing within the procedure body do not terminate the CREATE PROCEDURE statement;
Your entire procedure is an extremely complicated way of doing a fairly simple task in SQL:
CREATE TEMPORARY TABLE procResult
SELECT product.name, SUM(orderlines.amount) AS amount
FROM orderlines
JOIN product ON product.ID = orderlines.productID
JOIN category ON category.ID = product.categoryID
WHERE category.name = ?
GROUP BY product.ID
HAVING amount > 0
I'm stuck on how to get incremented id and max, min, sum or count from the previous insertion statement.
Can anyone advice me how to do that in simple way?
CREATE PROCEDURE INSERTRECORD()
BEGIN
INSERT INTO tb_normalized_data_20110615
SELECT * FROM tb_normalized_data WHERE
date_added BETWEEN '2011-06-15 01:10:00' and '2011-06-15 01:19:59'
-- Stuck here how to get the value for(x_min_id, x_max_id, x_min_date,
-- x_max_date) from the statement above without querying again?
INSERT INTO tb_backup_tracker(min_id, max_id, min_date, max_date)
VALUES(x_min_id, x_max_id, x_min_date, x_max_date);
END;
I think you're looking for a cursor. Basically, here's how it could work:
DECLARE cur CURSOR FOR SELECT * FROM tb_normalized_data WHERE
date_added BETWEEN '2011-06-15 01:10:00' and '2011-06-15 01:19:59';
DECLARE ID INT;
DECLARE DT DATE;/* Declare all of your columns */
DECLARE MIN_ID INT;
DECLARE MAX_ID INT;
DECLARE MIN_DATE DATE;
DECLARE MAX_DATE DATE;
-- add your other columns here...
BEGIN
OPEN cur;
read_loop: LOOP
FETCH cur INTO ID, DT /* Fetch into all of your columns */;
IF ID < MIN_ID THEN
SET #MIN_ID = ID;
IF ID > MAX_ID THEN
SET #MAX_ID = ID;
END IF;
INSERT INTO tb_normalized_data_20110615 (ID, DATE_ADDED
/*, rest of your columns*/ ) VALUES( /* columns */ );
END LOOP;
INSERT INTO tb_backup_tracker(min_id, max_id, min_date, max_date)
VALUES(min_id, max_id, min_date, max_date);
CLOSE cur;
Use a cursor to loop through the data and inside the cursor loop both insert and keep track of min/max values for whatever you need.
Also, your code is brittle: avoid the pattern INSERT INTO TABLE SELECT * FROM ...; if the second table adds a column your SQL will break. It's good practice to name the columns explicitly anyway.
Post if you need help with the cursor.