我有一个具有ID,值和日期的表。该表中有许多ID,值和日期。

记录会定期插入此表中。该ID始终保持不变,但有时值会更改。注意:该值将始终增加。

从此示例数据中:

  Create Table Taco
 (  Taco_ID int,
    Taco_value int,
    Taco_date datetime)

Insert INTO Taco 
Values (1, 1, '2012-07-01 00:00:01'),
        (1, 1, '2012-07-01 00:00:02'),
        (1, 1, '2012-07-01 00:00:03'),
        (1, 1, '2012-07-01 00:00:04'),
        (1, 2, '2012-07-01 00:00:05'),
        (1, 2, '2012-07-01 00:00:06'),
        (1, 2, '2012-07-01 00:00:07'),
        (1, 2, '2012-07-01 00:00:08')


结果应为:

Taco_ID      Taco_date
1            2012-07-01 00:00:05


(因为00:05是Taco_Value的最后一次更改。)

评论

我以为玉米卷与食物无关吗?

我饿了,想吃一些炸玉米饼。只需为样品表命名。

您是否以类似的方式选择了用户名?

很有可能。

#1 楼

这两个查询均基于以下假设:Taco_value总是随着时间增加。 >更新
对于那些跟踪的人,如果可以重复Taco_value,将会发生什么是有争议的。如果对于任何给定的Taco_ID,它可以从1变为2,然后又返回1,则查询将不起作用。对于这种情况,这是一个解决方案,即使它不是Itzik Ben-Gan之类的人可能可以梦想的间隙和孤岛技术,即使它与OP的情况无关-与未来的读者有关。稍微复杂一点,我还添加了一个额外的变量-一个Taco_ID,该变量只能有一个Taco_value。 :
;WITH x AS
(
  SELECT Taco_ID, Taco_date,
    dr = ROW_NUMBER() OVER (PARTITION BY Taco_ID, Taco_Value ORDER BY Taco_date),
    qr = ROW_NUMBER() OVER (PARTITION BY Taco_ID ORDER BY Taco_date)
  FROM dbo.Taco
), y AS
(
  SELECT Taco_ID, Taco_date,
    rn = ROW_NUMBER() OVER (PARTITION BY Taco_ID, dr ORDER BY qr DESC)
  FROM x WHERE dr = 1
)
SELECT Taco_ID, Taco_date
FROM y 
WHERE rn = 1;

如果要排除这些行,则要复杂一些,但仍需进行一些细微的更改:
;WITH x AS
(
  SELECT Taco_ID, Taco_value, Taco_date = MIN(Taco_date)
  FROM dbo.Taco
  GROUP BY Taco_ID, Taco_value
), y AS
(
  SELECT Taco_ID, Taco_date, 
    rn = ROW_NUMBER() OVER (PARTITION BY Taco_ID ORDER BY Taco_date DESC)
  FROM x
)
SELECT Taco_ID, Taco_date FROM y WHERE rn = 1;

更新了SQLfiddle示例

评论


我注意到OVER存在一些重大的性能问题,但仅使用了几次,可能编写得很差。你有没有注意到?

–肯尼斯·费舍尔
2013年6月18日19:21



@KennethFisher不专门用于OVER。像其他任何东西一样,查询构造在很大程度上依赖于基础架构/索引才能正常工作。分区的over子句将遭受与GROUP BY相同的问题。

–亚伦·伯特兰(Aaron Bertrand)
13年6月18日在19:26

@KennethFisher请注意不要从单个,孤立的观察中得出广泛而笼统的结论。我看到了反对CTE的相同论点-“嗯,我曾经有一次递归CTE,它的性能糟透了。因此,我不再使用CTE。”

–亚伦·伯特兰(Aaron Bertrand)
13年6月18日在19:32

这就是为什么我问。我还没有足够用它来表达一种或另一种方式,但是几次使用它我都能通过CTE获得更好的性能。我会继续玩下去。

–肯尼斯·费舍尔
13年6月18日在19:38

@AaronBertrand我不认为如果重新出现值,这些将不会起作用:小提琴

–超立方体ᵀᴹ
13年6月18日在19:44

#2 楼

基本上,这是@Taryn的建议,“压缩”为没有派生表的单个SELECT:

。 (更确切地说,它假设Taco_value无法更改回先前的值-实际上与链接的答案相同。)

用于查询的SQL Fiddle演示:http://sqlfiddle.com/ #!3/91368/2

评论


哇,嵌套MAX / MIN。心灵吹+1

–亚伦·伯特兰(Aaron Bertrand)
2013年6月19日11:16



#3 楼

您应该能够同时使用min()max()聚合函数来获得结果:

