mysql - 使用存储过程游标存储数据的问题

标签 mysql sql stored-procedures cursor

我在这里尝试实现下面的存储过程。但值(value)并没有像预期的那样节省

DELIMITER $$

USE `someDB`$$

DROP PROCEDURE IF EXISTS `AAB`$$

CREATE PROCEDURE `AAB`(IN `feed_setting_user_id` BIGINT)
BEGIN
DECLARE v_friendID, FoFID BIGINT; # use datatype which is used for u.ID used int based on ur result
DECLARE exit_loop, exit_loop1 BOOLEAN DEFAULT FALSE;

DECLARE friend_cursor CURSOR FOR 

    SELECT `u`.`ID` FROM `users` `u`  
    WHERE `u`.`ID` IN (SELECT `u1`.`ID` FROM users `u1` 
    WHERE `u1`.`ID` IN (SELECT `uf`.`friendid` FROM user_friends `uf` WHERE `uf`.`status` = '2' AND `uf`.`userid` = feed_setting_user_id ) 
    OR `u1`.`ID` IN (SELECT `uf2`.`userid` FROM `user_friends` `uf2` WHERE `uf2`.`status` = '2' AND `uf2`.`friendid` = feed_setting_user_id) 
    AND `u1`.`ID` != feed_setting_user_id); 

DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;

DROP TEMPORARY TABLE IF EXISTS unique_tbl; #precaution: when sp stops with error 
CREATE TEMPORARY TABLE unique_tbl (user_id BIGINT UNIQUE); #to avoid duplicate added unique

INSERT INTO unique_tbl VALUES (feed_setting_user_id); # added input from sp

    OPEN friend_cursor;
    friend_loop: LOOP

        FETCH friend_cursor INTO v_friendID;

        IF exit_loop THEN
            LEAVE friend_loop;
        ELSE

            REPLACE INTO unique_tbl VALUES (v_friendID); # since we need all unique id's using replace if exists

            fof: BEGIN

                DECLARE friend_of_friend_cursor CURSOR FOR 


                    SELECT `u`.`ID` FROM `users` `u` WHERE `u`.`ID` NOT IN (feed_setting_user_id) AND `u`.`ID` 
            IN (SELECT `u1`.`ID` FROM `users` `u1` 
            WHERE `u1`.`ID` IN (SELECT `uf`.`friendid` FROM `user_friends` `uf` WHERE `uf`.`status` = '2' AND `uf`.`userid` = v_friendID AND `uf`.`friendid` != v_friendID) 
            OR `u1`.`ID` IN (SELECT `uf2`.`userid` FROM `user_friends` `uf2` WHERE `uf2`.`status` = '2' AND `uf2`.`friendid` = v_friendID AND `uf2`.`userid` != v_friendID) 
            AND `u1`.`ID` != v_friendID ); 

                DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop1 = TRUE;

                OPEN friend_of_friend_cursor;
                friend_of_friend_loop: LOOP

                    FETCH friend_of_friend_cursor INTO FoFID;

                    IF exit_loop1 THEN
                        LEAVE friend_of_friend_loop;
                    END IF;

                    REPLACE INTO unique_tbl VALUES (FoFID);

                END LOOP friend_of_friend_loop;
                CLOSE friend_of_friend_cursor;
            END;
        END IF;
    END LOOP friend_loop;
    CLOSE friend_cursor;

SELECT GROUP_CONCAT(user_id) FROM unique_tbl; #this will show result in comma seperated 2,34,56,78

#cleanup
DROP TEMPORARY TABLE IF EXISTS unique_tbl;

END$$

DELIMITER ;

实际结果:

+-----------------------------------+
| GROUP_CONCAT(user_id)             |
+-----------------------------------+
| 1,2,3,5,6,7,8,9,11,14,15,19,20,26 |
+-----------------------------------+
1 row in set (0,01 sec)

Query OK, 0 rows affected (0,01 sec)

预期结果:

+--------------------------------------+
| GROUP_CONCAT(user_id)                |
+--------------------------------------+
| 1,2,3,5,6,7,8,9,11,14,15,19,20,25,26 |
+--------------------------------------+
1 row in set (0,01 sec)

Query OK, 0 rows affected (0,01 sec)

ID = 25 已被关闭


调试以上两条SQL:

feed_setting_user_id = 15 设置为以下 SQL 查询

SELECT
  `u`.`ID`
FROM
  `users` `u`
WHERE `u`.`ID` IN
  (SELECT
    `u1`.`ID`
  FROM
    users `u1`
  WHERE `u1`.`ID` IN
    (SELECT
      `uf`.`friendid`
    FROM
      user_friends `uf`
    WHERE `uf`.`status` = '2'
      AND `uf`.`userid` = feed_setting_user_id)
    OR `u1`.`ID` IN
    (SELECT
      `uf2`.`userid`
    FROM
      `user_friends` `uf2`
    WHERE `uf2`.`status` = '2'
      AND `uf2`.`friendid` = feed_setting_user_id)
    AND `u1`.`ID` != feed_setting_user_id);

结果:

+----+
| ID |
+----+
|  1 |
| 14 |
| 26 |
+----+
3 rows in set (0,00 sec)

递归地将上述 ID's 替换为 v_friendID 并保持 feed_setting_user_id = 15 并运行下面的 SQL

SELECT
  `u`.`ID`
FROM
  `users` `u`
