同一组连接表上的 Mysql 联合

Posted

技术标签:

【中文标题】同一组连接表上的 Mysql 联合【英文标题】:Mysql Unions on the Same Set of Joined Tables 【发布时间】:2012-01-14 10:10:39 【问题描述】:

因此,如果以前出现过这种情况,我深表歉意,但我找不到可靠的答案。

我正在尝试从与另一个表连接的表中的一组 3 列中获取一列 id。

仅用于获取单个列的 select 语句如下所示:

SELECT id FROM TableA JOIN TableB USING (key1, key2) WHERE someValue = X;

现在据我了解,我可以通过联合来获得这些:

SELECT spec_id1 AS id FROM TableA JOIN TableB USING (key1, key2) WHERE someValue1 = X
UNION
SELECT spec_id2 AS id FROM TableA JOIN TableB USING (key1, key2) WHERE someValue2 = Y
UNION
SELECT spec_id3 AS id FROM TableA JOIN TableB USING (key1, key2) WHERE someValue3 = Z

有没有办法重用 TableA JOIN TableB USING (key1, key2) 所以它不会为每个选择加入?我还有一个适用于上面未显示的所有选择的 WHERE 条件。我可以重复使用类似的东西吗:

FROM TableA JOIN TableB USING (key1, key2) WHERE someOtherValue = W

我正在尝试使用 mysqli 在 php 中执行此操作。我最初的直觉是使用临时表并查询它,但我不确定如何在 mysqli 中处理它。如果我可以将该表用于多个以下查询,那将是双重理想的,因为连接表中有额外的数据可以稍后使用。

对不起,如果这太天真了,但我并不是一个真正的大型网络开发人员。提前致谢。

编辑: 我正在研究临时表,这似乎是解决它的好方法。在对它进行任何操作之前,我仍然希望确认这是否是一个好主意。

【问题讨论】:

您可以尝试CASE 声明:dev.mysql.com/doc/refman/5.0/en/… 虽然我不太确定这对您的情况有多大用处。我知道您要做什么,但是,一旦将这些列组合在一起,您将如何判断哪个值来自哪个列? 我不在乎它来自哪个专栏。给你一个更具体的例子来说明我在做什么,这 3 列类似于经理 ID、协调员 ID 和主管 ID。每个角色都是截然不同的角色,尽管看起来可能并不像。我正在努力向他们发送一封类似的电子邮件,这只是一般管理类型的电子邮件。无论他们的确切位置如何,他们都会收到相同的电子邮件,因此尽管出于其他原因需要 3 个不同的列,但他们都会收到相同的电子邮件。 啊,明白了。是的,我建议使用 CASE 语句和组合 WHERE 子句,然后如果你真的决定只执行一个查询。 【参考方案1】:

没有捷径可走——除非改变表格的设计。您的方法很可靠,您不必担心查询中有 3 个联接。

如果已知 3 个 spec_id 列表没有任何重叠值,则可以通过将 UNION 更改为 UNION ALL 来提高性能。


在不改变整体UNION 计划的情况下,一种可能的重写是将连接更改为EXISTS 子查询:

    SELECT spec_id1 AS id 
    FROM TableA 
    WHERE EXISTS
          ( SELECT * 
            FROM TableB 
            WHERE (TableB.key1, TableB.key2) = (TableA.key1, TableA.key2)
              AND someValue1 = X
          )
UNION                --- or UNION ALL
    ...
UNION
    ...

或者 - 如果 spec_ids 都包含在另一个 BaseTable 中 - 你可以有这样的东西,这可能会产生更好的执行计划:

SELECT id
FROM BaseTable
WHERE EXISTS
      ( SELECT * AS id 
        FROM TableA 
          JOIN TableB 
            USING (key1, key2) 
        WHERE someValue1
          AND TableA.spec_id1 = BaseTable.id
      )
    OR EXISTS
       ( 
       ...
       )
    OR ...

【讨论】:

如果 3 个列表中的每个列表中可能存在重叠值,但 3 个列表之间没有重叠值,使用 UNION ALL 执行 SELECT DISTINCT 或使用 UNION 执行 SELECT(没有不同或全部)会更便宜吗? 我猜是第一个但最好的方法是测试它(使用您的数据)。如果可以使用UNION ALL,则应该尝试分别优化3个子查询。 确实如此 :-p 出于某种原因,我总是尝试优化然后尝试。我不习惯大多数东西都可以立即测试的 Web 开发。 ;)【参考方案2】:

试试 CASE 语句。你应该能够在没有 UNION 的情况下做到这一点

SELECT 
    CASE 
        WHEN someValue1 = X THEN spec_id1 
        WHEN someValue2 = Y THEN spec_id2 
        WHEN someValue3 = Z THEN spec_id3 
    END
 AS id FROM TableA JOIN TableB USING (key1, key2) 
WHERE 
someValue1 = X OR someValue2 = Y OR WHERE someValue3 = Z

【讨论】:

以上是关于同一组连接表上的 Mysql 联合的主要内容,如果未能解决你的问题,请参考以下文章

SQL:同一表上的多个连接的性能

同一张表上的多个连接,在一个查询中计数

同一张表上的多个连接:转换状态

MYSQL:与 Group_Concatenate 一起使用的两个表上的左连接

在同一个表上具有多个连接的 Oracle 复杂查询

具有多个表的联结表上的 MySQL SELECT 查询