我需要将所有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)块。
答案 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 ;