【问题标题】:Group by minimum value in one field while selecting distinct rowsSQL:在选择不同行时按一个字段中的最小值分组
【发布时间】:2020-11-29 19:47:17
【问题描述】:

这就是我想要做的。假设我有这张桌子:

key_id | id | record_date | other_cols
1      | 18 | 2011-04-03  | x
2      | 18 | 2012-05-19  | y
3      | 18 | 2012-08-09  | z
4      | 19 | 2009-06-01  | a
5      | 19 | 2011-04-03  | b
6      | 19 | 2011-10-25  | c
7      | 19 | 2012-08-09  | d

对于每个 id,我想选择包含最小记录日期的行。所以我会得到:

key_id | id | record_date | other_cols
1      | 18 | 2011-04-03  | x
4      | 19 | 2009-06-01  | a

我见过的唯一解决方案是假设所有 record_date 条目都是不同的,但在我的数据中并非如此。使用带有两个条件的子查询和内部联接会给我一些 id 的重复行,这是我不想要的:

key_id | id | record_date | other_cols
1      | 18 | 2011-04-03  | x
5      | 19 | 2011-04-03  | b
4      | 19 | 2009-06-01  | a

【问题讨论】:

  • 如果有 min_by 函数,请考虑使用它。它使我免于编写更复杂的东西。

标签: sql group-by max distinct min


【解决方案1】:
SELECT p.* FROM tbl p
INNER JOIN(
  SELECT t.id, MIN(record_date) AS MinDate
  FROM tbl t
  GROUP BY t.id
) t ON p.id = t.id AND p.record_date = t.MinDate
GROUP BY p.id

此代码消除了重复的record_date,以防有相同的ids 和相同的record_date
如果要重复,请删除最后一行 GROUP BY p.id

【讨论】:

    【解决方案2】:
    select 
        department, 
        min_salary, 
        (select s1.last_name from staff s1 where s1.salary=s3.min_salary ) lastname 
    from 
        (select department, min (salary) min_salary from staff s2 group by s2.department) s3
    

    【讨论】:

    • 欢迎来到 Stack Overflow。在 Stack Overflow 上不鼓励仅使用代码的答案,因为它们没有解释它是如何解决问题的。请编辑您的答案以解释此代码的作用以及它如何改进此问题已有的现有答案,以便对其他有类似问题的用户有用。
    【解决方案3】:

    如果record_date 在组内没有重复项:

    将其视为过滤。简单地从当前组中获取 (WHERE) 一个 (MIN(record_date)) 行:

    SELECT * FROM t t1 WHERE record_date = (
                                     select MIN(record_date)
                                     from t t2 where t2.group_id = t1.group_id)
    

    如果一个组内可能有 2+ 分钟 record_date

    1. 过滤掉非最小行(见上文)

    2. 然后 (AND) 在给定的group_id 内从至少 2+ 的 record_date 行中选择一个。例如。选择具有最小唯一键的那个:

                      AND key_id = (select MIN(key_id)
                                    from t t3 where t3.record_date = t1.record_date
                                                and t3.group_id    = t1.group_id)
      

    所以

    key_id | group_id | record_date | other_cols
    1      | 18       | 2011-04-03  | x
    4      | 19       | 2009-06-01  | a
    8      | 19       | 2009-06-01  | e
    

    将选择key_ids:#1 和#4

    【讨论】:

      【解决方案4】:

      怎么样:

      SELECT mt.*     
      FROM MyTable mt INNER JOIN
          (
              SELECT id, MIN(record_date) AS MinDate
              FROM MyTable
              GROUP BY id
          ) t ON mt.id = t.id AND mt.record_date = t.MinDate
      

      这会获取每个 ID 的最小日期,然后根据这些值获取值。唯一会出现重复的情况是同一 ID 的最小记录日期重复。

      【讨论】:

      • 啊,最初我使用表达式来输出导致内部连接上的“和”条件无法正常工作的日期。将其更改为实际列,现在可以使用(因此不得不修改其他一些内容),谢谢!
      • 当存在两条相同 id 和 date 的记录时,这将不起作用,会得到多行吗?
      【解决方案5】:

      我想在这里添加一些其他答案,如果您不需要 第一个 项,但说第二个数字,例如您可以在子查询中使用 rownumber 并根据您的结果开始吧。

      SELECT * FROM
      (
          SELECT
              ROW_NUM() OVER (PARTITION BY Id ORDER BY record_date, other_cols) as rownum,
              *
          FROM products P
      ) INNER
      WHERE rownum = 2
      

      这还允许您对子查询中的多个列进行排序,如果两个记录日期具有相同的值,这可能会有所帮助。如果需要,您还可以使用逗号分隔多个列

      【讨论】:

        【解决方案6】:

        以下查询获取每个工作订单的第一个日期(在显示所有状态更改的表格中):

        SELECT
            WORKORDERNUM,
            MIN(DATE)
        FROM
            WORKORDERS
        WHERE
            DATE >= to_date('2015-01-01','YYYY-MM-DD')
        GROUP BY
            WORKORDERNUM
        

        【讨论】:

          【解决方案7】:

          我可以通过在 中执行此操作来达到您的预期结果:

           SELECT id, min(record_date), other_cols 
            FROM mytable
            GROUP BY id
          

          这对你有用吗?

          【讨论】:

          • 无论出于何种原因,这似乎在人为的示例(sqlfiddle.com/#!2/f8469/6/0)中有效,但实际上我得到“列'database.table.col_name'在选择列表中无效,因为它不是包含在聚合函数或 GROUP BY 子句中。”无论如何,我都能让它与 asstander 的答案一起工作,谢谢。
          • 是的,我遇到了同样的问题,我想在 SQL Server 上得到一个像这样的简单答案
          【解决方案8】:

          这样做很简单:

          select t2.id,t2.record_date,t2.other_cols 
          from (select ROW_NUMBER() over(partition by id order by record_date)as rownum,id,record_date,other_cols from MyTable)t2 
          where t2.rownum = 1
          

          【讨论】:

            【解决方案9】:

            这是一个老问题,但这对某人有用 在我的情况下,我不能使用子查询,因为我有一个大查询,我需要在我的结果上使用 min(),如果我使用子查询,数据库需要重新执行我的大查询。我正在使用Mysql

            select t.* 
                from (select m.*, @g := 0
                    from MyTable m --here i have a big query
                    order by id, record_date) t
                where (1 = case when @g = 0 or @g <> id then 1 else  0 end )
                      and (@g := id) IS NOT NULL
            

            基本上我对结果进行排序,然后放入一个变量,以便只获取每组中的第一条记录。

            【讨论】:

              【解决方案10】:

              要获得每个类别中最便宜的产品,您可以在相关子查询中使用 MIN() 函数,如下所示:

                  SELECT categoryid,
                     productid,
                     productName,
                     unitprice 
                  FROM products a WHERE unitprice = (
                              SELECT MIN(unitprice)
                              FROM products b
                              WHERE b.categoryid = a.categoryid)
              

              外部查询扫描 products 表中的所有行,并返回单价与相关子查询返回的每个类别中最低价格匹配的产品。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2013-07-22
                • 2021-11-28
                • 1970-01-01
                • 1970-01-01
                • 2021-02-23
                • 1970-01-01
                相关资源
                最近更新 更多