我有一些数据。我想根据data
列的值对它们进行分组。如果有3个或更多连续行的数据大于10,那么这些行就是我想要的。
所以对于这个数据:
use tempdb;
go
set nocount on;
if object_id('t', 'U') is not null
drop table t;
go
create table t
(
id int primary key identity,
[when] datetime,
data int
)
go
insert into t([when], data) values ('20130801', 1);
insert into t([when], data) values ('20130802', 121);
insert into t([when], data) values ('20130803', 132);
insert into t([when], data) values ('20130804', 15);
insert into t([when], data) values ('20130805', 9);
insert into t([when], data) values ('20130806', 1435);
insert into t([when], data) values ('20130807', 143);
insert into t([when], data) values ('20130808', 18);
insert into t([when], data) values ('20130809', 19);
insert into t([when], data) values ('20130810', 1);
insert into t([when], data) values ('20130811', 1234);
insert into t([when], data) values ('20130812', 124);
insert into t([when], data) values ('20130813', 6);
select * from t;
我想要的是:
id when data
----------- ----------------------- -----------
2 2013-08-02 00:00:00.000 121
3 2013-08-03 00:00:00.000 132
4 2013-08-04 00:00:00.000 15
6 2013-08-06 00:00:00.000 1435
7 2013-08-07 00:00:00.000 143
8 2013-08-08 00:00:00.000 18
9 2013-08-09 00:00:00.000 19
怎么做?
答案 0 :(得分:16)
试试这个
WITH cte
AS
(
SELECT *,COUNT(1) OVER(PARTITION BY cnt) pt FROM
(
SELECT tt.*
,(SELECT COUNT(id) FROM t WHERE data <= 10 AND ID < tt.ID) AS cnt
FROM t tt
WHERE data > 10
) t1
)
SELECT id, [when], data FROM cte WHERE pt >= 3
<强>输出强>
id when data
2 2013-08-02 00:00:00.000 121
3 2013-08-03 00:00:00.000 132
4 2013-08-04 00:00:00.000 15
6 2013-08-06 00:00:00.000 1435
7 2013-08-07 00:00:00.000 143
8 2013-08-08 00:00:00.000 18
9 2013-08-09 00:00:00.000 19
修改强>
首先,内部查询计算数据&lt; = 10
的记录数SELECT tt.*
,(SELECT COUNT(id) FROM t WHERE data <= 10 AND ID < tt.ID) AS cnt
FROM t tt
输出
id when data cnt
1 2013-08-01 00:00:00.000 1 1
2 2013-08-02 00:00:00.000 121 1
3 2013-08-03 00:00:00.000 132 1
4 2013-08-04 00:00:00.000 15 1
5 2013-08-05 00:00:00.000 9 2
6 2013-08-06 00:00:00.000 1435 2
7 2013-08-07 00:00:00.000 143 2
8 2013-08-08 00:00:00.000 18 2
9 2013-08-09 00:00:00.000 19 2
10 2013-08-10 00:00:00.000 1 3
11 2013-08-11 00:00:00.000 1234 3
12 2013-08-12 00:00:00.000 124 3
13 2013-08-13 00:00:00.000 6 4
然后我们使用数据&gt;过滤记录10
WHERE data > 10
现在我们通过分配cnt列
来计算记录SELECT *,COUNT(1) OVER(PARTITION BY cnt) pt FROM
(
SELECT tt.*
,(SELECT COUNT(id) FROM t WHERE data <= 10 AND ID < tt.ID) AS cnt
FROM t tt
WHERE data > 10
) t1
输出
id when data cnt pt
2 2013-08-02 00:00:00.000 121 1 3
3 2013-08-03 00:00:00.000 132 1 3
4 2013-08-04 00:00:00.000 15 1 3
6 2013-08-06 00:00:00.000 1435 2 4
7 2013-08-07 00:00:00.000 143 2 4
8 2013-08-08 00:00:00.000 18 2 4
9 2013-08-09 00:00:00.000 19 2 4
11 2013-08-11 00:00:00.000 1234 3 2
12 2013-08-12 00:00:00.000 124 3 2
上面的查询就像临时表一样放在cte中
现在选择具有连续计数&gt; = 3
的记录SELECT id, [when], data FROM cte WHERE pt >= 3
另一种解决方案
;WITH partitioned AS (
SELECT *, id - ROW_NUMBER() OVER (ORDER BY id) AS grp
FROM t
WHERE data > 10
),
counted AS (
SELECT *, COUNT(*) OVER (PARTITION BY grp) AS cnt
FROM partitioned
)
SELECT id, [when], data
FROM counted
WHERE cnt >= 3
答案 1 :(得分:3)
首先,我们对任何值为10或更小的行进行折扣:
WITH t10 AS (SELECT * FROM t WHERE data > 10),
接下来,获取其前一个行也超过10的行:
okleft AS (SELECT t10.*, pred.id AS predid FROM
t10
INNER JOIN t pred ON
pred.[when] < t10.[when]
AND pred.[when] >= ALL (SELECT [when] FROM t t2 WHERE t2.[when] < t10.[when])
WHERE pred.data > 10
),
同时获取其直接后继也超过10的行:
okright as (SELECT t10.*, succ.id AS succid FROM
t10
INNER JOIN t succ ON
succ.[when] > t10.[when]
AND succ.[when] <= ALL (SELECT [when] FROM t t2 WHERE t2.[when] > t10.[when])
WHERE succ.data > 10
),
最后,选择任何一行开始序列3,在一个中间或结束一行:
有效右侧也有有效右侧的行开始至少为3的序列:
starts3 AS (SELECT id, [when], data FROM okright r1 WHERE EXISTS(
SELECT NULL FROM okright r2 WHERE r2.id = r1.succid)),
其前身和后继者都有效的行至少在3的中间:
mid3 AS (SELECT id, [when], data FROM okleft l WHERE EXISTS(
SELECT NULL FROM okright r WHERE r.id = l.id)),
有效左侧也有有效左侧的行结束至少为3的序列:
ends3 AS (SELECT id, [when], data FROM okleft l1 WHERE EXISTS(
SELECT NULL FROM okleft l2 WHERE l2.id = l1.predid))
加入他们所有人,使用UNION删除重复项:
SELECT * FROM starts3
UNION SELECT * FROM mid3
UNION SELECT * FROM ends3
SQL Fiddler:http://sqlfiddle.com/#!3/12f3a/9
编辑:我喜欢BVR的答案,比我的更优雅。