【问题标题】:Using joins correctly正确使用连接
【发布时间】:2009-08-21 16:59:48
【问题描述】:

我正在寻找有关如何优化此功能的提示....

SELECT   u.uid,
         u.username,
         u.nid,
         wd.pay
FROM     (users_data AS u
          LEFT JOIN winners_data wd
            ON u.nid = wd.nid
               AND u.uid = wd.uid)
         LEFT JOIN dp_node dn
           ON u.nid = dn.nid
WHERE    u.uid = ".$val."
         AND ((dn.TYPE = 'event'
               AND (SELECT Count(nid)
                    FROM   tournament_event
                    WHERE  nid = u.nid
                           AND type_value IN ('A','B','C')) > 0)
               OR (dn.TYPE = 'new_event'
                   AND (SELECT Count(nid)
                        FROM   user_tournament_event
                        WHERE  nid = u.nid
                               AND type_0_value IN ('Y','X')) > 0))
ORDER BY nid ASC

实际上 $val 只不过是来自以下查询的 uid,作为我循环的一部分,一次一个。

SELECT DISTINCT(dump.uid) FROM leader_Jdump AS 转储

有没有办法将此部分也添加到上述查询中?我想如果我能在 MySQL 级别做到这一点会更快。

【问题讨论】:

  • 也许您可以缩进查询以提高可读性,我发现这种格式对大脑来说很难。
  • 你离开了,我的大脑也跟着走了。
  • 我不确定这里是否支持/格式化 HTML。所以在livejournal上发了一个帖子。 shantanuo.livejournal.com/64338.html
  • 我在假设您使用MySQL 的情况下发布了一个答案(因为您的“.$val.”看起来像PHPPHP 始终是MySQLApacheLinuxJolt 和头巾),但您能确认一下吗?
  • 刚刚注意到您 LJ 帖子上的标签。没关系。

标签: sql mysql join subquery


【解决方案1】:

试试这个:

SELECT  u.uid, u.username, u.nid, wd.pay
FROM    users_data AS u
LEFT JOIN
        winners_data wd
ON      (wd.nid, wd.uid) = (u.nid, u.uid)
JOIN    dp_node dn 
ON      dn.nid = u.nid
        AND dn.type IN ('event', 'new_event')
WHERE   u.uid = ".$val."
        AND EXISTS
        (
        SELECT  NULL
        FROM    tournament_event te
        WHERE   te.nid = u.nid
                AND type_value IN ('A', 'B', 'C')
                AND dn.type = 'event'
        UNION ALL
        SELECT  NULL
        FROM    user_tournament_event te
        WHERE   te.nid = u.nid
                AND type_0_value IN ('X', 'Y')
                AND dn.type = 'new_event'

        )
ORDER BY
        u.nid ASC

我从dp_node 中删除了OUTER JOIN,因为您的原始查询在WHERE 子句中的dp_node 字段上需要一个非NULL 条件,所以LEFT JOIN 在这里没有用。

创建以下索引:

users_data (uid, nid)
winners_data (uid, nid)
dp_node (nid, event_type)
tournament_event (nid, type_value)
user_tournament_event (nid, type_0_value)

【讨论】:

  • 该死的Quassnoi,你的速度很快。
  • @Leonel: 你打瞌睡,你输了!
  • @Lionel:你正在拟人化一个 shell 脚本
  • @rexem: 我们shell脚本就是讨厌被拟人化!
  • 谢谢。但是没有引用我在原始帖子中提到的 user_tournament_event 表(在格式化之前)。请查看上面提到的livejournal链接。
【解决方案2】:

我见过这种风格(单行末尾的所有右括号),我想知道人们如何理解它。之前有人要求重新格式化版本:

SELECT    u.uid,
          u.username,
          u.nid,
          wd.pay
FROM      users_data u
          LEFT JOIN winners_data wd
               ON u.nid = wd.nid
               AND u.uid = wd.uid
          LEFT JOIN dp_node dn
               ON u.nid = dn.nid
WHERE     u.uid = ".$val."
          AND (
                (
                    dn.TYPE = 'event'
                    AND (
                        SELECT Count(nid)
                        FROM   tournament_event
                        WHERE  nid = u.nid
                               AND type_value IN ('A','B','C')
                    ) > 0
                )
                OR (
                    dn.TYPE = 'new_event'
                    AND (
                        SELECT Count(nid)
                        FROM   user_tournament_event
                        WHERE  nid = u.nid
                               AND type_0_value IN ('Y','X')
                    ) > 0
                )
          )
ORDER BY  nid ASC

【讨论】:

    【解决方案3】:

    这可能是等效的,但更容易阅读:

    WITH NIDs(type_value,nid) AS (
      SELECT 'event', nid FROM tournament_event
      WHERE type_value IN ('A','B','C')
      UNION ALL
      SELECT 'new_event', nid FROM user_tournament_event
      WHERE type_value IN ('X','Y')
    )
    
    SELECT
      u.uid,
      u.username,
      u.nid,
      wd.pay
    FROM users_data AS u JOIN NIDs AS n
    ON n.nid = u.nid
    AND n.type_value = u."type"
    LEFT JOIN winners_data AS wd
    ON u.nid=wd.nid AND u.uid=wd.uid
    LEFT JOIN dp_node AS dn 
    ON u.nid = dn.nid
    WHERE u.uid=".$val."
    ORDER BY nid ASC
    

    如果“什么样的事件”是一个重要的问题,您最好使用一张表格,您可以通过查看一两列来做出决定。您似乎有两个保存此信息的表(tournament_event 和 user_tournament_event)。例如,您可以将信息存储在此查询的 NID 表达式中。

    添加于 2009 年 8 月 22 日:

    这是相同的查询,CTE 表示为派生表:

    SELECT
      u.uid,
      u.username,
      u.nid,
      wd.pay
    FROM users_data AS u JOIN (
      SELECT 'event', nid FROM tournament_event
      WHERE type_value IN ('A','B','C')
      UNION ALL
      SELECT 'new_event', nid FROM user_tournament_event
      WHERE type_value IN ('X','Y')
    ) AS n(type_value,nid)
    ON n.nid = u.nid
    AND n.type_value = u."type"
    LEFT JOIN winners_data AS wd
    ON u.nid=wd.nid AND u.uid=wd.uid
    LEFT JOIN dp_node AS dn 
    ON u.nid = dn.nid
    WHERE u.uid=".$val."
    ORDER BY nid ASC
    

    【讨论】:

    • FWIW,MySQL 不支持 CTE。
    • @Bill:没有 CTE 支持没问题,因为 CTE 可以重写为派生表。我会在我的答案中添加重写,但我会留下 CTE,这可能更容易让人们阅读。有朝一日,MySQL 可能会支持它,因为它已成为 ANSI/ISO 标准的一部分。
    猜你喜欢
    • 1970-01-01
    • 2010-12-27
    • 2014-12-19
    • 2018-12-12
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2019-05-03
    • 1970-01-01
    相关资源
    最近更新 更多