2012-01-17 152 views
1

如果可能,我想用连接替换子查询。是否可以将此子查询转换为连接?

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上连接可能会更快,但我问这个问题的真正原因是我似乎无法制定一个连接来替换子查询,我想知道它是否可能。

+4

没有试图破译ascii-art:你尝试过GROUP BY吗? – mvds 2012-01-17 03:42:30

+0

对不起,它是由orm生成的,所以它不是非常人性化的。 – Eloff 2012-01-17 04:19:04

回答

3

你可以使用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方法,但更强调原则性,少特设方式,恕我直言。

+0

这似乎是完美的工作,而且很干净。我不知道你可以在SQL中做到这一点! – Eloff 2012-01-17 05:18:55

+0

你确定吗?这在我看来就像是等同于原始海报的第一次尝试;也就是说,每个调查结果会给每个农民一个结果。我相信,实际上不可能做到原始海报想要的东西,而不知道哪些专栏是关键专栏;并且使用“in”子句实际上是编写此查询的一种非常好的方法。 – 2012-01-17 05:23:18

+0

@DavidWallace:我真的不会说我确定,不会;但布丁的证明是在吃,而OP似乎已经吃光了! :-P。 。 。 (当然,起初查询看起来很好,直到测试更彻底,所以谁知道?)至于IN子句:我不确定。我仍然没有很好地理解各种表之间的关系,但是'fftenant_farmer_surveyresults'似乎是'fftenant_surveyanswer'和'fftenant_farmer'之间的桥梁,所以在逻辑上,加入后两者的任何查询都应该*加入第一个。 – ruakh 2012-01-17 05:44:48

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 
+0

这有效,我不能相信,没有发生在我身上。谢谢! – Eloff 2012-01-17 04:19:36

+0

实际上,这并不奏效,因为它不一定要从调查答案表中选择具有连接值的重复行。 – Eloff 2012-01-17 05:16:42

+0

如果需要某些重复行,则始终可以使用GROUP BY保留重复项的所有表的主键(而不是使用SELECT DISTINCT)。大多数数据库(但不包括MySQL)也将要求您将所有列包含在GROUP BY中的SELECT子句中。 – Brilliand 2012-01-18 07:31:15

1

的真正原因我问这个问题是我似乎无法制定一个连接来取代子查询,我想知道,如果它甚至有可能

然后考虑一个非常简单的例子,以从例如开始

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

这被称为一个semi join和如果需要,可以使用(以及其它可能性)一个JOIN只从“外”表SELECT子句一个)项目,和b)只返回重写DISTINCT行:

SELECT DISTINCT T1.* 
    FROM T1 
     JOIN T2 USING (id); 
相关问题