MySQL多个连接具有多个条件,并根据其他行

时间:2016-12-07 11:03:43

标签: mysql

我正在尝试编写一个查询,向我展示我可能组成的所有robot_partners来攻击特定的机器人。 Database Graph

所以考虑到上面的图像,

案例1:我需要能够看到, Kris控制着Wall-E,Kris和Wall-E目标R2D2,Mike控制着Bender,而Mike和Bender也控制着R2D2,而Wall-E和Bender则是合作伙伴。这表明Kris和Mike将成为攻击R2D2的好队友。

案例2:我也需要能够看到, Kris控制Wall-E,Kris和Wall-E目标GlaDOS,Bender控制GlaDOS,Bender是Wall-E的合作伙伴。在这种情况下,没有人控制Bender并且也是GlaDOS的目标,这意味着找到一个控制Bender的人会对我很有帮助。

案例3:我也需要能够看到, Kris控制着Wall-E,Kris和Wall-E目标Rosie。 Wall-E和Bender是合作伙伴,但Bender并没有瞄准Rosie。

我不关心Wall-E以擎天柱为目标的事实,因为Kris并不针对擎天柱。

现在,如果你和我呆在一起这么久,我就把这个查询写到了一个点,我可以把SELECT INSERT SELECT到我的表中,让我的应用程序在从表中读取之前做一点清理然后再传递结果关闭给用户。我需要帮助才能获得最后一点,所以除了格式化之外,应用程序不需要做任何事情。

这是我现在的查询,

SELECT DISTINCT pt.person_id AS person_1, rt.robot_1 AS robot_1, rt.robot_2 AS target, rp.robot_2 AS robot_2, IFNULL(pt2.person_id, 0) AS person_2
FROM robot_partners AS rp
JOIN robot_targets AS rt ON (rp.robot_1 = rt.robot_1)
LEFT JOIN robot_targets AS rt2 ON (rt.robot_2 = rt2.robot_2 And rp.robot_2 = rt2.robot_1)
JOIN people AS p ON (p.robot_id = rt.robot_1)
JOIN person_targets AS pt ON (p.person_id = pt.person_id And pt.robot_id = rt.robot_2)
LEFT JOIN people AS p2 ON (rt2.robot_1 = p2.robot_id)
LEFT JOIN person_targets AS pt2 ON (p2.person_id = pt2.person_id And rt2.robot_2 = pt2.robot_id)
ORDER BY pt.person_id, rt.robot_1, rt.robot_2, rp.robot_2;

此查询生成如下输出

|person_1 | robot_1 | target | robot_2 | person_2 |
|   1     |    1    |   3    |     2   |    0     |
|   1     |    1    |   3    |     2   |    2     |
|   1     |    1    |   3    |     11  |    0     |
|   1     |    1    |   4    |     2   |    3     |
|   1     |    1    |   4    |     2   |    0     |
|   1     |    1    |   4    |     11  |    0     |
|   1     |    1    |   5    |     2   |    3     |
|   1     |    1    |   5    |     2   |    4     |
|   1     |    1    |   5    |     2   |    0     |
|   1     |    1    |   5    |     11  |    0     |
|   1     |    1    |   6    |     2   |    0     |
|   1     |    1    |   6    |     11  |    0     |
|   1     |    1    |   7    |     2   |    0     |
|   1     |    1    |   7    |     11  |    0     |
|   1     |    1    |   8    |     2   |    0     |
|   1     |    1    |   8    |     11  |    0     |
|   1     |    1    |   9    |     2   |    0     |
|   1     |    1    |   9    |     11  |    0     |
|   1     |    1    |   12   |     2   |    0     |
|   1     |    1    |   12   |     11  |    5     |
|   2     |    2    |   3    |     1   |    1     |
|   3     |    2    |   4    |     1   |    1     |
|   4     |    2    |   5    |     1   |    1     |
|   5     |    11   |   12   |     1   |    1     |

它依赖于DISTINCT来删除一堆重复项,我无法通过重新排列查询来解决这些问题。它还返回一个0 person_2的行,此时还有一行具有person_2 id,直到该点的完全相同的连接流。

例如:

|person_1 | robot_1 | target | robot_2 | person_2 |
|   1     |    1    |   5    |     2   |    4     |
|   1     |    1    |   5    |     2   |    0     |

