【问题标题】:Is it possible to convert this subquery into a join?是否可以将此子查询转换为连接?
【发布时间】:2012-01-17 03:34:08
【问题描述】:

如果可能,我想用连接替换子查询。

SELECT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`) 
LEFT OUTER JOIN `fftenant_surveyanswer` 
ON fftenant_surveyanswer.surveyquestion_id = 1
AND fftenant_surveyanswer.`surveyresult_id` IN (SELECT y.`surveyresult_id` FROM `fftenant_farmer_surveyresults` y WHERE y.farmer_id = `fftenant_farmer`.`person_ptr_id`)

我试过了:

SELECT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`#, T5.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`) 
LEFT OUTER JOIN `fftenant_farmer_surveyresults` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_farmer_surveyresults`.`farmer_id`) 
LEFT OUTER JOIN `fftenant_surveyanswer` 
ON (`fftenant_farmer_surveyresults`.`surveyresult_id` = `fftenant_surveyanswer`.`surveyresult_id`) 
AND fftenant_surveyanswer.surveyquestion_id = 1 

但这给了我一个农民的每个调查结果的记录。我只想要第一个查询返回的每个农民一条记录。

在大多数 RDBM 上连接可能更快,但我问这个问题的真正原因是我似乎无法制定一个连接来替换子查询,我想知道它是否可能。

【问题讨论】:

  • 没有尝试破译该 ascii-art:您是否尝试过 GROUP BY?
  • 抱歉,它是由 orm 生成的,所以对人类不太友好。

标签: mysql sql


【解决方案1】:

您可以使用 DISTINCTGROUP BY,正如 mvds 和 Brilliand 所建议的那样,但我认为如果您将最后一个联接更改为内部联接,但提高其优先级,它更接近查询的设计意图:

SELECT farmer.person_ptr_id, surveyanswer.text_value
  FROM fftenant_farmer AS farmer
 INNER
  JOIN fftenant_person AS person
    ON person.id = farmer.person_ptr_id
  LEFT
 OUTER
  JOIN
(      fftenant_farmer_surveyresults AS farmer_surveyresults
 INNER
  JOIN fftenant_surveyanswer AS surveyanswer
    ON surveyanswer.surveyresult_id = farmer_surveyresults.surveyresult_id
   AND surveyanswer.surveyquestion_id = 1
)
    ON farmer_surveyresults.farmer_id = farmer.person_ptr_id

总的来说,这最终会得到与 DISTINCTGROUP BY 方法相同的结果,但恕我直言,这是一种更有原则、更少临时性的方式。

【讨论】:

  • 这似乎完美地完成了这项工作,而且很干净。我不知道你可以在 SQL 中做到这一点!
  • 你确定吗?在我看来,这相当于原始海报的第一次尝试;也就是说,每个调查结果会给每个农民一个结果。我相信,在不知道哪些列是关键列的情况下,实际上不可能做原始发布者想要的;并且使用“in”子句实际上是编写此查询的好方法。
  • @DavidWallace:我真的不会说我确定,不;但是布丁的证据就在吃,OP好像吃过了! :-P。 . . (当然,一个查询起初看起来不错,直到它经过更彻底的测试,所以谁知道呢?) 至于 IN 子句:我不确定。我对各个表之间的关系仍然没有很好的把握,但似乎fftenant_farmer_surveyresultsfftenant_surveyanswerfftenant_farmer 之间的桥梁,所以从逻辑上讲,任何加入后两者的查询都可能 应该加入第一个。
  • @ruakh - 我很抱歉。我已经重新阅读了您的答案和 Eloff 的第一次尝试。我现在明白为什么它们不完全相同了。感谢您的耐心等待。
  • @DavidWallace:完全没有必要道歉,没关系。 :-)
【解决方案2】:

使用 SELECT DISTINCT 或 GROUP BY 删除重复条目。

尽可能少地改变你的尝试:

SELECT DISTINCT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`#, T5.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`) 
LEFT OUTER JOIN `fftenant_farmer_surveyresults` 
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_farmer_surveyresults`.`farmer_id`) 
LEFT OUTER JOIN `fftenant_surveyanswer` 
ON (`fftenant_farmer_surveyresults`.`surveyresult_id` = `fftenant_surveyanswer`.`surveyresult_id`) 
AND fftenant_surveyanswer.surveyquestion_id = 1

【讨论】:

  • 实际上这并不完全奏效,因为它不一定从调查答案表中选择具有连接值的重复行。
  • 如果需要一些重复的行,您总是可以对所有应该保留重复的表的主键进行 GROUP BY(而不是使用 SELECT DISTINCT)。大多数数据库(但不是 MySQL)还要求您在 GROUP BY 中包含 SELECT 子句中的所有列。
  • 哎呀,我没有对那些 LEFT JOIN 给予足够的重视。仅删除您想要删除的特定重复项将需要 WHERE 子句来提取未与空调查结果配对的空调查答案。但 ruak 的回答更好。
【解决方案3】:

我问这个问题的真正原因是我似乎无法制定一个连接来替换子查询,我想知道它是否可能

然后考虑一个更简单的例子,例如

SELECT * 
  FROM T1
 WHERE id IN (SELECT id FROM T2);

这被称为semi join,如果需要,可以使用(以及其他可能性)带有SELECT 子句的JOIN 重写到a)仅来自“外部”表的项目,以及b)仅返回 DISTINCT 行:

SELECT DISTINCT T1.* 
  FROM T1
       JOIN T2 USING (id);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-12
    • 2020-05-31
    • 2021-06-23
    • 1970-01-01
    • 2021-08-08
    • 2016-03-02
    • 2020-06-11
    • 1970-01-01
    相关资源
    最近更新 更多