【Transact-SQL】统计某字段中的值第一次出现后的2小时内出现的次数
原文:【Transact-SQL】统计某字段中的值第一次出现后的2小时内出现的次数
table1
name createdate
a 2011-03-01 10:00:00
a 2011-03-01 11:00:00
a 2011-03-01 14:00:00
b 2011-03-01 13:00:00
b 2011-03-01 13:20:00
b 2011-03-01 14:00:00 查询结果为
name createdate count
a 2011-03-01 10:00:00 2
a 2011-03-01 14:00:00 1
b 2011-03-01 13:00:00 3 就相当于是统计name字段中的值在第一次出现后的2小时内,总共出现了几次?
这个是网上的解答:
-
declare @table1 table(name nvarchar,createdate smalldatetime)
-
-
insert into @table1
-
select 'a','2011-03-01 10:00:00'
-
union all select 'a','2011-03-01 11:00:00'
-
union all select 'a','2011-03-01 14:00:00'
-
union all select 'b','2011-03-01 13:00:00'
-
union all select 'b','2011-03-01 13:20:00'
-
union all select 'b','2011-03-01 14:00:00'
-
-
select name,
-
createdate,
-
(select count(createdate)
-
from @table1 b
-
where a.name=b.name and
-
a.createdate<=b.createdate and
-
dateadd(hh,2,a.createdate) >= b.createdate
-
) as count
-
-
from @table1 a
-
where not exists
-
(select 1 from
-
@table1 b
-
where a.name=b.name and
-
a.createdate>b.createdate and
-
a.createdate<dateadd(hh,2,b.createdate))
-
group by name,createdate
但是这个解答其实是有问题的,当把临时表中的第3条数据的createdate改为'2011-03-01 12:00:00',那么显示的结果是:
name createdate count
a 2011-03-01 10:00:00 3
b 2011-03-01 13:00:00 3
在其中没有包括createdate为'2011-03-01 12:00:00'的记录,因为这个时间到为'2011-03-01 10:00:00'是超过2个小时了,也就是说为'2011-03-01 10:00:00'是第一个出现时间,到为'2011-03-01 11:59:59'为止,接下来应该是从'2011-03-01 12:00:00'开始的下个区间了,而这里显然是有问题的。
以下是我写的解法,虽然效率不是太高,但是能解决这个问题:
-
declare @table1 table(name nvarchar,createdate smalldatetime)
-
-
insert into @table1
-
select 'a','2011-03-01 10:00:00'
-
union all select 'a','2011-03-01 11:00:00'
-
union all select 'a','2011-03-01 12:00:00'
-
union all select 'b','2011-03-01 13:10:00'
-
union all select 'b','2011-03-01 13:20:00'
-
union all select 'b','2011-03-01 14:30:00'
-
union all select 'b','2011-03-01 15:15:00'
-
union all select 'b','2011-03-01 16:00:00'
-
union all select 'b','2011-03-01 17:00:00'
-
-
-
-
;with aa --按照name分区,同时按照createdate排序编号
-
as
-
(
-
select name,
-
createdate,
-
ROW_NUMBER() over(partition by name
-
order by createdate) as k1
-
from @table1
-
),
-
-
r
-
as
-
(
-
select v.name,
-
starts=v.k1, --区间开始的编号
-
-
ends=isnull(
-
min(case when v.k1<a.k1
-
and DATEADD(hour,2,v.createdate) <= a.createdate
-
then a.k1
-
else null
-
end)-1,
-
-
max(case when v.k1<a.k1
-
then a.k1
-
else v.k1
-
end)
-
), --区间结尾的编号
-
-
isnull(
-
min(case when v.k1<a.k1
-
and DATEADD(hour,2,v.createdate) <= a.createdate
-
then a.k1
-
else null
-
end)-1,
-
-
max(case when v.k1<a.k1
-
then a.k1
-
else v.k1
-
end)
-
) - v.k1 as diff --区间结尾编号与区间开始编号之间的差值
-
-
from aa v
-
inner join aa a
-
on v.name = a.name --只关联name相等的
-
group by v.name,
-
v.k1
-
having isnull(
-
min(case when v.k1<a.k1
-
and DATEADD(hour,2,v.createdate) <= a.createdate
-
then a.k1
-
else null
-
end)-1,
-
-
max(case when v.k1<a.k1
-
then a.k1
-
else v.k1
-
end)
-
) >=v.k1
-
and
-
isnull(
-
max(case when v.k1>a.k1 and
-
DATEADD(hour,-2,v.createdate) >= a.createdate
-
then v.k1 - 1
-
else null
-
end) + 1,
-
-
min(case when v.k1>a.k1
-
then a.k1
-
else v.k1
-
end)
-
) = v.k1
-
)
-
-
--select * from r
-
-
-
select aa.name,
-
aa.createdate,
-
diff + 1
-
from r
-
inner join aa
-
on aa.name = r.name
-
and aa.k1 =r.starts
-
where not exists
-
(select 1
-
from r rr
-
where rr.name = r.name and
-
rr.starts <> r.starts and
-
rr.starts < r.starts and
-
(rr.ends = r.ends or
-
rr.ends = r.starts)
-
)
不过发现我的这个解法也是有问题的,最大的问题在与不能准确的确定上限在那里,还得继续考虑问题的解法。
下面这个也是有问题的:
-
declare @table1 table(name nvarchar,createdate smalldatetime)
-
-
insert into @table1
-
select 'a','2011-03-01 10:00:00'
-
union all select 'a','2011-03-01 11:00:00'
-
union all select 'a','2011-03-01 12:00:00'
-
-
--union all select 'b','2011-03-01 13:10:00'
-
--union all select 'b','2011-03-01 13:20:00'
-
--union all select 'b','2011-03-01 14:30:00'
-
--union all select 'b','2011-03-01 15:15:00'
-
--union all select 'b','2011-03-01 16:00:00'
-
--union all select 'b','2011-03-01 17:15:00'
-
-
-
-
;with a --按照name分区,同时按照createdate排序编号
-
as
-
(
-
select name,
-
createdate,
-
ROW_NUMBER() over(partition by name
-
order by createdate) as k1
-
from @table1
-
),
-
-
c
-
as
-
(
-
select a1.name,
-
a1.createdate,
-
a1.k1,
-
MIN(a2.createdate) as nextCreatedate,
-
MIN(a2.k1) as nextK1
-
from a a1
-
inner join a a2
-
on a1.name = a2.name
-
and a2.createdate < DATEADD(hour,2,a1.createdate)
-
and a2.createdate >= a1.createdate
-
and a1.k1 <= a2.k1
-
group by a1.name,
-
a1.createdate,
-
a1.k1
-
),
-
-
w
-
as
-
(
-
select name,
-
createdate,
-
k1
-
-
--null,
-
--null,
-
--null
-
from a
-
where k1 = 1
-
-
union all
-
-
select c.name,
-
c.nextCreatedate,
-
c.nextK1
-
-
from W
-
inner join a
-
on a.name = w.name
-
and dateadd(hour,2,w.createdate) <= a.createdate
-
and w.k1 <= a.k1
-
and w.createdate <> '2011-03-01 12:00:00'
-
inner join c
-
on w.name = c.name
-
and w.createdate = c.createdate
-
and w.k1 = c.k1
-
where w.k1 <=3
-
)
-
-
SELECT *
-
FROM w
下面的解法是正确的,不过用的是T-SQL,不是纯sql了:
-
declare @table1 table(name nvarchar(100),createdate smalldatetime)
-
-
declare @table2 table(name nvarchar(100),createdate smalldatetime,rnum bigint)
-
-
declare @temp table(name nvarchar(100),createdate smalldatetime,rnum bigint)
-
-
declare @i int = 1;
-
-
insert into @table1
-
select 'a','2011-03-01 10:00:00'
-
union all select 'a','2011-03-01 11:00:00'
-
union all select 'a','2011-03-01 12:00:00'
-
-
union all select 'b','2011-03-01 13:10:00'
-
union all select 'b','2011-03-01 13:20:00'
-
union all select 'b','2011-03-01 14:30:00'
-
union all select 'b','2011-03-01 15:15:00'
-
union all select 'b','2011-03-01 16:00:00'
-
union all select 'b','2011-03-01 17:16:00'
-
union all select 'b','2011-03-01 17:15:00'
-
-
-
;with a --按照name分区,同时按照createdate排序编号
-
as
-
(
-
select name,
-
createdate,
-
ROW_NUMBER() over(partition by name
-
order by createdate) as k1
-
from @table1
-
)
-
-
insert into @table2
-
select * from a
-
-
insert into @temp
-
select name,
-
createdate,
-
rnum
-
from @table2
-
where rnum = 1
-
-
--select * from @temp
-
-
-
while @i <= (select MAX(rnum) from @table2)
-
begin
-
insert into @temp
-
-
select t2.name,
-
min(t2.createdate),
-
@i +1
-
from @temp t1
-
inner join @table2 t2
-
on t1.name = t2.name
-
and t2.createdate >= dateadd(hour,2,t1.createdate)
-
where t1.rnum = @i
-
group by t2.name
-
-
set @i = @i + 1
-
end
-
-
;with r
-
as
-
(
-
select name,
-
createdate
-
from @temp
-
group by name,
-
createdate
-
)
-
-
select r.name,
-
r.createdate,
-
COUNT(1)
-
from r
-
inner join @table1 t
-
on t.name = r.name
-
and t.createdate >= r.createdate
-
and t.createdate <DATEADD(HOUR,2,r.createdate)
-
group by r.name,
-
r.createdate
其实这个问题是个递归问题,由上一个找到下一个,但是得构造一下:
-
declare @table1 table(name nvarchar,createdate smalldatetime)
-
-
insert into @table1
-
select 'a','2011-03-01 10:00:00'
-
union all select 'a','2011-03-01 11:00:00'
-
union all select 'a','2011-03-01 12:00:00'
-
union all select 'a','2011-03-01 12:20:00'
-
-
union all select 'b','2011-03-01 13:10:00'
-
union all select 'b','2011-03-01 13:20:00'
-
union all select 'b','2011-03-01 14:30:00'
-
union all select 'b','2011-03-01 15:15:00'
-
union all select 'b','2011-03-01 16:00:00'
-
union all select 'b','2011-03-01 17:20:00'
-
union all select 'b','2011-03-01 17:15:00'
-
union all select 'b','2011-03-01 19:16:00'
-
union all select 'b','2011-03-01 17:15:00'
-
-
-
;with a --按照name分区,同时按照createdate排序编号
-
as
-
(
-
select name,
-
createdate,
-
ROW_NUMBER() over(partition by name
-
order by createdate) as k1
-
from @table1
-
),
-
-
c --对于每个时间,找到大于这个时间2小时的时间中最小那个时间
-
as
-
(
-
select a1.name,
-
a1.createdate,
-
a1.k1,
-
MIN(a2.createdate) as nextCreatedate,
-
MIN(a2.k1) as nextK1
-
from a a1
-
inner join a a2
-
on a1.name = a2.name
-
and a2.createdate >= DATEADD(hour,2,a1.createdate)
-
-
group by a1.name,
-
a1.createdate,
-
a1.k1
-
-
union all
-
-
select a.name,null,null,a.createdate,1 --构造递归运行时需要的层级
-
from a
-
where k1 = 1
-
),
-
-
w --递归查询
-
as
-
(
-
select c.name,
-
c.createdate,
-
c.k1,
-
c.nextCreatedate,
-
c.nextK1,
-
1 as lev
-
from c
-
where createdate is null
-
and k1 is null
-
-
union all
-
-
select c.name,
-
c.createdate,
-
c.k1,
-
c.nextCreatedate,
-
c.nextK1,
-
lev + 1
-
from W
-
inner join c
-
on w.name = c.name
-
and w.nextCreatedate = c.createdate
-
-
)
-
-
SELECT distinct name,
-
nextCreatedate,
-
nextK1
-
FROM w
【Transact-SQL】统计某字段中的值第一次出现后的2小时内出现的次数的更多相关文章
- 利用Entity Framework修改指定字段中的值
利用Entity Framework修改指定字段中的值一般我们编辑某些模型的时候会用到类似这样的代码: [HttpPost] public ActionResult Edit(Article mode ...
- sql语句把字段中的某个字符去掉
sql语句把字段中的某个字符去掉 )),'http://demo.m-school.net','') 例如: )),'http://192.168.2.180','') )),'http://zpzx ...
- SQL Server为字段添加默认值
SQL Server为字段添加默认值 if not exists ( select * from sys.columns as c join sys.objects as o on c.default ...
- sql查询某字段的相同值
sql查询某字段的相同值: SELECT * FROM table WHERE col in (SELECT col FROM table GROUP BY col HAVING COUNT (col ...
- sql替换数据库字段中的字符
UPDATE `table_name` SET `field_name` = replace (`field_name`,'from_str','to_str') WHERE ……说明:table_n ...
- 统计numpy数组中每个值出现的个数
统计numpy数组中某一个值或某几个值出现的个数:sum(data==4) # 统计出现了几个cluster include0Cluster = sum(res == 0) include1Clust ...
- SQL(replace)替换字段中指定的字符
语法:update 表名 set 字段名=REPLACE(字段名,'修改前的字符','修改后的字符') 例 Product商品表中Name 名字字段中描述中将'AAA' 修改成 'BBB' SQL语句 ...
- sql修改一个字段多个值
UPDATE 表名 SET 修改的字段=REPLACE(修改的字段,'修改的值','新值');
- SQL Server提取字段中的所有数字
今天公司项目中遇到了一个需求,要求提取用户电话号码字段中的所有电话信息. 由于该字段在项目最初设计中没有严格控制数据质量,导致用户在输入时包含了很多非电话的信息,如用户名字等(136 **** *** ...
随机推荐
- 23Flutter FloatingActionButton实现类似闲鱼App底部导航凸起按钮:
/* 一.Flutter FloatingActionButton介绍 FloatingActionButton简称FAB,可以实现浮动按钮,也可以实现类型闲鱼app的底部凸起导航. child:子视 ...
- 25 Flutter仿京东商城项目 购物车页面布局
加群452892873 下载对应25课文件,运行方法,建好项目,直接替换lib目录,在往pubspec.yaml添加上一下扩展. cupertino_icons: ^0.1.2 flutter_swi ...
- 不同操作系统上DNS客户端操作区别汇总
结论:windows有DNS缓存,Linux默认无DNS缓存,只能依赖于安装其他软件. 一.不同操作系统的客户端的DNS缓存差别 1.windows 系统中dns 解析器会使用系统的dns缓存来提高d ...
- trylock方法
synchronized 是不占用到手不罢休的,会一直试图占用下去. 与 synchronized 的钻牛角尖不一样,Lock接口还提供了一个trylock方法.trylock会在指定时间范围内试图占 ...
- PAT 甲级 1035 Password (20 分)(简单题)
1035 Password (20 分) To prepare for PAT, the judge sometimes has to generate random passwords for ...
- VL10B 采购订单转DN
传入采购订单项目建交货单 FUNCTION zmmfmXXXX. *"------------------------------------------------------------ ...
- jQuery学习四——效果
1.显示,隐藏: <!DOCTYPE html> <html> <head> <title>jquery事件</title> </he ...
- [CareerCup] Guards in a museum 博物馆的警卫
A museum was represented by a square matrix that was filled with O, G, and W where O represented ope ...
- 基于Visual Studio Code搭建Vue开发环境
安装node.js最新版 这里安装的是8.11.4版 image.png 更新npm至最新版 安装node.js后, npm默认版本为: 6.1.0 image.png 使用npm insta ...
- 实现一个Promise
实现一个Promise promise特点 一个promise的当前状态只能是pending.fulfilled和rejected三种之一.状态改变只能是pending到fulfilled或者pend ...