在这种情况下,我不关心person_2 = 0的行,因为person_2 = 4的行在那里,并且它们具有相同的路径(1,1,5,2,X)。

我无法使用子查询ORDER BY DESC / GROUP BY来摆脱它,因为当这种情况发生时,

|person_1 | robot_1 | target | robot_2 | person_2 |
|   1     |    1    |   5    |     2   |    3     |
|   1     |    1    |   5    |     2   |    4     |
|   1     |    1    |   5    |     2   |    0     |

我需要能够看到第3和第4人拥有连接并使用GROUP BY来删除此信息。

但是我不能忽略person_2 = 0的所有行,因为我需要能够知道案例2何时适用。

至于为什么person_2从NULL转换为0,这是因为存储此数据的表,主键包含所有5列,PK不能为NULL。我也不能只使它成为一个唯一键,因为当我执行INSERT INTO SELECT时...它会不断添加重复行,因为NULL!= NULL。此外,它们中的所有5列都对其各自的表具有外键约束。 0工作的原因是因为我在人员表中有一个虚拟人0。

所以我的理想输出看起来像这样,

|person_1 | robot_1 | target | robot_2 | person_2 |
|   1     |    1    |   3    |     2   |    2     |
|   1     |    1    |   3    |     11  |    0     |
|   1     |    1    |   4    |     2   |    3     |
|   1     |    1    |   4    |     11  |    0     |
|   1     |    1    |   5    |     2   |    4     |
|   1     |    1    |   5    |     2   |    3     |
|   1     |    1    |   5    |     11  |    0     |
|   1     |    1    |   6    |     2   |    0     |
|   1     |    1    |   6    |     11  |    0     |
|   1     |    1    |   7    |     2   |    0     |
|   1     |    1    |   7    |     11  |    0     |
|   1     |    1    |   8    |     2   |    0     |
|   1     |    1    |   8    |     11  |    0     |
|   1     |    1    |   9    |     2   |    0     |
|   1     |    1    |   9    |     11  |    0     |
|   1     |    1    |   12   |     2   |    0     |
|   1     |    1    |   12   |     11  |    5     |
|   2     |    2    |   3    |     1   |    1     |
|   3     |    2    |   4    |     1   |    1     |
|   4     |    2    |   5    |     1   |    1     |
|   5     |    11   |   12   |     1   |    1     |

从结果中删除了这3行。

|   1     |    1    |   3    |     2   |    0     |
|   1     |    1    |   4    |     2   |    0     |
|   1     |    1    |   5    |     2   |    0     |

播放所有设置区域。与sqlfiddle相似。

http://rextester.com/MQCZX67915

以下是此示例中使用的所有表,我也提供了rextester链接。生成所有这些的代码也在rextester链接中。我会做sqlfiddle,但它拒绝运行查询。

感谢您的任何帮助或想法。

人:

+-----------+--------+----------+
| person_id |  name  | robot_id |
+-----------+--------+----------+
|         1 | Kris   |        1 |
|         2 | Mike   |        2 |
|         3 | Sue    |        2 |
|         4 | Dora   |        2 |
|         5 | Walter |       11 |
+-----------+--------+----------+

机器人:

+----------+----------------+
| robot_id |      name      |
+----------+----------------+
|        1 | Wall-E         |
|        2 | Bender         |
|        3 | R2D2           |
|        4 | Data           |
|        5 | HAL 9000       |
|        6 | GlaDOS         |
|        7 | ASIMO          |
|        8 | The Terminator |
|        9 | Rosie          |
|       10 | Optimus Prime  |
|       11 | The Iron Giant |
|       12 | Clank          |
+----------+----------------+

robot_partners:

+------------------+---------+---------+
| robot_partner_id | Robot_1 | Robot_2 |
+------------------+---------+---------+
|                1 |       1 |       2 |
|                2 |       2 |       1 |
|                3 |       1 |      11 |
|                4 |      11 |       1 |
+------------------+---------+---------+

person_targets:

