【问题标题】:sql self join on multiple attributessql 自连接多个属性
【发布时间】:2011-11-29 05:04:08
【问题描述】:

我有一个(旧)表,其中包含列:

bug_num   build_id    closed_to
1         3            NULL
2         4            NULL
3         NULL         1
4         3            NULL
5         NULL         2

我想编写一个查询,它将选择特定版本中的所有错误,以及该版本中已关闭的所有错误。因此,如果我想为构建 3 执行此操作,它将包括 #s 1 和 4(因为它们在构建 3 中)以及 3,因为它已关闭构建 3 (1) 中的错误。

我以为我很接近:

SELECT stat.bug_num, 
       stat.build_id 
FROM   bug_status stat 
       JOIN bug_status stat2 
         ON stat2.closed_to = stat.bug_num 
WHERE  stat.build_id = 3; 

...但它似乎并没有给我想要的结果。谢谢你的帮助!

【问题讨论】:

  • 澄清一下,“关闭”不是构建 ID,而是错误编号。

标签: mysql sql join


【解决方案1】:
SELECT stat.bug_num,
       stat.build_id
  FROM bug_status  stat
 WHERE stat.build_id = 3
    OR stat.closed_to IN
        ( SELECT stat2.bug_num
            FROM bug_status  stat2
           WHERE stat2.build_id = 3
        )
;

(也可以使用 JOIN,或者使用 JOIN 和 UNION,但我相信上面是最直观的方式。)


编辑添加:这是一个展示上述内容的 MySQL 成绩单:

mysql> create table bug_status
    -> (bug_num numeric, build_id numeric, closed_to numeric);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into bug_status values (1, 3, null);
Query OK, 1 row affected (0.00 sec)

mysql> insert into bug_status values (2, 4, null);
Query OK, 1 row affected (0.01 sec)

mysql> insert into bug_status values (3, null, 1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into bug_status values (4, 3, null);
Query OK, 1 row affected (0.00 sec)

mysql> insert into bug_status values (5, null, 2);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT stat.bug_num,
    ->        stat.build_id
    ->   FROM bug_status  stat
    ->  WHERE stat.build_id = 3
    ->     OR stat.closed_to IN
    ->         ( SELECT stat2.bug_num
    ->             FROM bug_status  stat2
    ->            WHERE stat2.build_id = 3
    ->         )
    -> ;
+---------+----------+
| bug_num | build_id |
+---------+----------+
|       1 |        3 |
|       3 |     NULL |
|       4 |        3 |
+---------+----------+
3 rows in set (0.00 sec)

编辑添加,因为IN (...) 方法似乎在 OP 版本的 MySQL 中不起作用:这是一个提供相同结果的替代查询:

SELECT stat.bug_num,
       stat.build_id
  FROM bug_status  stat
  LEFT
 OUTER
  JOIN bug_status  stat2
    ON stat.closed_to = stat2.bug_num
 WHERE stat.build_id = 3
    OR stat2.build_id = 3
;

【讨论】:

  • 不幸的是,当一个 bug 被另一个 bug 关闭时,build ID 会被清除,因为不知道另一个 bug 什么时候会真正实现,所以我需要将 closed_to 直接映射到 bug_num...
  • 重读时,看起来您的解决方案可能有效,但由于某种原因,sql 似乎不喜欢嵌套查询。
  • @pennstatephil:这很奇怪。我刚刚在 MySQL 5.1.53 版本上测试了我的查询,它返回了完全正确的行。有没有可能你抄错了什么?
  • @pennstatephil:哎呀,对不起,我错了,在子查询中写 stat 而不是 stat2。将更新我的答案。
  • @pennstatephil:是的,我想这一定是因为 MySQL 版本的不同。我添加了一个替代版本,它使用 LEFT OUTER JOIN 而不是 IN (SELECT ...) - 实际上,我认为这与 Branko Dimitrijevic 在 cmets 中建议的 knittl 答案相同 - 愿意尝试一下吗?
【解决方案2】:

您的 WHERE 子句中没有包含 stat2.build_id(我认为您的 ON 列取自错误的表):

SELECT stat.bug_num, stat.build_id
FROM bug_status stat
LEFT JOIN bug_status stat2
ON stat.closed_to = stat2.bug_num
WHERE stat.build_id = 3 OR stat2.build_id = 3

【讨论】:

  • 奇怪...如果我完全去掉 where 子句,它会给出一堆 bug id 为 0 并且构建 id 为 null 的行。似乎连接没有正确地将表连接在一起?
  • 这是不对的。它有几个问题;例如,stat2.build_id = 3 永远不会为真,因为bug_status.build_id IS NULL 每当bug_status.closed_to IS NOT NULL 时(至少在问题中的示例数据中)。
  • 试试ON stat.closed_to = stat2.bug_num
  • @ruakh:是的,但我们不加入 build_id,而是加入 closed_to <-> bug_num
  • @knittl 好主意,但你需要LEFT JOIN。修复该问题后,您的查询将返回正确的结果。
【解决方案3】:

为什么不:

DECLARE  @build_id int = <the build id>

SELECT   stat.bug_num, stat.build_id, stat.closed_to
FROM     bug_status stat
WHERE    stat.build_id = @build_id 
   OR    stat.closed_to = @build_id

【讨论】:

  • +1 在 SQL 上,但语法看起来像 TSQL 而不是 MySQL。您最好删除声明并在答案中输入文字值,然后让 OP 弄清楚如何处理参数
  • closed_to 映射到 bug_num 而不是 build_id
【解决方案4】:

这个查询...

SELECT *
FROM bug_status t1
WHERE
    build_id = 3
    OR EXISTS (
        SELECT *
        FROM bug_status t2
        WHERE
            t2.build_id = 3
            AND t1.closed_to = t2.bug_num
    )

...产生以下结果:

bug_num   build_id    closed_to
1         3           NULL
3         NULL        1
4         3           NULL

用简单的英语:选择这样的行:

  • build_id = 3
  • 或者有build_id = 3的相关行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 2021-10-31
    • 2018-08-03
    相关资源
    最近更新 更多