【问题标题】:Query that uses min aggregate function on multiple columns with priority在具有优先级的多个列上使用 min 聚合函数的查询
【发布时间】:2016-09-30 21:53:20
【问题描述】:

我在互联网上四处寻找解决此问题的方法,但似乎找不到我正在寻找的确切内容。

假设我们有一个如下所示的表:

_____________________________________________________
| id (PK) | name  |  date      | ... other data ... |
-----------------------------------------------------
|    1    |  BOB  | 2016-11-20 |      ....
--------------------------------     
|    3    |  CARL | 2015-09-02 |      ....
--------------------------------
|    4    |  BOB  | 2016-11-18 |      ....
--------------------------------
|    5    |  JON  | 2016-03-03 |      ....
--------------------------------
|    6    |  TIM  | 2016-11-24 |      ....
--------------------------------
|    7    |  TIM  | 2016-11-24 |      ....
--------------------------------
|    8    |  JON  | 2016-05-05 |      ....
--------------------------------

我需要一个查询:
1.返回一个不同的名字列表(distinct function)
2.对于每个名字都有最早的日期(min函数)
3. 上面两列的id。
4.如果日期相同,则使用 min(id) 来决定选择哪一行

所以在这种情况下所需的结果看起来像这样......

_____________________________________________________ 
| id (PK) | name  |    date    | ... other data ... |
-----------------------------------------------------
|    3    |  CARL | 2015-09-02 |      ....
--------------------------------
|    4    |  BOB  | 2016-11-18 |      ....
--------------------------------
|    5    |  JON  | 2016-03-03 |      ....
--------------------------------
|    6    |  TIM  | 2016-11-24 |      ....
--------------------------------

有没有一种方法可以在查询中有效地执行此操作,而无需创建临时表并使用脚本对其进行循环?

这让我成功了一半:
SELECT distinct(name), min(date), ... other data ... from table1


当我将 min 函数应用于 id 时,尽管它的行为并不符合我的需要。在 BOB 的情况下,它将两行混合并返回 1 表示“id”和“2016-11-18”表示日期 - 这是完全不正确的

非常感谢任何帮助。

【问题讨论】:

    标签: sql-server aggregate-functions


    【解决方案1】:

    SQL Server 2005 及更高版本支持窗口函数,并且 row_number 非常有用。这或非常相似的东西应该可以工作。

    SELECT
       name
      ,date
      ,id
     from (--  Can't reference the windowing function within it's own select,
           --  so we make it a subquery
           select
              name
             ,date
             ,id
             ,row_number() over (partition by name order by date, id) Ranking
            from Table1
          ) sub
     where Ranking = 1
     order by name
    

    【讨论】:

      【解决方案2】:
      ;WITH cte AS (
          SELECT *
             ,ROW_NUMBER() OVER (PARTITION BY name ORDER BY Date, Id) as RowNum
          FROM
             @Table
      )
      
      SELECT *
      FROM
          cte
      WHERE
          RowNum = 1
      

      因此,如果您认为它略有不同。您需要每个名称的最早日期行。因此,如果您在按日期升序排序的名称上创建partitioned ROW_NUMBER(),然后选择ROW_NUMBER() = 1 的位置,您将得到答案。也有一些方法可以通过聚合来做到这一点。如果您想要第一个 id,如果 Date 与 Tim 的情况相同,您也可以按顺序添加 id。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多