仅从分组依据中选择一行?

Posted

技术标签:

【中文标题】仅从分组依据中选择一行?【英文标题】:Select only one row from a group by? 【发布时间】:2015-09-03 16:28:43 【问题描述】:

我正在使用 Microsoft Access 2010,我有一个表 T_Offers,如下所示:

Key    ID    Date          Name           Text
---    --    ----------    -----------    -----------  
1      10    10/10/2015    Lorem          Consectetur
2      10    10/10/2015    Ipsum          Amet
3      11    27/09/2014    Dolor          Sit
4      13    12/11/2013    Sit            Dolor
5      14    11/07/2015    Amet           Ipsum
6      14    12/07/2015    Consectetur    Lorem 

我只需要获取每个 ID 的一行(日期最小的那一行),因此,例如,此表的结果将是:

Key    ID    Date          Name           Text
---    --    ----------    -----------    -----------  
1      10    10/10/2015    Lorem          Consectetur
3      11    27/09/2014    Dolor          Sit
4      13    12/11/2013    Sit            Dolor
5      14    11/07/2015    Amet           Ipsum

这是我尝试过的查询之一:

SELECT ID, name, text, MIN (date) AS minDate
FROM (SELECT ID, name, text, date
      FROM T_Offers
      GROUP BY ID, name, text, date
      ORDER BY ID asc) as X
GROUP BY ID, name, text

这可以正常工作,但有一个小问题:如果 2 个具有相同 ID 的报价具有相同的日期,则结果表将重复 ID,我不希望这种情况发生。有没有办法解决这个问题?

【问题讨论】:

【参考方案1】:

您可以使用NOT EXISTS 排除存在具有相同 ID 和更早日期的另一行的所有行:

SELECT  t1.Key, t1.ID, t1.Date, t1.Name, t1.Text
FROM    t_offers AS t1
WHERE   NOT EXISTS
        (   SELECT  1
            FROM    T_Offers AS t2
            WHERE   t2.ID = t1.ID
            AND     t2.Date < t1.Date
        );

这将为每个 ID 留下 1 行,它将是日期最早的行。

关于然后删除第一个日期相同的重复项,我不确定您的逻辑,但您可能需要进一步检查,这可能会变得非常混乱。在这种情况下,我使用了Key 来确定应该返回两条记录中的哪一条。

SELECT  t1.Key, t1.ID, t1.Date, t1.Name, t1.Text
FROM    t_offers AS t1
WHERE   NOT EXISTS
        (   SELECT  1
            FROM    T_Offers AS t2
            WHERE   t2.ID = t2.ID
            AND (   t2.Date < t1.Date
                OR  (t2.Date = t1.Date AND t2.Key < t1.Key)
                )
        );

【讨论】:

这就是答案,谢谢(无论如何我认为子查询条件 t2.ID = t2.ID 应该是 t2.ID = t1.ID 对吗?还有另一个问题:你能解释一下“SELECT 1”是什么意思? 是的,确实应该是t2.ID = t1.ID。我已经纠正了这一点。在EXISTS 子句中,不会检索列,但您仍需要在SELECT 之后放置一些内容。对我来说SELECT 1 只是一种风格选择,其他人更喜欢SELECT NULLSELECT *。我选择SELECT 1,因为它更短,并且表明我不关心值的意图,只是存在一行。有一个related question here【参考方案2】:

假设 id 不重复,这是在 Access 中执行此操作的一种方法:

select o.*
from t_offers as o
where o.key = (select min(o2.key)
               from t_offers as o2
               where o2.id = o.id
              );

【讨论】:

对不起,如果我现在才问,我忘了在问题中包含这个:有没有办法让每个 id 只选择 1 条记录,但日期最短? @MattiaNocerino 。 . .根据问题中的数据,看起来key 是唯一的,所以这个每个id 只选择一条记录。【参考方案3】:

您需要一个选择不同的查询:

SELECT DISTINCT ID, name, text, MIN (date) AS minDate
FROM T_Offers
GROUP BY ID, name, text
ORDER BY ID asc;

【讨论】:

这与我已经尝试过的东西非常相似,并且给出了同样的问题:如果有 2 个具有相同 ID 和相同日期的报价,我将不会获得不同的 ID跨度> 如果它们具有相同的 id、name、text 和 date,distinct 将删除重复的行。但是,如果您有相同的 ID、相同的日期,但名称或文本不同,则不会。在这种情况下,您希望查询如何响应?如果您不关心出现的所有不同名称和文本,请不要按它们分组:SELECT DISTINCT ID, name, text, MIN (date) AS minDate FROM T_Offers GROUP BY ID ORDER BY ID asc;【参考方案4】:

这是我的解决方案。虽然我的测试环境是mysql,但sql语法是一样的。

SELECT TO1.KEY,TO1.ID,TO.DATE,TO1.NAME,TO1.TEXT
FROM T_Offer TO1 
INNER JOIN   
(
 select MIN(TO2.KEY) AS KEY  from T_Offer TO2 group by ID 
)TO3 
ON TO1.KEY = TO3.KEY

建议:如果您方便的话,我可以帮助您提供创建表和插入测试数据的脚本。

【讨论】:

以上是关于仅从分组依据中选择一行?的主要内容,如果未能解决你的问题,请参考以下文章

SQL“分组依据”问题 - 我无法选择每一列

加入和分组依据 - 选择列表中的列无效

即使字段包含在分组依据列表中,分组依据或聚合错误

选择匹配日期到 min() 分组依据

MongoDB 选择 * 分组依据

Pandas 中的 SQL 选择和分组依据