【问题标题】:SQL Server query to get first and last valueSQL Server 查询以获取第一个和最后一个值
【发布时间】:2018-10-20 20:29:57
【问题描述】:

我有一张带有FieldID, ChangeField, OldValue, NewValue and ChangeDate 的表格,如下所示:

FieldID   ChangeField  OldValue   NewValue   ChangeDate
1         interest     1.5        1.2        2018-05-01 13:00:00
1         interest     1.2        1.3        2018-05-01 14:00:00
1         quantity     2          1          2018-05-01 15:00:00
1         quantity     1          2          2018-05-01 16:00:00
1         quantity     2          3          2018-05-01 17:00:00
2         quantity     10         20         2018-05-01 18:00:00
2         quantity     20         30         2018-05-01 19:00:00

是否可以获得每个 FieldID 的每个 ChangeField 的第一个和最后一个更改,例如下面的结果?

FieldID ChangeField     OldValue    NewValue    dtChangeDate
1       interest        1.5         1.3     2018-05-01 14:00:00  
--> The original value for interest was 1.5, the last value for interest is 1.3
1       quantity        2           3       2018-05-01 17:00:00  
--> The original value for quantity was 2, the last value for interest is 3
2       quantity        10          30      2018-05-01 19:00:00  
--> The original value for quantity was 10, the last value for interest is 30

请注意,ChangeDate 始终是最新的 ChangeDate

【问题讨论】:

标签: sql sql-server tsql


【解决方案1】:

使用我的标量聚合比较技术(根据我在此处的回答 Get other columns that correspond with MAX value of one column?),您可以非常简单地在没有 CTE 或分区的单个分组查询中执行此操作。

这是查询:

SELECT FieldID, ChangeField,
    MIN(ChangeDate) AS FirstChangeDate,
    SUBSTRING(MIN(CONCAT(ChangeDate, OldValue)), 20) AS FirstOldValue,
    SUBSTRING(MIN(CONCAT(ChangeDate, NewValue)), 20) AS FirstNewValue,
    MAX(ChangeDate) AS LastChangeDate,
    SUBSTRING(MAX(CONCAT(ChangeDate, OldValue)), 20) AS LastOldValue,
    SUBSTRING(MAX(CONCAT(ChangeDate, NewValue)), 20) AS LastNewValue
FROM MyTable
GROUP BY FieldID, ChangeField;

与上面提供的其他答案相比,性能可能提高了 3-4 倍。

这里有更多关于这种技术的信息:https://www.stevenmoseley.com/high-performance-correlated-aggregate-sql-queries-without-ctes

【讨论】:

    【解决方案2】:

    您可以尝试以下代码,我使用FIRST_VALUE() 获取 OldValue 列中的第一个值,使用 LAST_VALUE() 获取 NewValue 和 dtChangeDate 组的最后一个值。

        SELECT
        FieldID,
        ChangeField,
        FIRST_VALUE(OldValue) OVER (PARTITION BY
                                        fieldID, ChangeField
                                    ORDER BY FieldID
                                   )  AS OldValue,
        LAST_VALUE(NewValue) OVER (PARTITION BY
                                       fieldID, ChangeField
                                   ORDER BY FieldID
                                  )   AS NewValue,
        LAST_VALUE(ChangeDate) OVER (PARTITION BY
                                         fieldID, ChangeField
                                     ORDER BY FieldID
                                    ) AS dtChangeDate
        FROM YourTable;
    

    【讨论】:

    • 谢谢大家。我尝试了 Aureate 的解决方案,它有效!
    【解决方案3】:

    您可以使用ROW_NUMBER() 获取最旧/最新。

    ;WITH Boundaries AS
    (
        SELECT
            T.FieldID,
            T.ChangeField,
            T.OldValue,
            T.NewValue,
            OldestRanking = ROW_NUMBER() OVER (
                PARTITION BY
                    T.FieldID,
                    T.ChangeField
                ORDER BY
                    T.ChangeDate ASC),
            NewestRanking = ROW_NUMBER() OVER (
                PARTITION BY
                    T.FieldID,
                    T.ChangeField
                ORDER BY
                    T.ChangeDate DESC)
        FROM
            YourTable AS T
    )
    SELECT
        T.FieldID,
        T.ChangeField,
        T.OldValue,
        OldValueDate = T.ChangeDate,
        N.NewValue,
        NewValueDate = N.ChangeDate,
    FROM
        Boundaries AS T
        INNER JOIN Boundaries AS N ON 
            T.FieldID = N.FieldID AND
            T.ChangeField  = N.ChangeField
    WHERE
        T.OldestRanking = 1 AND
        N.NewestRanking = 1
    

    【讨论】:

      【解决方案4】:

      您可以尝试如下查询:

      see live demo

      ;with cte as
      ( 
          select
          *,
          rn1= row_number() over (partition by FieldID,ChangeField order by ChangeDate asc),
          rn2= row_number() over (partition by FieldID,ChangeField order by ChangeDate desc)
          from
          Tbl
      )
      
      select 
          FieldId,
          ChangeField,
          ChangeDate=MAX(ChangeDate),
          Oldvalue= MAX(Case when rn1=1 then Oldvalue end),
          NewValue= MAX(Case when rn2=1 then NewValue end)
      from cte 
          where  rn1=1 or rn2=1
      group by 
          FieldId,ChangeField
      

      【讨论】:

        【解决方案5】:

        使用first_value()last_value ()

        select distinct * 
        from (
          select FieldID, ChangeField  
               first_value(OldValue) over (partition by FieldID, ChangeField order by ChangeDate) OldValue,
               last_value(OldValue) over (partition by FieldID, ChangeField order by ChangeDate) NewValue,
               last_value(OldValue) over (partition by FieldID, ChangeField order by ChangeDate) dtChangeDate
          from table t
        ) t;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-29
          • 2019-03-09
          • 1970-01-01
          • 1970-01-01
          • 2018-10-21
          • 2022-08-05
          • 1970-01-01
          • 2014-12-14
          相关资源
          最近更新 更多