【问题标题】:Merging two complex queries合并两个复杂的查询
【发布时间】:2010-07-21 20:48:04
【问题描述】:

我最终做了两个 SQL 查询并在 PHP 中使用 array_intersect() 过滤掉结果:

$sql1 = 'SELECT z.*, u.username, u.user_colour, u.username_clean, u.user_avatar, u.user_avatar_type
    FROM ' . ZEBRA_TABLE . ' z, ' . USERS_TABLE . ' u
    WHERE (( z.user_id = ' . $user->data['user_id'] . '
        AND z.friend = 1
        AND u.user_id = z.zebra_id )
            OR ( z.zebra_id = ' . $user->data['user_id'] . '
                AND z.friend = 1
                AND u.user_id = z.user_id ))
    ORDER BY u.username_clean ASC';

$sql2 = 'SELECT z.*, u.username, u.user_colour, u.username_clean, u.user_avatar, u.user_avatar_type
    FROM ' . ZEBRA_TABLE . ' z, ' . USERS_TABLE . ' u
    WHERE (( z.user_id = ' . $user_id . '
        AND z.friend = 1
        AND u.user_id = z.zebra_id )
            OR ( z.zebra_id = ' . $user_id . '
                AND z.friend = 1
                AND u.user_id = z.user_id ))
    ORDER BY u.username_clean ASC';

两个查询的结构是相同的,唯一的区别是在第二个查询中$user->data['user_id](第一人称)被替换为$user_id(第二人称)。我想检索两个用户共有的朋友。谁能将其合并到一个查询中,这样我就不必使用两个查询并调用array_intersect()

【问题讨论】:

  • 您使用什么风格的 SQL?是否支持 INTERSECT 运算符?
  • MySQL。我从不知道 INTERSECT 运算符。
  • 一个普通的“多对多”关系表,有 2 个(或更多条目)共同:参见stackoverflow.com/questions/477006/…
  • 我刚刚检查过,MySQL 没有 INTERSECT 运算符。但是......“mysql intersect”的网络搜索带来了很多人的解决方法。也许其中之一会有所帮助?

标签: php sql mysql intersection


【解决方案1】:

嗯,你总是可以同时子查询:

$sql = 'SELECT a.* 
    FROM ('.$sql1.') AS a 
    JOIN ('.$sql2.') AS b ON a.user_id = b.user_id AND a.username = b.username';

您可能希望将u.user_id 添加到两个查询u.user_id AS u_user_id 的字段列表中,然后将第二个连接子句从a.username = b.username 更改为a.u_user_id = b.u_user_id...

编辑:现在我仔细看了一下,这两个查询几乎相同......为什么不做这样的事情(将 where 子句替换为 this):

WHERE z.friend = 1 
   AND (
       ( z.user_id = '.$user_id.' AND u.user_id = z.zebra_id )
        OR
       (z.zebra_id = '.$user_id.' AND u.user_id = z.user_id )
   ) AND (
       ( z.user_id = '.$user->data['user_id'].' AND u.user_id = z.zebra_id )
        OR
       (z.zebra_id = '.$user->data['user_id'].' AND u.user_id = z.user_id )
   ) 

这应该会给你两个查询相交的结果,并且更快,因为它可以更好地优化(希望如此)......

哦,它们位于不同的 where 块中,因为在少数情况下 z.user_id 匹配 $user_id,但 z.zebra_id 匹配 $user->data['user_id']... 所以我没有列出所有排列,而是将其列出像这样……

【讨论】:

  • +1 这可能是 更好 选项,因为并非所有 SQL 风格都有 INTERSECT
  • 感谢 ircmaxell,这就是我想要的。我是数据库新手,您可能会看到我的 SQL 查询变得非常草率。
  • 我必须指出——这不会将两个查询合并为 1 个查询,而是将它们合并为 3 个查询。另外 - WHERE 子句替换似乎不起作用。 z 表不能在一行中包含 (u.user_id, @friend_id1)(u.user_id, @friend_id2),您必须添加对 z 表的第二个引用
  • 这是一种带有嵌套选择的惰性方法,可能无法很好地扩展。
  • @gnarf 一点也不。他想合并相同的结果行并删除其他所有内容。由于他选择 z.*,它们相同的唯一方法(假设正常形式)是如果 $user_id == $user->data['user_id'] (这会短路并因此将整个 where 子句减少到 3 个语句),或者如果z.user_id == 两个变量之一,如果 z.zebra_id == 另一个。所以不,没有必要在 z 上重新加入(事实上,它会更加消耗性能)......
【解决方案2】:

您可以通过将用户表链接到斑马表两次来选择与这两个用户都是朋友的用户:

SELECT u.username, u.user_colour, u.username_clean, u.user_avatar, u.user_avatar_type 
FROM users u
JOIN zebra z1 ON z1.friend=1 AND (
                   (u.user_id = z1.user_id AND z1.zebra_id = @user_id1)
                   OR (u.user_id = z1.zebra_id AND z1.user_id = @user_id1)
                 )
JOIN zebra z2 ON z2.friend=1 AND (
                   (u.user_id = z2.user_id AND z2.zebra_id = @user_id2)
                   OR (u.user_id = z2.zebra_id AND z2.user_id = @user_id2)
                 )
ORDER BY u.username_clean ASC

JOIN 获取 users 表中的所有行和 zebra 表中的所有行,并查找满足 ON 子句的组合。在这种情况下,第一个加入查找所有与@user_id1 为朋友的用户,第二个加入进一步将其限制为与@user_id2 为朋友的用户。

此查询的执行速度将比使用子查询快得多。如果zebra 表在两个方向上存储friendships,查询会更快,允许您更多地利用表索引,并且您可以删除ON 子句的OR 部分:

SELECT u.username, u.user_colour, u.username_clean, u.user_avatar, u.user_avatar_type 
FROM users u
JOIN zebra z1 ON u.user_id = z1.user_id AND z1.friend=1 AND z1.zebra_id = @user_id1
JOIN zebra z2 ON u.user_id = z2.user_id AND z2.friend=1 AND z2.zebra_id = @user_id2
ORDER BY u.username_clean ASC

【讨论】:

    猜你喜欢
    • 2013-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-27
    相关资源
    最近更新 更多