WHERE `u`.`ID` NOT IN (feed_setting_user_id)
  AND `u`.`ID` IN
  (SELECT
    `u1`.`ID`
  FROM
    `users` `u1`
  WHERE `u1`.`ID` IN
    (SELECT
      `uf`.`friendid`
    FROM
      `user_friends` `uf`
    WHERE `uf`.`status` = '2'
      AND `uf`.`userid` = v_friendID
      AND `uf`.`friendid` != v_friendID)
    OR `u1`.`ID` IN
    (SELECT
      `uf2`.`userid`
    FROM
      `user_friends` `uf2`
    WHERE `uf2`.`status` = '2'
      AND `uf2`.`friendid` = v_friendID
      AND `uf2`.`userid` != v_friendID)
    AND `u1`.`ID` != v_friendID); 

结果如下:

替换 v_friendID = 1feed_setting_user_id = 15

+----+
| ID |
+----+
|  2 |
|  3 |
|  5 |
|  6 |
|  7 |
|  8 |
|  9 |
| 11 |
| 19 |
| 20 |
+----+
10 rows in set (0,00 sec)

替换 v_friendID = 14feed_setting_user_id = 15

+----+
| ID |
+----+
| 15 |
| 25 |
+----+
2 rows in set (0,00 sec)

替换 v_friendID = 26feed_setting_user_id = 15

Empty set (0,00 sec)

value=15 的 ID 被保存到 unique_tbl 中。但不适用于值为 25 的 ID

最佳答案

BEGIN
DECLARE v_friendID, FoFID BIGINT; # use datatype which is used for u.ID used int based on ur result
DECLARE exit_loop, exit_loop1 BOOLEAN DEFAULT FALSE;

DECLARE friend_cursor CURSOR FOR 

    SELECT `u`.`ID` FROM `users` `u`  
    WHERE `u`.`ID` IN (SELECT `u1`.`ID` FROM users `u1` 
    WHERE `u1`.`ID` IN (SELECT `uf`.`friendid` FROM user_friends `uf` WHERE `uf`.`status` = '2' AND `uf`.`userid` = feed_setting_user_id ) 
    OR `u1`.`ID` IN (SELECT `uf2`.`userid` FROM `user_friends` `uf2` WHERE `uf2`.`status` = '2' AND `uf2`.`friendid` = feed_setting_user_id) 
    AND `u1`.`ID` != feed_setting_user_id); 

DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;

DROP TEMPORARY TABLE IF EXISTS unique_tbl; #precaution: when sp stops with error 
CREATE TEMPORARY TABLE unique_tbl (user_id BIGINT UNIQUE); #to avoid duplicate added unique

INSERT INTO unique_tbl VALUES (feed_setting_user_id); # added input from sp

    OPEN friend_cursor;
    friend_loop: LOOP

        FETCH friend_cursor INTO v_friendID;

        IF exit_loop THEN
            LEAVE friend_loop;
        ELSE

            REPLACE INTO unique_tbl VALUES (v_friendID); # since we need all unique id's using replace if exists

            fof: BEGIN

                DECLARE friend_of_friend_cursor CURSOR FOR 


                    SELECT `u`.`ID` FROM `users` `u` WHERE `u`.`ID` NOT IN (feed_setting_user_id) AND `u`.`ID` 
            IN (SELECT `u1`.`ID` FROM `users` `u1` 
            WHERE `u1`.`ID` IN (SELECT `uf`.`friendid` FROM `user_friends` `uf` WHERE `uf`.`status` = '2' AND `uf`.`userid` = v_friendID AND `uf`.`friendid` != v_friendID) 
            OR `u1`.`ID` IN (SELECT `uf2`.`userid` FROM `user_friends` `uf2` WHERE `uf2`.`status` = '2' AND `uf2`.`friendid` = v_friendID AND `uf2`.`userid` != v_friendID) 
            AND `u1`.`ID` != v_friendID ); 

                DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop1 = TRUE;

                OPEN friend_of_friend_cursor;
                friend_of_friend_loop: LOOP

                    FETCH friend_of_friend_cursor INTO FoFID;

                    IF exit_loop1 THEN
                        LEAVE friend_of_friend_loop;
                    END IF;

                    REPLACE INTO unique_tbl VALUES (FoFID);

                END LOOP friend_of_friend_loop;
                CLOSE friend_of_friend_cursor;
                SET exit_loop1 = FALSE; 
            END;
        END IF;
    END LOOP friend_loop;
    CLOSE friend_cursor;
    SET exit_loop = FALSE;

SELECT GROUP_CONCAT(user_id) FROM unique_tbl; #this will show result in comma seperated 2,34,56,78

#cleanup
DROP TEMPORARY TABLE IF EXISTS unique_tbl;

END$$

DELIMITER ;

关于mysql - 使用存储过程游标存储数据的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57159270/

相关文章:

sql-server - 使用 If EXIST DROP 生成脚本,但不包括 SQL Server 中 CREATE 中的 If Not Exists

Android htmlText 上的换行符

mysql group_concat 在哪里

mysql - sql查询获取两个不同表的两行的乘积并将答案插入到两个表之一

mysql - 在 DbVisualizer 中创建 HSQLDB 过程

mysql - 如果为空或计算值,则将设置 col 更新为 0.00

php - 如何在 Zend 中优化我的查询?

mysql - 如何查找 mySQL DB 中没有重复的行?

php - 通过 PDO 使用 MySQL 时收到 "SQLSTATE[42000]: LIMIT ERROR"

sql - 写函数时PostgreSQL sql函数语法错误