確定連續出現的值
我有一個如下所示的表格:
CAR NAME INSERT DATE MERCEDES 2018-01-01 SEAT 2018-01-01 MERCEDES 2018-01-02 BMW 2018-01-02 MERCEDES 2018-01-03 MERCEDES 2018-01-04 MERCEDES 2018-01-05 BMW 2018-01-05 BMW 2018-01-06 SEAT 2018-01-07 BMW 2018-01-08 AUDI 2018-01-08 BMW 2018-01-09 BMW 2018-01-10 NULL 2018-01-12 SEAT 2018-01-12 SEAT 2018-01-14 SEAT 2018-01-16 BMW 2018-01-17 NULL 2018-01-19 MERCEDES 2018-01-21 MERCEDES 2018-01-22 MERCEDES 2018-01-23
我想知道在按順序以及第一個和最後一個
CAR NAME
順序時,相同的連續插入了多少次。出於此查詢的目的,應忽略一個連續的結果。INSERT DATE``INSERT DATE``CAR NAME
例如:
name count first last mercedes 3 2018-01-03 2018-01-05 bmw 2 2018-01-05 2018-01-06 bmw 2 2018-01-09 2018-01-10 seat 3 2018-01-12 2018-01-16 mercedes 3 2018-01-21 2018-01-23
我在執行此操作時遇到問題,也許有人可以提供幫助。
這是針對 SQL Server 的。不幸的是,我只有兩列可供使用。
你的問題沒有明確形成,但考慮到你的例子 -菲爾的評論是正確的:
您的範例僅在有另一列定義數據順序(即您在問題中呈現數據的順序)時才有意義。
除非您有一個具有行順序的附加列 - 您的問題沒有解決方案。
為什麼? 因為 SQL 基於關係理論,在這個概念中數據本身沒有順序。因此,除非您提供具有行順序的附加列(最常見的是帶有遞增數字的 Id 列),否則將無法告知數據的順序,因此 - 您的問題無法得到回答。如果您從數據庫中執行,如果沒有帶有訂單號的列
SELECT
,SQL 官方不保證您每次都會以相同的順序接收行(在許多情況下您不會)。解決方案 添加另一列,例如 Id 作為整數,並讓每一行都有一個遞增值,如下所示:
Id NAME DATE 1 MERCEDES 2018-01-01 2 SEAT 2018-02-01 3 MERCEDES 2018-04-01 4 BMW 2018-01-01 5 MERCEDES 2018-01-01 6 MERCEDES 2018-01-05 7 MERCEDES 2018-01-09
我很高興弄清楚如何實際查詢以獲得所需的結果,但就是這樣(對不起,我沒有花太多時間進行格式化):
;WITH First (id, car, d, is_first, rn) AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY id) rn FROM ( SELECT id ,car ,d ,CASE WHEN ((LEAD(car,1) OVER (ORDER BY id) = car) AND (LAG(car,1) OVER (ORDER BY id) <> car OR LAG(car,1) OVER (ORDER BY id) IS NULL)) THEN 1 ELSE 0 END is_first FROM dbo.cars ) t WHERE t.is_first = 1 ), Last (id, car, d, is_last, rn) AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY id) rn FROM ( SELECT id ,car ,d , CASE WHEN (LEAD(car,1) OVER (ORDER BY id) <> car OR LEAD(car,1) OVER (ORDER BY id) IS NULL) AND (LAG(car,1) OVER (ORDER BY id) = car ) THEN 1 ELSE 0 END is_last FROM dbo.cars ) t WHERE t.is_last = 1 ) SELECT c.car, COUNT(*) cnt, f.d min_date, l.d max_date FROM First f LEFT JOIN Last l ON f.rn = l.rn LEFT JOIN cars c ON c.car = f.car AND c.id BETWEEN f.id AND l.id GROUP BY c.car, f.d, l.d, f.rn ORDER BY f.rn
主要思想是找到範圍的第一項和最後一項(使用視窗函式
LAG
和LEAD
),然後將第一項與最後一項ROW_NUMBER()
作為鍵配對。最後但並非最不重要的一點是將這些對與原始表再次連接以獲得COUNT(*)
s。瞧:
舊執行緒,但這仍然是一個有趣的問題。
正如Błażej提到的,我們需要一個可以排序的列,沒有關係。否則,查詢將不知道哪個記錄先出現,並且會以某種不可預測的方式將事物計為一個組。
假設我們有這個列(讓我們命名它
seq
),下面的查詢也可以工作:WITH grouped_cars AS ( SELECT name, date, ( name, -- There is a subtraction below, -- don't be fooled by the formatting DENSE_RANK() OVER (ORDER BY seq) - DENSE_RANK() OVER (PARTITION BY name ORDER BY seq) ) AS car_group FROM cars ) SELECT MIN(name), -- Could be 'ARBITRARY(name)' in Presto COUNT(1) AS count, MIN(date) AS first, MAX(date) AS last FROM grouped_cars GROUP BY car_group HAVING COUNT(1) > 1 ORDER BY MIN(date)
這是帶有查詢的 SQLFiddle 的連結:http ://sqlfiddle.com/#!17/10304/5
這個問題真的很好地解釋了這個技巧:用row_number()和dense_rank()解決“差距和島嶼”?
這個怎麼運作?
訣竅是,如果你減去兩個執行序列,你會得到所有元素的相同數字
8, 9, 10
-1, 2, 3
=7, 7, 7
。但是如果第二個序列亂序8, 9, 10, 11, 12
-1, 2, 3, 1, 2
= ,結果會有所不同7, 7, 7, 10, 10
。因此,
dense_rank()
一切的第一個為您提供了第一個執行序列。dense_rank()
在汽車名稱上劃分的第二個為您提供了第二個。當其中的數字是連續的時,我們會得到相同的結果,但每次它因為另一個分區交錯而“中斷”時,數字都會改變。最後,你把車名和數字放在一起,這給了你一些沒有真正意義的東西,但這對於序列上的所有項目都是相等的,沒有間隙。
鑑於此,只需按它分組即可:)