从PHP SQL查询迁移到MySQL存储过程的问题

时间:2019-07-15 11:10:24

标签: php mysql sql stored-procedures migration

我需要将所有SQL查询从PHP迁移到存储过程

我在迁移时遇到语法问题,例如,数组,对于每个循环,联接,内爆函数都需要转换为存储过程

<?php

$id = $this->user->info->ID;
$friendQuery = $this->db->query("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 = '".$id."' ) 
                            OR u1.ID IN (SELECT uf2.userid FROM user_friends uf2 WHERE uf2.status = '2' AND uf2.friendid = '".$id."') AND u1.ID != '".$id."' ) 
                            ")->result_array();

foreach($friendQuery as $key => $fof) {

    $fofQuery[$fof['username']] = $this->db->query("SELECT u.ID FROM users u WHERE u.`ID` NOT IN ('".$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 = '".$fof['ID']."' AND uf.friendid != '".$fof['ID']."') 
            OR u1.ID IN (SELECT uf2.userid FROM user_friends uf2 WHERE uf2.status = '2' AND uf2.friendid = '".$fof['ID']."' AND uf2.userid != '".$fof['ID']."') AND u1.ID != '".$fof['ID']."' ) 
            ")->result_array();

} 
$final_array = array();

foreach($fofQuery as $arr){
    foreach($arr as $a){
        $final_array[$a['ID']] = $a['ID'];
    }
}
$FoFData = array_values($final_array);

foreach($FoFData as $fa){
    $commaList[] = join(',', (array) $fa);
}

$result = implode(",", $commaList);
$data = $this->db->query("SELECT DISTINCT ft.ID as ID, ft.userid, ft.content, ft.timestamp, ft.likes, ft.comments, u.username, u.avatar, ft.friend_id, ft.friend_username, feed_item_setting.*  
                FROM feed_item ft
                LEFT JOIN users u ON ft.userid = u.ID
                JOIN `feed_item_setting` ON `feed_item_setting`.`user_id` = u.id
                WHERE ft.userid = u.ID AND u.ID IN (".$result.",".$id.") ORDER BY ft.ID DESC")->result_array();

我已将上面的代码片段部分转换为存储过程

DELIMITER $$

USE `SomeDB`$$

DROP PROCEDURE IF EXISTS `GetFeedSetting`$$

CREATE PROCEDURE `GetFeedSetting` (IN `feed_setting_user_id` BIGINT) READS SQL DATA DETERMINISTIC SQL SECURITY INVOKER
BEGIN
  DECLARE flag VARCHAR(255);
  DECLARE v_read_setting_status,
          v_write_setting_status,
          v_write_cmt_setting_status,
          v_like_setting_status INT(11);
  SELECT
    `read_status`,
    `write_status`,
    `write_cmt_status`,
    `like_status` 
  INTO v_read_setting_status,
    `v_write_setting_status`,
    `v_write_cmt_setting_status`,
    `v_like_setting_status`
  FROM `feed_item_setting`
  WHERE `user_id` = feed_setting_user_id;

  IF (v_read_setting_status = 3) THEN
    SELECT `u`.`ID` FROM `users` `u` 
    WHERE `u`.`ID` IN (SELECT `uf`.`friendid` FROM `user_friends` `uf` WHERE `uf`.`status` = '2' AND `uf`.`userid` = feed_setting_user_id) 
    OR 
        `u`.`ID` IN (SELECT `uf`.`friendid` FROM `user_friends` `uf` WHERE `uf`.`status` = '2' AND `uf`.`friendid` = feed_setting_user_id)
    OR
        `u`.`ID` = feed_setting_user_id;


  ELSE
    SET flag = 'failure';
  END IF;

  SELECT flag;
END$$


DELIMITER ;

由于我在foreach循环中遇到数组迭代和一些内置的PHP函数(如join)的问题,因此爆裂需要转换为存储过程


更新

DELIMITER $$

USE `someDB`$$

DROP PROCEDURE IF EXISTS `AddFeedFriendItemsMod`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `AddFeedFriendItemsMod`(IN `senderid` BIGINT(255), IN `friendid` BIGINT(255), IN `friendusername` VARCHAR(255), IN `keyword` TEXT)
    MODIFIES SQL DATA
    DETERMINISTIC
    SQL SECURITY INVOKER
BEGIN

        DECLARE v_read_setting_status, v_write_setting_status, v_write_cmt_setting_status,  v_like_setting_status INT(11);
        DECLARE LastFeedId INT;
        DECLARE flag VARCHAR(255);
        INSERT INTO feed_item (`userid`, `content`, `timestamp`, `likes`, `comments`, `user_flag`, `likes_data`, `friend_id`, `friend_username`)
        VALUES (senderid, keyword, CURRENT_TIMESTAMP(), 0, 0, 0, 'like', friendid, friendusername);
        SET LastFeedId = LAST_INSERT_ID();
        INSERT INTO feed_item_likes (`feed_item_id`, `user_id`, `timestamp`, `is_like`)
        VALUES (LastFeedId, senderid, CURRENT_TIMESTAMP(), 0);
        SELECT LastFeedId;


        SELECT `read_status`, `write_status`, `write_cmt_status`, `like_status` INTO v_read_setting_status, `v_write_setting_status`, `v_write_cmt_setting_status`, `v_like_setting_status`
        FROM `feed_item_setting`
        WHERE `user_id` = friendid;

        IF (v_write_setting_status = 0) THEN
            SELECT `u`.`ID` FROM `users` `u` WHERE 
            `u`.`ID` IN (SELECT `uf`.`friendid` FROM `user_friends` `uf` WHERE `uf`.`status` = '2' AND `uf`.`userid` = friendid  ) 
            OR 
            `u`.`ID` IN (SELECT `uf`.`userid` FROM `user_friends` `uf` WHERE `uf`.`status` = '2' AND `uf`.`friendid` = friendid )
            OR
            `u`.`ID` = friendid;

        ELSEIF (v_write_setting_status = 1) THEN
            SELECT `ID` FROM `users` WHERE `users`.`ID`= friendid;

        ELSEIF (v_write_setting_status = 2) THEN
            SELECT `u`.`ID` FROM `users` `u` WHERE 
            `u`.`ID` IN (SELECT `uf`.`friendid` FROM `user_friends` `uf` WHERE `uf`.`status` = '2' AND `uf`.`userid` = friendid  ) 
            OR 
            `u`.`ID` IN (SELECT `uf`.`userid` FROM `user_friends` `uf` WHERE `uf`.`status` = '2' AND `uf`.`friendid` = friendid )
            OR
            `u`.`ID` = friendid;

        ELSEIF (v_write_setting_status = 3) THEN

            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` = friendid ) 
                OR `u1`.`ID` IN (SELECT `uf2`.`userid` FROM `user_friends` `uf2` WHERE `uf2`.`status` = '2' AND `uf2`.`friendid` = friendid) 
                AND `u1`.`ID` != friendid);

            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 (friendid); # 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 (friendid) 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;

        ELSEIF (v_write_setting_status = 4) THEN
            SELECT `ID` FROM `users`;

        ELSE
            SELECT `ID` FROM `users`;
        END IF;




    END$$

DELIMITER ;

实际结果:

Query: CREATE DEFINER=`root`@`localhost` PROCEDURE `AddFeedFriendItemsMod`(IN `senderid` BIGINT(255), IN `friendid` BIGINT(255), IN `fr...

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_cursor CURSOR FOR 
                SELECT `u`.`ID` FROM `users` `u`  
        ' at line 43

获取错误w.r.t(v_write_setting_status = 3)块。

1 个答案:

答案 0 :(得分:0)

DELIMITER $$

USE `someDB`$$

DROP PROCEDURE IF EXISTS `AAB`$$

CREATE PROCEDURE `AAB`(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;
                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 ;