Tom*_*Tom -1 sql-server gaps-and-islands
我有一张表,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
我想知道有多少次连续CAR NAME插入到表中,排序时INSERT DATE,以及 first 和 last 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
Run Code Online (Sandbox Code Playgroud)
我在实现这个时遇到了问题,也许有人可以提供帮助。
这是针对 SQL Server 的。不幸的是,我只有两列可供使用。
小智 8
你的问题没有明确形成,但考虑到你的例子 -菲尔的评论是正确的:
只有当有另一列定义数据的顺序(这是您在问题中呈现数据的顺序)时,您的示例才有意义。
除非您有一个附加的行顺序列 - 您的问题没有解决方案。
为什么?
因为 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
Run Code Online (Sandbox Code Playgroud)
我很高兴弄清楚如何实际查询以获得所需的结果,但在这里(对不起,我没有花太多时间进行格式化):
;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
Run Code Online (Sandbox Code Playgroud)
主要思想是找到范围的第一个和最后一个项目(使用窗口函数LAG和LEAD),然后将第一个项目与最后一个项目ROW_NUMBER()作为键配对。最后但并非最不重要的一点是再次将这些对与原始表连接起来以获得COUNT(*)s。等等:
| 归档时间: |
|
| 查看次数: |
11662 次 |
| 最近记录: |