【问题标题】:SQL SELECT MAX() is returning multiple recordsSQL SELECT MAX() 返回多条记录
【发布时间】:2017-06-02 16:21:38
【问题描述】:

我正在尝试编写一个 SQL 查询,以带回具有 MAX ID2 和 MAX DATETIME 的记录

在我目前的结果中,

存在具有相同 nmae 和 special_number 的记录。它们仅在 ID2 和 Date_Time 上有所不同。 special_number 应该是唯一的并且没有重复。如果有重复的special_number,则选择ID2和date_time最大的记录

对于重复项(有很多),我只需要选择具有 MAx ID2 和 DATE_TIME 的记录。 比如ADDEN CROSS,我只需要带回ID2 = 333和2017-05-05的ADDEN CROSS即可。

我试过 MAX 但没用

SELECT DISTINCT ID, NAME, MAX(ID2), SPECIAL_NUMBER and DATE_TIME
FROm TABLE1
WHERE DATE_TIME BETWEEN @START_DATE and @END_DATE
GROUP BY ID, ID2, SPECIAL_NUMBER, DATE_TIME

感谢任何帮助。谢谢

我目前的结果

ID      NAME        ID2     SPECIAL_NUMBER  DATE_TIME   
123     JOE SMITH   456     D123            2017-06-05
123     JOE SMITH   455     D123            2017-06-04
124     JIM DONE    111     E111            2017-06-02
122     ME TOO      222     G111            2017-06-01
146     ADDEN CROSS 333     R555            2017-05-05
146     ADDEN CROSS 332     R555            2017-05-04
146     ADDEN CROSS 331     R555            2017-05-02

我的预期结果

ID      NAME        ID2     SPECIAL_NUMBER  DATE_TIME   
123     JOE SMITH   456     D123            2017-06-05
124     JIM DONE    111     E111            2017-06-02
122     ME TOO      222     G111            2017-06-01
146     ADDEN CROSS 333     R555            2017-05-05

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    你可以使用 top n 与下面的关系

    Select top (1) with ties * from yourtable
        order by row_number() over(partition by name order by Id2 desc)
    

    【讨论】:

    • 从来没想过用WITH TIES代替子查询,这样更优雅!
    • 但是这样的子查询性能更好,因为 top 1 with ties 包括一个排序运算符...检查我在这个问题中的答案:stackoverflow.com/questions/44310873/…
    • 是的,我自己在相对简单的表上比较了执行计划。子查询似乎更丑更有效。
    【解决方案2】:

    嗯,你的结果是独一无二的,我怀疑你想根据日期获得最新的 ID2。

    在这种情况下,您可以使用ROW_NUMBER()

    SELECT *
    FROM (  SELECT ROW_NUMBER() OVER (PARTITION BY ID, NAME, SPECIAL_NUMBER, DATE_TIME ORDER BY ID2 DESC) AS RN
              , ID
              , NAME
              , ID2
              , SPECIAL_NUMBER
              , DATE_TIME
            FROM TABLE1
            WHERE DATE_TIME BETWEEN @START_DATE and @END_DATE) AS T
    WHERE T.RN = 1;
    

    【讨论】:

      【解决方案3】:

      您获得多条记录的原因是GROUP BY 子句。

      考虑顶部的两行:

      ID      NAME        ID2     SPECIAL_NUMBER  DATE_TIME   
      123     JOE SMITH   456     D123            2017-06-05
      123     JOE SMITH   455     D123            2017-06-04
      

      由于IDID2SPECIAL_NUMBERDATE_TIME都是GROUP BY中的列,因此SQL无法将这两条记录合并为符合您期望的一条:

      ID      NAME        ID2     SPECIAL_NUMBER  DATE_TIME   
      123     JOE SMITH   456     D123            2017-06-05
      

      ID2 的值可以是 455 或 456; SQL 无法选择其中一个。同样,DATE_TIME 可以是2017-06-052017-06-04,如果没有您明确指示选择MAX,DB 无法决定应该选择哪一个。

      我试过MAX,但没用

      你已经很接近了——删除DISTINCT,并从列表中删除ID2DATE_TIME

      SELECT ID, NAME, MAX(ID2), SPECIAL_NUMBER, MAX(DATE_TIME)
      FROM TABLE1
      WHERE DATE_TIME BETWEEN @START_DATE and @END_DATE
      GROUP BY ID, SPECIAL_NUMBER
      

      【讨论】:

      • 如果ID2 不是最新DATE_TIME 最高的记录,这可能会给出不正确的数据,也许它在他的数据中,但有机会。 :)
      • @EvaldasBuinauskas OP 的声明“我只需要选择具有 MAX ID2DATE_TIME 的记录”意味着两者在同一记录上变为 MAX。否则,选择将是模棱两可的。
      【解决方案4】:

      WITH e AS ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY ID, Name, SPECIAL_NUMBER ORDER BY ID2 DESC ) AS R FROM TABLE1 ) SELECT ID, NAME, ID2, SPECIAL_NUMBER, DATE_TIME FROM e WHERE DATE_TIME BETWEEN @START_DATE and @END_DATE

      【讨论】:

        猜你喜欢
        • 2017-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-19
        • 1970-01-01
        • 1970-01-01
        • 2017-03-19
        相关资源
        最近更新 更多