select t1.Taco_ID, MAX(t1.taco_date) Taco_Date
from taco t1
inner join
(
    select MIN(taco_date) taco_date,
        Taco_ID, Taco_value
    from Taco
    group by Taco_ID, Taco_value
) t2
    on t1.Taco_ID = t2.Taco_ID
    and t1.Taco_date = t2.taco_date
group by t1.Taco_Id


请参阅带有演示的SQL Fiddle

#4 楼

另一个答案是基于以下假设:这些值不会再次出现(这基本上是@Aaron的查询2,压缩在较少的嵌套中): :SQL-Fiddle


并回答一个更普遍的问题,在该问题中值可能重新出现: CROSS APPLY,因此显示了所有相关行,包括value):

;WITH x AS
(
  SELECT 
    Taco_ID, Taco_value, 
    Rn = ROW_NUMBER() OVER (PARTITION BY Taco_ID
                            ORDER BY MIN(Taco_date) DESC),
    Taco_date = MIN(Taco_date) 
  FROM dbo.Taco
  GROUP BY Taco_ID, Taco_value
)
SELECT Taco_ID, Taco_value, Taco_date
FROM x 
WHERE Rn = 1 ;


在以下位置进行测试:SQL-Fiddle-2

评论


对于更普遍的问题的建议不适用于没有更改的ID。可以通过在原始集中添加虚拟条目来解决(例如dbo.Taco UNION ALL SELECT DISTINCT Taco_ID,NULL AS Taco_value,'19000101'AS Taco_date)。

– Andriy M
13年6月20日在6:54

@AndriyM我知道。我以为“更改”意味着当至少有2个值时他们想要结果,OP并没有澄清这一点(并且因为编写起来更容易:)

–超立方体ᵀᴹ
2013年6月20日6:56



#5 楼

FYI +1,用于提供样本结构和数据。我唯一想要的就是该数据的预期输出。

编辑:这会让我发疯。我只是新手,这是一种“简单”的方法。我摆脱了不正确的解决方案,并提出了一个我认为是正确的解决方案。这是一种类似于@bluefeets的解决方案,但涵盖了@AaronBertrand进行的测试。

;WITH TacoMin AS (SELECT Taco_ID, Taco_value, MIN(Taco_date) InitialValueDate
                FROM Taco
                GROUP BY Taco_ID, Taco_value)
SELECT Taco_ID, MAX(InitialValueDate)
FROM TacoMin
GROUP BY Taco_ID


评论


OP不要求提供更新日期,而是询问值何时更改。

–超立方体ᵀᴹ
13年6月18日在19:22

啊,我明白了我的错误。我得出了一个答案,但这与@Aaron的答案几乎相同,因此发布它毫无意义。

–肯尼斯·费舍尔
13年6月18日在19:48

#6 楼

为什么不仅仅获得滞后值和提前值之差?如果差为零,则它没有变化,它不是零,那么它就改变了。这可以通过简单的查询完成:

-- example gives the times the value changed in the last 24 hrs
SELECT
    LastUpdated, [DiffValue]
FROM (
  SELECT
      LastUpdated,
      a.AboveBurdenProbe1TempC - coalesce(lag(a.AboveBurdenProbe1TempC) over (order by ProcessHistoryId), 0) as [DiffValue]
  FROM BFProcessHistory a
  WHERE LastUpdated > getdate() - 1
) b
WHERE [DiffValue] <> 0
ORDER BY LastUpdated ASC


评论


滞后...仅在SQL Server 2012中“最近”引入了分析功能。最初的问题是在SQL Server 2008 R2上寻求解决方案。您的解决方案不适用于SQL Server 2008 R2。

– John K. N.
18/09/21在9:43

#7 楼

今天有一个类似的问题-在Power BI中,我可以使用Tabler.FillDown解决它。经过一番搜索,我找到了FillDown的SQL变体:

https://www.oraylis.de/blog/fill-down-table-in-t-sql-last-non-empty -value

因此,我花时间使该解决方案适应此示例-添加了额外的一行以显示Taco_value的重用。 >注意:此解决方案考虑到Taco_value可以增加和减少(或更改回先前的值)

Insert INTO Taco 
Values (1, 1, '2012-07-01 00:00:09')


结果:

#8 楼



       SELECT taco_id, MAX(
             CASE 
                 WHEN taco_value <> MAX(taco_value) 
                 THEN taco_date 
                 ELSE null 
             END) AS last_change_date


鉴于taco_value总是增加?

p.s。我本人还是SQL的初学者,但是学习肯定很慢。

评论


在SQL Server上,这会给出错误。无法对包含聚集或子查询的表达式执行聚集功能

–马丁·史密斯
2013年6月19日7:01

在Martin的评论中添加一点:如果您只发布经过测试的代码,那么您会很安全。如果您不在通常的操场上,可以使用一种简单的方法访问sqlfiddle.com。

– dezso
13年6月19日在8:07