使用join和子查询优化简单查询

时间:2013-07-17 12:24:51

标签: mysql sql

我有两个表 - object_72194_object_72197_

| attr_72195_ |     | attr_72198_ | attr_72199_  |
| 2013-07-31  |     |   a         | 2013-07-31   |
| 2013-07-30  |     |   b         | 2013-07-31   |
| 2013-07-29  |     |   c         | 2013-07-30   |
| 2013-07-28  |     |   d         | 2013-07-29   |

对于第一个表格中的每一行,我想从attr_72198_小于或等于attr_72199_的第二个表格中获取字段attr_72195_的值。因此,在这种情况下,结果将如下所示:

|attr_72195_  | attr_72196_  |
|2013-07-31   | a            |
|2013-07-30   | c            |
|2013-07-29   | d            |
|2013-07-28   | NULL         | 

我想获得每行的价值。现在我的工作查询如下所示:

SELECT f1.attr_72195_, t.attr_72198_ AS attr_72196_ 
FROM object_72194_ f1 
LEFT OUTER JOIN ( 
 SELECT id, attr_72198_, attr_72199_ FROM object_72197_ t 
) AS t ON t.attr_72199_ <= f1.attr_72195_ 
WHERE ( f1.id_obj = 72194 ) AND (t.attr_72199_ = (
 SELECT MAX(attr_72199_) FROM object_72197_ t 
 WHERE attr_72199_ <= f1.attr_72195_
) OR t.attr_72199_ IS NULL

)ORDER BY f1.id_order DESC

它按预期工作。但由于上一个WHERE块中的子查询,它似乎并不是最佳的。一位程序员建议我使用另一个联接进行分组,但我只是不知道如何。 谢谢!

编辑: 在子查询中删除了不必要的排序并检查了两个查询(我的和连接而不是子查询)并获得了有趣的结果。 EXPLAIN为带有子查询的版本返回了五行,为带有连接的版本返回了四行(id列)。在“行”列中,我为子查询版本提供了13行,为连接版本提供了18行。因此,必须检查大数据以确定要使用的版本。

编辑: 哦,这个带有连接的查询结果不正确,因为它按列

对结果进行分组

编辑: 问题仍然存在。当第二个表中有重复项时,会出现此问题。因此,两个查询都返回与第二个表中一样多的行。但我每行只需要一个值。正如我在示例中的第一个中显示的值为“a”,“b”,“c”和“d”。

编辑: 最后,我做到了。我在第一个表中添加了按唯一字段分组,并返回了之前的分组。所以查询现在看起来像这样:

SELECT f1.attr_72195_, f2.attr_72198_ AS attr_72196_ 
FROM object_72194_ f1
INNER JOIN 
(
 SELECT f1.attr_72195_, MAX(f2.attr_72199_) AS attr_72199_
 FROM object_72194_ f1 
 LEFT OUTER JOIN object_72197_ f2 ON f1.attr_72195_ >= f2.attr_72199_
 GROUP BY f1.attr_72195_
) o
ON f1.attr_72195_ = o.attr_72195_
LEFT OUTER JOIN object_72197_ f2 ON f2.attr_72199_ = o.attr_72199_
GROUP BY f1.id, attr_72195_ ORDER BY f1.id_order DESC

简单而优雅。

1 个答案:

答案 0 :(得分:2)

避免相关的子查询(未测试): -

SELECT f1.attr_72195_, MIN(f2.attr_72198_)
FROM object_72194_ f1
INNER JOIN 
(
    SELECT f1.attr_72195_, MAX(f2.attr_72199_) As Max_attr_72199_
    FROM object_72194_ f1 
    LEFT OUTER JOIN object_72197_ f2
    ON f1.attr_72195_ >= f2.attr_72199_
    GROUP BY f1.attr_72195_
) Sub1
ON f1.attr_72195_ = Sub1.attr_72195_
LEFT OUTER JOIN object_72197_ f2
ON f2.attr_72199_ = Sub1.Max_attr_72199_
GROUP BY f1.attr_72195_

在2个表之间进行LEFT JOIN,并从第2个表中获取小于或等于第一个表的最大日期。内部将结果返回到第一个表并将左连接连接到第二个表。当日期重复时,不确定你想要attr_72198_的哪个值,所以我刚用min函数来获得最小值。

修改

尝试这个应该处理第一个表上的重复项。

SELECT f1.attr_72195_, f2.attr_72198_
FROM object_72194_ f1
INNER JOIN 
(
    SELECT f1.attr_72195_, MAX(f2.attr_72199_) As Max_attr_72199_
    FROM object_72194_ f1 
    LEFT OUTER JOIN object_72197_ f2
    ON f1.attr_72195_ >= f2.attr_72199_
    GROUP BY f1.attr_72195_
) Sub1
ON f1.attr_72195_ = Sub1.attr_72195_
LEFT OUTER JOIN 
(
    SELECT attr_72199_, MIN(attr_72198_) AS attr_72198_
    FROM object_72197_ 
    GROUP BY attr_72199_
) f2
ON f2.attr_72199_ = Sub1.Max_attr_72199_