MySQL 程序嵌套游标

MySQL Procedure nested cursor

我正在努力处理 MySQL 程序。所以,我有两个 tables

Table 用户

id      user
--------------
 1     user_1
 2     user_2
 3     user_3
 4     user_4

Table 笔交易

id   user_id   transaction_type
---------------------------
 1      5           cash
 2      5         non cash
 3      5           cash
 4      5           cash
 5      5           cash

现在我想更新事务 table 中的 user_id 并按顺序替换为用户 table 中的 ID。

我想要的结果是这样的

 id   user_id   transaction_type
---------------------------
 1      1           cash
 2      2         non cash
 3      3           cash
 4      4           cash
 5      1           cash

我试过像下面这样的程序,但不能正常工作,也不能按顺序更新。

CREATE DEFINER=`root`@`%` PROCEDURE `sequentially_update`()
BEGIN
    DECLARE finished INTEGER DEFAULT 0;
    DECLARE i int DEFAULT 500;
    DECLARE userId int DEFAULT 0;
    DECLARE transactionType int DEFAULT 0;
    
    DEClARE curTransactions  CURSOR FOR 
        SELECT * FROM transactions;
        
    DECLARE curUsers CURSOR FOR
        SELECT user_id FROM users
        ORDER BY RAND() LIMIT 1;
        
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
    
    OPEN curTransactions; 
        loopTransactions: LOOP 
            FETCH curContacts INTO transactionType; 
            IF finished = 1 THEN 
                LEAVE loopTransactions; 
            END IF; 
            OPEN curUsers; 
                FETCH curUsers INTO userId; 
            CLOSE curUsers; 
            UPDATE transactions SET user_id = userId;
        END LOOP loopTransactions;
    CLOSE curTransactions;
END 

在这种情况下如何在 MySQL 中创建正确的程序?

我建议使用一种稍微不同的方法,避免使用 2 个处理程序(1 个用于用户,1 个用于事务)并为用户使用偏移量和限制。注意,您只需要来自交易的 ID

 DROP TABLE IF EXISTS T,T1;
 
 CREATE TABLE T
 (id  INT,    user VARCHAR(10));
 INSERT INTO T VALUES
(1   ,  'user_1'),
(2   ,  'user_2'),
(3   ,  'user_3'),
(4   ,  'user_4');

CREATE TABLE T1
(id INT,  user_id INT,  transaction_type VARCHAR(10));
INSERT INTO T1 VALUES
( 1   ,   5   ,        'cash'),
( 2   ,   5   ,        'non cash'),
( 3   ,   5   ,        'cash'),
( 4   ,   5   ,        'cash'),
( 5   ,   5   ,        'cash');

DROP PROCEDURE IF EXISTS P;
DELIMITER $$
CREATE PROCEDURE P()
BEGIN
    DECLARE finished INTEGER DEFAULT 0;
    DECLARE i int DEFAULT 500;
    DECLARE userId int DEFAULT 0;
    DECLARE VtransactionID int DEFAULT 0;
    declare voffset int default 0;
    declare vid int;
    declare vmax_rows int;
    
    DEClARE curTransactions  CURSOR FOR 
        SELECT ID FROM t1 order by id;
        
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
    
    select count(*) into vmax_rows from t;
    select vmax_rows;
    OPEN curTransactions; 
        loopTransactions: LOOP 
            FETCH curTransactions  INTO Vtransactionid; 
            IF finished = 1 THEN 
                LEAVE loopTransactions; 
            END IF; 
            select voffset;
            select id into vid from t order by id limit voffset,1;
            set voffset = voffset + 1;
            if voffset  = vmax_rows then 
                set voffset = 0 ;
            end if;
            UPDATE t1 SET user_id = vid WHERE ID = vtransactionID;
        END LOOP loopTransactions;
    CLOSE curTransactions;
END  $$
delimiter ;

call p();

select * from t1;

+------+---------+------------------+
| id   | user_id | transaction_type |
+------+---------+------------------+
|    1 |       1 | cash             |
|    2 |       2 | non cash         |
|    3 |       3 | cash             |
|    4 |       4 | cash             |
|    5 |       1 | cash             |
+------+---------+------------------+
5 rows in set (0.00 sec)