【问题标题】:MySQL combination of view, subquery and left join produces a strange result视图、子查询和左连接的 MySQL 组合产生了一个奇怪的结果
【发布时间】:2015-03-23 08:01:25
【问题描述】:

更新 1

我发现它什么时候做错了。如果视图由两个表组成,则只有第一个表中的字段在子查询中具有值。我不知道为什么,但是如果我更改 JOIN 顺序,它会起作用。一旦我尝试将另一个字段与第二个表匹配,它就会再次返回 NULL。

更新 2

我在这里创建了一个工作示例:http://sqlfiddle.com/#!2/d4eb97/1

更新 3

相同的示例适用于较新的 MySQL 版本 (5.6.6),因此 5.5 中可能存在错误 - http://sqlfiddle.com/#!9/4e140/2


我有一个架构,我在其中结束了这样的 SQL:

SELECT view.user,
(
    SELECT tableA.user
    FROM tableA
    LEFT JOIN tableB ON tableA.id = tableB.tableA_id
    WHERE tableA.user = view.user
    LIMIT 1
) as b_user
FROM view
WHERE view.user = 1

我在这里做的很简单:

  1. view 中选择两个字段
    view 是 MySQL 视图,而不是真实表。
  2. 第二个字段是一个子查询:
    2.1 表的字段用户tableA
    2.2 与表tableB 与关系字段的左连接
    tableB 中还没有行
    2.3 仅当tableA 用户与view 中的用户相同
    2.4 限制1,仅用于本例
  3. 将结果限制为user = 1

这里奇怪的是,在某些情况下b_user这个字段是NULL,但是数据是ok的。

我可以进行三个更改以使其正常工作:

修复 1

手动输入用户ID使其工作

SELECT view.user,
(
    SELECT tableA.user
    FROM tableA
    LEFT JOIN tableB ON tableA.id = tableB.tableA_id
    WHERE tableA.user = 1
    LIMIT 1
) as b_user
FROM view
WHERE view.user = 1

修复 2

删除左连接也使其工作:

SELECT view.user,
(
    SELECT tableA.user
    FROM tableA
    WHERE tableA.user = view.user
    LIMIT 1
) as b_user
FROM view
WHERE view.user = 1

修复 3

另一种选择是不使用 MySQL 视图:

SELECT view.user,
(
    SELECT tableA.user
    FROM tableA
    WHERE tableA.user = view_table_a.user
    LEFT JOIN tableB ON tableA.id = tableB.tableA_id
    LIMIT 1
) as b_user
FROM view_table_a INNER JOIN view_table_b ON condition
WHERE table_a.user = 1

我无法手动重现此重新创建新数据库架构,它仅发生在我当前的设置中,由于安全原因,我无法在此处公开。

为什么子查询返回 NULL 值?我需要使第一个查询工作,因为我无法使用这三个修复中的任何一个。

【问题讨论】:

  • 您有问题吗?
  • 我认为这是含蓄的,抱歉。为什么子查询返回 NULL 值?
  • 如果您愿意,请考虑遵循以下简单的两步操作: 1. 如果您还没有这样做,请提供适当的 DDL(和/或 sqlfiddle),以便我们可以更轻松地复制问题。 2. 如果您尚未这样做,请提供与步骤 1 中提供的信息相对应的所需结果集。
  • 我什至无法自己复制这个问题,我决定问一下,以防有人对此有任何想法......我仍在寻找,如果我能重现它,我将发布所有 SQL所以你可以正确地测试它。
  • 我取得了一些进展,这个问题有一个 sqlfiddle:sqlfiddle.com/#!2/d4eb97/1

标签: mysql sql subquery views left-join


【解决方案1】:

为什么首先要有子查询?我喜欢子查询,它们是非常方便的东西。但如果非必要,则不应使用它们。如果没有我们的帮助,查询可能会变得足够复杂。

您正在从主表中寻找特定用户(实际上它是一个视图是无关紧要的),然后使用相同的 User 值加入 TableA,然后使用与该用户关联的 ID 值选择性地加入到 TableB :

select  rs.Origin, a.Origin as Same_Origin
from    requests_status  rs
join    assignments      a
    on  a.employee = rs.employee
    and a.origin   = rs.origin
left join assignments_author aa
    on  aa.assignment = a.id
where   rs.employee = 1;

然后我注意到在您的小提琴中,您创建了 assignments_author 表但从未填充它。但这并不重要,因为你离开加入它。但是您不使用该表中的任何数据。所以实际上,您的查询中根本不需要该表。因此,等效查询将是:

select  rs.Origin, a.Origin as Same_Origin
from    requests_status  rs
join    assignments      a
    on  a.employee = rs.employee
    and a.origin   = rs.origin
where   rs.employee = 1;

我不知道为什么你得到一个 NULL 而不是另一个。但是由于上面的查询在两个小提琴中返回相同的答案并且这是预期的结果,所以我的工作已经完成。

【讨论】:

  • 谢谢。我不能停止使用子查询,因为在我的应用程序中,requests_status 有更多字段,我必须匹配到不同的表,所以我使用子查询来匹配基于某些字段值的行。作业只是其中一种可能性。我开始认为可能与此有关:bugs.mysql.com/bug.php?id=52051
  • 是的,看起来它可能是一个实际的错误。但我仍然会在选择列表中查看子查询的使用。我发现其中很少(只有一个我能真正记住)无法转换为联接。首先将其完全删除。查看您获得的数据并推理出您可能如何获得剩余数据。这可能是不可能的。但首先要假设它是。
  • 我找到了一种解决方法,不是通过连接,因为在我的场景中,性能最差,而是通过现有的 cron 进程将数据保存在同一个表中。还是谢谢
【解决方案2】:

我认为这是一个错误,可能是这个错误 (http://bugs.mysql.com/bug.php?id=52051),因为查询在 MySQL 5.5 (http://sqlfiddle.com/#!2/d4eb97/1) 中失败,但在 5.6 (http://sqlfiddle.com/#!9/4e140/2) 中有效

【讨论】:

    猜你喜欢
    • 2015-11-26
    • 2021-09-25
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 2014-05-25
    • 2012-11-21
    • 2021-03-03
    • 1970-01-01
    相关资源
    最近更新 更多