+------------------+-----------+----------+
| person_target_id | person_id | robot_id |
+------------------+-----------+----------+
|                1 |         1 |        3 |
|                2 |         1 |        4 |
|                3 |         1 |        5 |
|                4 |         1 |        6 |
|                5 |         1 |        7 |
|                6 |         1 |        8 |
|                7 |         1 |        9 |
|                8 |         1 |       12 |
|                9 |         2 |        3 |
|               10 |         3 |        4 |
|               11 |         4 |        5 |
|               12 |         5 |       12 |
|               13 |         3 |        5 |
+------------------+-----------+----------+

robot_targets:

+-----------------+---------+---------+
| robot_target_id | Robot_1 | Robot_2 |
+-----------------+---------+---------+
|               1 |       1 |       3 |
|               2 |       1 |       4 |
|               3 |       1 |       5 |
|               4 |       1 |       6 |
|               5 |       1 |       7 |
|               6 |       1 |       8 |
|               7 |       1 |       9 |
|               8 |       1 |      10 |
|               9 |       1 |      12 |
|              10 |       2 |       3 |
|              11 |       2 |       4 |
|              12 |       2 |       5 |
|              13 |       2 |       6 |
|              14 |       2 |       7 |
|              15 |       2 |       8 |
|              16 |      11 |      12 |
+-----------------+---------+---------+

1 个答案:

答案 0 :(得分:1)

做一个人2的所有组合的联合,结合所有组合,或者没有人2,但无论如何前四个部分不在第一个列表中。 注意需要CONCAT_WS来区分1 + 23和12 + 3之间的区别,它们会连接到123 - 这使得它们分别为1~23和12~3。

(SELECT DISTINCT pt.person_id AS person_1, rt.robot_1 AS robot_1, rt.robot_2 AS target, rp.robot_2 AS robot_2, pt2.person_id AS person_2

FROM robot_partners AS rp

JOIN robot_targets AS rt ON (rp.robot_1 = rt.robot_1)

JOIN robot_targets AS rt2 ON (rt.robot_2 = rt2.robot_2 And rp.robot_2 = rt2.robot_1)

JOIN people AS p ON (p.robot_id = rt.robot_1)

JOIN person_targets AS pt ON (p.person_id = pt.person_id And pt.robot_id = rt.robot_2)

JOIN people AS p2 ON (rt2.robot_1 = p2.robot_id)

JOIN person_targets AS pt2 ON (p2.person_id = pt2.person_id And rt2.robot_2 = pt2.robot_id))

UNION

(SELECT DISTINCT pt.person_id AS person_1, rt.robot_1 AS robot_1, rt.robot_2 AS target, rp.robot_2 AS robot_2, IFNULL(pt2.person_id, 0) AS person_2

FROM robot_partners AS rp

JOIN robot_targets AS rt ON (rp.robot_1 = rt.robot_1)

LEFT JOIN robot_targets AS rt2 ON (rt.robot_2 = rt2.robot_2 And rp.robot_2 = rt2.robot_1)

JOIN people AS p ON (p.robot_id = rt.robot_1)

JOIN person_targets AS pt ON (p.person_id = pt.person_id And pt.robot_id = rt.robot_2)

LEFT JOIN people AS p2 ON (rt2.robot_1 = p2.robot_id)

LEFT JOIN person_targets AS pt2 ON (p2.person_id = pt2.person_id And rt2.robot_2 = pt2.robot_id)

WHERE CONCAT_WS('~',pt.person_id, rt.robot_1, rt.robot_2, rp.robot_2)

    NOT IN 

       (SELECT DISTINCT CONCAT_WS('~',pt.person_id, rt.robot_1, rt.robot_2, rp.robot_2)

       FROM robot_partners AS rp

       JOIN robot_targets AS rt ON (rp.robot_1 = rt.robot_1)

       JOIN robot_targets AS rt2 ON (rt.robot_2 = rt2.robot_2 And rp.robot_2 = rt2.robot_1)

       JOIN people AS p ON (p.robot_id = rt.robot_1)

       JOIN person_targets AS pt ON (p.person_id = pt.person_id And pt.robot_id = rt.robot_2)

       JOIN people AS p2 ON (rt2.robot_1 = p2.robot_id)

       JOIN person_targets AS pt2 ON (p2.person_id = pt2.person_id And rt2.robot_2 = pt2.robot_id))

 )

ORDER BY person_1, robot_1, target, robot_2;