【问题标题】: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,我不希望这种情况发生。有没有办法解决这个问题?

【问题讨论】:

    标签: sql database ms-access-2010


    【解决方案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
    

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

    【讨论】:

      猜你喜欢
      • 2020-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多