使用 MySQL 个存储过程从结果集中选择唯一值

Selecting unique values from the result set using MySQL stored procedures

从上述结果集中选择不同的值,即,从而消除重复值,并最终将这些值存储到具有逗号分隔值列表的变量中。这样,分配有逗号分隔值列表的变量必须作为另一个 SQL IN 运算符

的输入
DELIMITER $$

USE `someDB`$$

DROP PROCEDURE IF EXISTS `AAA`$$

CREATE PROCEDURE `AAA`(IN `feed_setting_user_id` BIGINT)
    READS SQL DATA
    DETERMINISTIC
    SQL SECURITY INVOKER
BEGIN
  DECLARE FoFID, FoFUsername, friendID, friendUsername TEXT;
  DECLARE exit_loop BOOLEAN DEFAULT FALSE;
    DECLARE friend_cursor CURSOR FOR 

        SELECT `u`.`ID`, `u`.`username` 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;

        OPEN friend_cursor;
        friend_loop: LOOP
            FETCH FROM friend_cursor INTO friendID, friendUsername;
            IF exit_loop THEN
                LEAVE friend_loop;
            END IF;
            -- SELECT  friendID, friendUsername;
            SELECT `u`.`ID`, `u`.`username` 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` = friendID AND `uf`.`friendid` != friendID) 
                            OR `u1`.`ID` IN (SELECT `uf2`.`userid` FROM `user_friends` `uf2` WHERE `uf2`.`status` = '2' AND `uf2`.`friendid` = friendID AND `uf2`.`userid` != friendID) AND `u1`.`ID` != friendID ); 
        END LOOP friend_loop;
        CLOSE friend_cursor;
END $$

DELIMITER ;

实际结果:

+----+-----------+
| ID | username  |
+----+-----------+
|  5 | SpiderMan |
|  8 | AntMan    |
|  9 | Bat       |
| 11 | SuperMan  |
| 12 | Arrow     |
| 13 | CAmerica  |
+----+-----------+
6 rows in set (0.53 sec)

+----+----------+
| ID | username |
+----+----------+
|  9 | Bat      |
| 10 | BatMan   |
| 13 | mustafa  |
+----+----------+
3 rows in set (0.61 sec)

+----+-----------+
| ID | username  |
+----+-----------+
|  5 | SpiderMan |
|  6 | Hulk      |
|  9 | Bat       |
| 10 | BatMan    |
+----+-----------+
4 rows in set (0.69 sec)

+----+----------+
| ID | username |
+----+----------+
|  8 | AntMan   |
|  9 | Bat      |
| 10 | BatMan   |
| 11 | SuperMan |
+----+----------+
4 rows in set (0.78 sec)

Query OK, 0 rows affected (0.86 sec)

预期结果:

5,6,8,9,11,12,10,13

我们需要将上面的逗号分隔值列表分配给一个变量。 所以我们需要从上面的值列表中删除重复项。


更新:

尝试实现嵌套游标

DELIMITER $$

USE `someDB`$$

DROP PROCEDURE IF EXISTS `AAA`$$

CREATE PROCEDURE `AAA`(IN `feed_setting_user_id` BIGINT)
    READS SQL DATA
    DETERMINISTIC
    SQL SECURITY INVOKER
BEGIN
  DECLARE FoFID, FoFUsername, friendID, friendUsername TEXT;
  DECLARE exit_loop BOOLEAN DEFAULT FALSE;
  DECLARE exit_loop1 BOOLEAN DEFAULT FALSE;
    DECLARE friend_cursor CURSOR FOR 

        SELECT `u`.`ID`, `u`.`username` 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;

        OPEN friend_cursor;
        friend_loop: LOOP
            FETCH FROM friend_cursor INTO friendID, friendUsername;
            IF exit_loop THEN
                LEAVE friend_loop;
            END IF;
--          SELECT  friendID, friendUsername;


            DECLARE friend_of_friend_cursor CURSOR FOR 

             SELECT `u`.`ID`, `u`.`username` 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` = friendID AND `uf`.`friendid` != friendID) 
                            OR `u1`.`ID` IN (SELECT `uf2`.`userid` FROM `user_friends` `uf2` WHERE `uf2`.`status` = '2' AND `uf2`.`friendid` = friendID AND `uf2`.`userid` != friendID) AND `u1`.`ID` != friendID );
            DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop1 = TRUE;               

            OPEN friend_of_friend_cursor;
                friend_of_friend_loop: LOOP
                    FETCH FROM friend_of_friend_cursor INTO FoFID, FoFUsername;
                    IF exit_loop1 THEN
                        LEAVE friend_of_friend_loop;
                    END IF;

                SELECT  FoFID, FoFUsername;

                END LOOP friend_of_friend_loop;
            CLOSE friend_of_friend_cursor;

        END LOOP friend_loop;
        CLOSE friend_cursor;
END $$

DELIMITER ;

结果:

Error Code: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DECLARE friend_of_friend_cursor CURSOR FOR 

             SELECT `u`.`ID`, `u`.`user' at line 29

试试下面的 sp

DELIMITER $$

USE `someDB`$$

DROP PROCEDURE IF EXISTS `AAA`$$

CREATE PROCEDURE `AAA`(IN `feed_setting_user_id` BIGINT)
    modifies SQL DATA
    DETERMINISTIC
    SQL SECURITY INVOKER
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 ;