【问题标题】:Nested Join in Subquery and failing correlation子查询中的嵌套连接和关联失败
【发布时间】:2015-06-04 18:11:30
【问题描述】:

我有 3 个表 sc_user、sc_cube、sc_cube_sent

我想加入一个用户查询(sc_user)一个不同的随机消息/多维数据集(来自 sc_cube),它之前没有发送给那个用户(sc_cube_sent),所以结果集中的每一行都有一个不同的用户 ID以及来自 sc_cube 的随机立方体 ID,它不是 sc_cube_sent 的一部分,并且与该用户 ID 相关联。

我面临的问题是我似乎无法在内部 On 子句中需要外部查询的 u.id 的情况下使用关联 ID。我需要注释部分才能使其正常工作。

# get one random idcube per user not already sent to that user
SELECT u.id, sub.idcube
FROM sc_user as u
LEFT JOIN (
    SELECT c.idcube, sent.idreceiver FROM sc_cube c
    LEFT JOIN sc_cube_sent sent ON ( c.idcube = sent.idcube /* AND sent.idreceiver = u.id <-- "unknown column u.id in on clause" */  )
WHERE sent.idcube IS NULL
ORDER BY RAND()
LIMIT 1
) as sub
ON 1

我添加了一些数据:http://sqlfiddle.com/#!9/7b0bc/1 应该为用户 1 显示的新立方体 (sc_cube) 如下:2150、2151、2152、2153

编辑>>

我可以用另一个子查询而不是连接来做到这一点,但这会对性能产生巨大影响并且是不可行的(每个表上几千行的 30 秒+,并具有合理实现的键),所以我仍在寻找一个使用 JOIN 解决方案的方法。

SELECT
u.id,
(SELECT sc_cube.idcube
FROM sc_cube
WHERE NOT EXISTS(
      SELECT sc_cube.idcube FROM sc_cube_sent WHERE sc_cube_sent.idcube = sc_cube.idcube AND sc_cube_sent.idreceiver = u.id
)
ORDER BY RAND() LIMIT 0,1
) as idcube
FROM sc_user u

【问题讨论】:

  • 你能添加一些数据或 sql fiddle 吗?您还指定 idcube 为空的位置,因此您的 on 子句不能基于 idcube
  • 您想要 user1 的所有这些结果吗?我以为你是按 rand 订购并限制 1
  • 每个用户元组没有一个随机 id
  • 哦,好的,明白了...所以您的初始查询有问题...没有返回的 idreceivers...sqlfiddle.com/#!9/8d1df/5
  • 感谢 John,但我不需要 idreceiver,您正在检查 2 个已知 id,我希望 idcube 与结果集中的每个用户行相关。

标签: mysql sql join subquery


【解决方案1】:

如果无法对此进行测试,我会说您需要将 sc_user 包含在子查询中,因为您失去了范围

LEFT JOIN 
(   SELECT c.idcube, sent.idreceiver 
    FROM sc_user u
    JOIN sc_cube c ON c.whatever_your_join_column_is = u.whatever_your_join_column_is
    LEFT JOIN sc_cube_sent sent ON ( c.idcube = sent.idcube AND sent.idreceiver = u.id  )
    WHERE sent.idcube IS NULL
    ORDER BY RAND()
    LIMIT 1
) sub

【讨论】:

  • 谢谢约翰!问题在于失去 sc_user 范围是查询是更大查询的摘录,其中 u 是非常外部范围的一部分。我将设置一些数据的小提琴。
【解决方案2】:

如果您想获得尚未发送给特定用户的消息 ID,那么为什么要使用联接或左联接呢?
做吧:

SELECT sent.idcube 
FROM sc_cube_sent sent 
WHERE sent.idreceiver <> u.id

那么查询可能如下所示:

SELECT u.id, 
       /* sub.idcube */
      (  SELECT sent.idcube 
         FROM sc_cube_sent sent 
         WHERE sent.idreceiver <> u.id
         ORDER BY RAND()
         LIMIT 1
      ) as idcube
FROM sc_user as u

【讨论】:

  • 我觉得你根本不需要LEFT JOIN,详情请看答案。
  • 因为我需要的 id 在 sc_cube_sent 中不是或可能不是(可能发送给其他用户),而是 sc_cube。仅发送的 id 位于 sc_cube_sent 中,因此加入。而且我需要每个用户一个随机的立方体 id(将 id 分散)
  • 感谢 kordirko,我修改了该方法(请参阅描述编辑),但这种方法非常慢(30+ 秒与 JOIN 解决方案中的 0.04 秒......但没有用户相关性)
【解决方案3】:

让它在 on 子句中使用 NOT IN 子选择。虽然关联链接 u.id 未在 LEFT JOIN 范围内给出,但它适用于 ON 子句的范围。以下是它的工作原理:

SELECT u.id, sub.idcube
FROM sc_user as u
LEFT JOIN ( 
     SELECT idcube FROM sc_cube c ORDER BY RAND()
) sub ON ( 
  sub.idcube NOT IN ( 
     SELECT s.idcube FROM sc_cube_sent s WHERE s.idreceiver = u.id
  ) 
)
GROUP BY u.id

小提琴:http://sqlfiddle.com/#!9/7b0bc/48

【讨论】:

  • 如果您对为什么会收到该错误感到好奇,如果您已将导致错误的检查移至 WHERE 子句,则必须专门针对您最初使用 ON 子句相同的子查询,您将避免错误消息。在这里查看我的问题:stackoverflow.com/questions/35788185/…
  • Nm,我撒谎了。它适用于我的情况,但不适用于这种情况:sqlfiddle.com/#!9/7b0bc/49
猜你喜欢
  • 2015-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
  • 1970-01-01
  • 2011-04-23
相关资源
最近更新 更多