不是没有在mysql程序中工作

时间:2015-03-12 04:05:47

标签: mysql stored-procedures

我有这张代表友情的表

+--------+--------+
| user_1 | user_2 |
+--------+--------+
| 1      | 5      |
| 2      | 67     |
| 3      | 23     |
| ...    | ...    |
+--------+--------+

我的目标是创建一个程序,返回用户朋友的朋友(不包括朋友)。

我开始创建一个程序来返回给定用户的朋友

CREATE DEFINER=`user`@`localhost` PROCEDURE `getFriends`(IN `myuser` BIGINT(20))
    NO SQL
BEGIN
DROP TABLE IF EXISTS friends;
CREATE TEMPORARY TABLE friends
SELECT user_2
FROM fb_friends
WHERE user_1=myuser;
END

此过程对用户534477793创建以下临时表

+------------+
|   user_2   |
+------------+
|  527419864 |
|  580101923 |
|  620972114 |
|  651861323 |
|  662123645 |
|  676185145 |
|  682866129 |
|  718761310 |
|  729611272 |
| 1036862839 |
+------------+

然后我创建了另一个调用第一个并返回朋友的朋友的程序

CREATE DEFINER=`user`@`localhost` PROCEDURE `getFriendsOfFriends`(IN `myuser` BIGINT(20))
BEGIN
-- Creates the table friends
CALL getFriends(myuser);

SELECT DISTINCT(fb.user_2)
FROM fb_friends fb, friends f
-- This works
WHERE fb.user_1 IN (f.user_2)
-- This doesn't
AND fb.user_2 NOT IN (f.user_2);

END

查询返回以下内容:

+------------+
|   user_2   |
+------------+
|  729611272 |
|  527419864 |
|  651861323 |
|  676185145 |
| 1036862839 |
|  502741322 |
|  546744626 |
|  636845886 |
|  652813833 |
|  663713246 |
|  682866129 |
|  781419583 |
|  845134109 |
| 1355751897 |
| 1359286892 |
| 1275961636 |
|  620972114 |
|  509609160 |
|  662123645 |
| 1460283586 |
+------------+

所以很明显 NOT IN 不起作用,因为来自getFriends的所有值都在第二个结果集中。

我设法通过做丑陋的事情来获得我想要的结果但是,我仍然想知道这里有什么问题。顺便提一下,没有 NULL 值。

谢谢!

2 个答案:

答案 0 :(得分:0)

这是因为f.user_2中的NOT IN只是一个用户,而不是整个用户。 正确的方法是

SELECT DISTINCT(fb.user_2)
FROM fb_friends fb, friends f
WHERE fb.user_1 IN (f.user_2)
AND fb.user_2 NOT IN (SELECT * FROM friends);

请注意,第一个IN可以替换为=运算符,因为IN列表中只有一个元素。

或者您可以完全删除联接以使查询保持一致(但它可能会使性能回归)

SELECT DISTINCT(fb.user_2)
FROM fb_friends fb
WHERE fb.user_1 IN (SELECT * FROM friends)
AND fb.user_2 NOT IN (SELECT * FROM friends);

答案 1 :(得分:0)

我认为问题可能出在临时表上,我说得对。通过在MySQLWorkbench中执行查询,以下错误是输出:

Error Code: 1137. Can't reopen table: 'friends'

所以我上网查看临时表在同一查询和in fact there is中的使用次数是否有限制。

所以我可能只是将临时表变为永久表(并且每次都预先删除它),所有这些都将按预期工作。 叹息