【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 **** *** ...
随机推荐
- Nginx配置信息损毁又无备份时如何恢复
worker_processes *; 本文介绍在Nginx配置信息出现问题后,在没有备份的情况下,如何利用Nginx进程的虚拟内存恢复配置信息. 问题背景 假设 /etc/nginx/site-av ...
- OpenJudge计算概论-买房子
/*================================================================= 买房子 总时间限制: 1000ms 内存限制: 65536kB ...
- SIT测试 和 UAT测试
在企业级软件的测试过程中,经常会划分为三个阶段——单元测试,SIT和UAT,如果开发人员足够,通常还会在SIT之前引入代码审查机制(Code Review)来保证软件符合客户需求且流程正确.下面简单介 ...
- 在 kubernetes 集群中部署一套 web 网站(网页内容不限)
环境准备 一台部署节点,一台master节点,还有两台节点node1,node2 完好的k8s集群环境 思路一: 在node1和node2节点上通过宿主机与容器之间目录映射和端口映射上线静态网站(或动 ...
- ABAP字符串操作1 检查字段小数位的长度
目的: 标准值1-6检查----最多保留小数点后3位 ,如果超出3位,显示错误信息”请检查父件XXX工序XXX的标准值X 的数值XXXX超出3位 “,退出. 关键语法1. SPLIT , ...
- Apache三种工作模式详解
Apache HTTP服务器被设计为一个强大的.灵活的能够在多种平台以及不同环境下工作的服务器.这种模块化的设计就叫做“多进程处理模块”(Multi-Processing Module,MPM),也叫 ...
- SSRF——weblogic vulhub 漏洞复现及攻击内网redis(一)(附批量检测脚本)
0X01 概述 SSRF(Server-Side Request Forgery, 服务端请求伪造)利用漏洞可以发起网络请求来攻击内网服务.利用SSRF能实现以下效果:1) 扫描内网(主 ...
- python线程互斥锁Lock(29)
在前一篇文章 python线程创建和传参 中我们介绍了关于python线程的一些简单函数使用和线程的参数传递,使用多线程可以同时执行多个任务,提高开发效率,但是在实际开发中往往我们会碰到线程同步问题, ...
- Extjs 中combobox下拉框初始化赋值
近日在工作中遇到一个需求,要求页面初始化的时候给dataGrid表插入一条数据. 前端使用的是Extjs框架,dataGrid表有四列,其中三列是类型为textbox,普通文本框,另外一列类型是com ...
- 基于tesseract-OCR进行中文识别
1. 环境准备 1.1 下载 下载Tesseract-OCR安装包,地址为: https://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-w32- ...