获取与最近出现的重复名称相对应的最早日期

Get Earliest Date corresponding to the latest occurrence of a recurring name

我有一个包含名称和日期列的 table。我想获得当前名称出现的最早日期。例如:

Name Date
X 30-Jan-2021
X 29-Jan-2021
X 28-Jan-2021
Y 27-Jan-2021
Y 26-Jan-2021
Y 25-Jan-2021
Y 24-Jan-2021
X 23-Jan-2021
X 22-Jan-2021

现在,当我尝试获取当前名称 (X) 开始出现的最早日期时,我想要 28-Jan,但 sql 查询会给出 22-Jan-2021,因为那是 X 出现的时间原来是第一次。

更新:这是我使用的查询:

Select min(Date) from myTable where Name='X'

我正在使用较旧的 SQL Server 2008(正在升级),因此无法使用 LEAD/LAG 功能。 下面建议的解决方案确实按预期工作。谢谢

这是一个缺口和孤岛问题。根据示例数据,这将起作用:

WITH Groups AS(
    SELECT YT.[Name],
           YT.[Date],
           ROW_NUMBER() OVER (ORDER BY YT.Date DESC) - 
           ROW_NUMBER() OVER (PARTITION BY YT.[Name] ORDER BY Date DESC) AS Grp
    FROM dbo.YourTable YT),
FirstGroup AS(
    SELECT TOP (1) WITH TIES
           G.[Name],
           G.[Date]
    FROM Groups G
    WHERE [Name] = 'X'
    ORDER BY Grp ASC)
SELECT MIN(FG.[Date]) AS Mi

db<>fiddle

这是一种空岛问题。

有很多解决方案。这是针对您的情况优化的

  • 使用LEAD/LAG确定每个分组中的第一行
  • 仅筛选那些行
  • 给它们编号并取第一行
WITH StartPoints AS (
    SELECT *,
      IsStart = CASE WHEN Name <> LEAD(Name, 1, '') OVER (ORDER BY Date DESC) THEN 1 END
    FROM YourTable
),
Numbered AS (
    SELECT *,
      rn = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date DESC)
    FROM StartPoints
    WHERE IsStart = 1 AND Name = 'X'
)
SELECT
  Name, Date
FROM Numbered
WHERE rn = 1;

db<>fiddle

对于 SQL Server 2008 或更早版本(我 强烈 建议您升级),您可以使用带行编号的自连接来模拟 LEAD/LAG

WITH RowNumbered AS (
    SELECT *,
      AllRn = ROW_NUMBER() OVER (ORDER BY Date ASC)
    FROM YourTable
),
StartPoints AS (
    SELECT r1.*,
      IsStart = CASE WHEN r1.Name <> ISNULL(r2.Name, '') THEN 1 END
    FROM RowNumbered r1
    LEFT JOIN RowNumbered r2 ON r2.AllRn = r1.AllRn - 1
),
Numbered AS (
    SELECT *,
      rn = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date DESC)
    FROM StartPoints
    WHERE IsStart = 1
)
SELECT
  Name, Date
FROM Numbered
WHERE rn = 1;

如果我没听懂,你想知道X什么时候消失又重新出现。在这种情况下,您可以按组搜索日期间隔。

这个和如何检测那个的例子

SELECT name
 ,DATE
FROM (
SELECT *
    ,DATEDIFF(day, lead(DATE) OVER (
            PARTITION BY name ORDER BY DATE DESC
            ), DATE) DIF
FROM YourTable
) a
WHERE DIF > 1