TSQL 不常见的查询聚合

TSQL Uncommon query aggregation

我会尽量简短地介绍我的问题。 我有一个 table,其中包含包含每天和类型值的行。我需要 select 更改所有值的类型。我会尝试通过 2 个查询来展示它。

全套看起来像这样:

SELECT * 
FROM (
  SELECT CONVERT(datetime, '2015-01-01', 120) Date, 0 Type,  0 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-01', 120) Date, 1 Type,  3 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-02', 120) Date, 0 Type,  0 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-02', 120) Date, 1 Type,  3 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-03', 120) Date, 0 Type,  0 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-03', 120) Date, 1 Type,  3 Val1,  7 Val2
  UNION SELECT CONVERT(datetime, '2015-01-04', 120) Date, 0 Type,  1 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-04', 120) Date, 1 Type,  4 Val1,  7 Val2
  UNION SELECT CONVERT(datetime, '2015-01-05', 120) Date, 0 Type,  1 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-05', 120) Date, 1 Type,  5 Val1,  7 Val2
  UNION SELECT CONVERT(datetime, '2015-01-06', 120) Date, 1 Type,  3 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-06', 120) Date, 0 Type,  0 Val1,  5 Val2
) X
ORDER BY 1, 2

现在的想法是这样的,我需要找到 val1 和 val2 发生变化时的所有第一个日期。 val1 和 val2 可以具有与之前某个时间相同的值,因此它是此类型的先前状态的变化。我希望输出是这样的:

SELECT * 
FROM (
  SELECT CONVERT(datetime, '2015-01-01', 120) Date, 0 Type,  0 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-01', 120) Date, 1 Type,  3 Val1,  5 Val2
  --UNION SELECT CONVERT(datetime, '2015-01-02', 120) Date, 0 Type,  0 Val1,  5 Val2
  --UNION SELECT CONVERT(datetime, '2015-01-02', 120) Date, 1 Type,  3 Val1,  5 Val2
  --UNION SELECT CONVERT(datetime, '2015-01-03', 120) Date, 0 Type,  0 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-03', 120) Date, 1 Type,  3 Val1,  7 Val2
  UNION SELECT CONVERT(datetime, '2015-01-04', 120) Date, 0 Type,  1 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-04', 120) Date, 1 Type,  4 Val1,  7 Val2
  --UNION SELECT CONVERT(datetime, '2015-01-05', 120) Date, 0 Type,  1 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-05', 120) Date, 1 Type,  5 Val1,  7 Val2
  UNION SELECT CONVERT(datetime, '2015-01-06', 120) Date, 1 Type,  3 Val1,  5 Val2
  UNION SELECT CONVERT(datetime, '2015-01-06', 120) Date, 0 Type,  0 Val1,  5 Val2
) X
ORDER BY 1, 2

有什么方法可以在不显着降低性能的情况下使其以这种方式运行?

欢迎您更改结果的排序顺序,但我发现按 Type 分组时更容易理解。

declare @Samples as Table ( EventDate Date, EventType Int, Val1 Int, Val2 Int );
insert into @Samples ( EventDate, EventType, Val1, Val2 ) values
  ( '2015-01-01', 0, 0, 5 ),
  ( '2015-01-01', 1, 3, 5 ),
  ( '2015-01-02', 0, 0, 5 ),
  ( '2015-01-02', 1, 3, 5 ),
  ( '2015-01-03', 0, 0, 5 ),
  ( '2015-01-03', 1, 3, 7 ),
  ( '2015-01-04', 0, 1, 5 ),
  ( '2015-01-04', 1, 4, 7 ),
  ( '2015-01-05', 0, 1, 5 ),
  ( '2015-01-05', 1, 5, 7 ),
  ( '2015-01-06', 1, 3, 5 ),
  ( '2015-01-06', 0, 0, 5 );
select * from @Samples;

with NumberedSamples ( EventOccurrence, EventDate, EventType, Val1, Val2 ) as
  ( select Row_Number() over ( partition by EventType order by EventDate ) as EventOccurrence,
    EventDate, EventType, Val1, Val2
    from @Samples ),
  StateChanges ( EventOccurrence, EventDate, EventType, Val1, Val2, Skip ) as
  ( -- Start with the initial Val1/Val2 pair for each Date/Type combination.
  select EventOccurrence, EventDate, EventType, Val1, Val2, 0
    from NumberedSamples
    where EventOccurrence = 1
  union all
  -- Add each subsequent occurrence for each event and determine whether the values changed.
  select NS.EventOccurrence, NS.EventDate, NS.EventType, NS.Val1, NS.Val2,
    case when NS.Val1 = SC.Val1 and NS.Val2 = SC.Val2 then 1 else 0 end
    from StateChanges as SC inner join
      NumberedSamples as NS on NS.EventType = SC.EventType and
      NS.EventOccurrence = SC.EventOccurrence + 1 )
  select *
    from StateChanges
    where Skip = 0
    order by EventType, EventDate;