簡體   English   中英

SQL對唯一ID的累積計數

[英]SQL Cumulative count on unique Ids

我有如下數據集(按“時間”列排序):

Time        ID1        ID2
2:00:00 AM  41  A56E34E0-FBE5-4C58-BDBD-87112E73A978
3:00:00 AM  34  B129798B-485E-41BB-8B9C-39A0E1841109
4:00:00 AM  41  A56E34E0-FBE5-4C58-BDBD-87112E73A978
4:00:00 AM  41  C1C14D08-C155-4857-93E2-3A748AC95C8D
4:00:00 AM  34  A4D389B1-C38F-446A-9336-6AA193D8F0E0
4:00:00 AM  17  C1C14D08-C155-4857-93E2-3A748AC95C8D

如果要按時間和ID1分組的同一ID1之前沒有出現過,我想獲取ID2的累積計數。 因此,對於上述數據集,中間結果可能是:

Time        ID1        ID2                                     IsNewForID1
2:00:00 AM  41  A56E34E0-FBE5-4C58-BDBD-87112E73A978        1
3:00:00 AM  34  B129798B-485E-41BB-8B9C-39A0E1841109        1
4:00:00 AM  41  A56E34E0-FBE5-4C58-BDBD-87112E73A978        0
4:00:00 AM  41  C1C14D08-C155-4857-93E2-3A748AC95C8D        1
4:00:00 AM  34  A4D389B1-C38F-446A-9336-6AA193D8F0E0        1
4:00:00 AM  17  C1C14D08-C155-4857-93E2-3A748AC95C8D        1

並且按時間分組,ID1將是:

Time        ID1       Count
2:00:00 AM  41  1
3:00:00 AM  34  1
4:00:00 AM  41  1
4:00:00 AM  34  1
4:00:00 AM  17  1

如何在SQL中執行此操作?

如果您想讓id1id2對首次出現,並加上時間,為什么不只使用group by 以下是標准SQL:

select min(time) as time, id1, id2, 1 as count
from dataset
group by id1, id2;

您可以使用Gordon Linoff的建議作為這種解決方案的起點:

SELECT
  d.Time,
  d.ID1,
  d.ID2,
  IsNewForID1 = CASE WHEN g.Time IS NULL THEN 0 ELSE 1 END
FROM
  YourDataset AS d
  LEFT JOIN (
    SELECT
      Time = MIN(Time),
      ID1,
      ID2,
    FROM
      YourDataset
    GROUP BY
      ID1,
      ID2
  ) AS g ON g.Time = d.Time AND g.ID1 = d.ID1 AND g.ID2 = d.ID2
;

也就是說,派生表包含每個ID1ID2第一個“新”出現,然后將其重新連接到原始數據集以用作參考並分別標記每行。

如果使用的是SQL Server 2005或更高版本,則可以使用窗口MIN重寫以上內容:

SELECT
  Time,
  ID1,
  ID2,
  IsNewForID1 = CASE Time
    WHEN MIN(Time) OVER (PARTITION BY ID1, ID2) THEN 1
    ELSE 0
  END
FROM
  YourDataset
;

這個想法與以前相同,但是不需要IsNewForID1表或派生表,因為第一次出現是在細節旁邊獲得的,並且IsNewForID1列是在同一范圍內計算的。 如果YourDataset實際上是一個查詢,則此方法尤其可取,因為第一個變體可能會對YourDataset兩次評估,而第二個變體則避免了。

顯然,要獲得最終結果,您可以采用任一查詢,然后按TimeID1將其進一步分組以采用SUM(IsForNewID1)

SELECT
  Time,
  ID1,
  Count = SUM(IsNewForID1)
FROM
  (
    SELECT
      Time,
      ID1,
      ID2,
      IsNewForID1 = CASE Time
        WHEN MIN(Time) OVER (PARTITION BY ID1, ID2) THEN 1
        ELSE 0
      END
    FROM
      YourDataset
  ) AS s
;

但是請注意,如果實際上僅需要IsNewForID1來獲取計數,則可以以其他方式使用Gordon的想法來跳過該中間步驟,如下所示:

SELECT
  Time,
  ID1,
  Count = COUNT(*)
FROM
  (
    SELECT
      Time = MIN(Time),
      ID1,
      ID2,
    FROM
      YourDataset
    GROUP BY
      ID1,
      ID2
  ) AS s
;

本質上,無論您是使用IsNewForID1還是不使用IsNewForID1計算它們,結果都是相同的。 但是,就行而言,可能有所不同。 前一種方法可能會返回Count = 0行。 例如,如果您的示例中的第4行不存在,它將返回以下內容:

Time        ID1  Count
----------  ---  -----
2:00:00 AM  41   1
3:00:00 AM  34   1
4:00:00 AM  41   0
4:00:00 AM  34   1
4:00:00 AM  17   1

最后一個方法將簡單地忽略計數為0的行,因此4:00:00 AM, 41如果我們從示例數據中刪除第四行,則在4:00:00 AM, 41將沒有結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM