【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 **** *** ...
随机推荐
- java中 int、char、long各占多少字节数
所谓的占用字节数 就是申请内存的时候所占的空间大小 byte 1字节 最小值是 -128(-2^7): 最大值是 127(2^7-1): boolean 至少1字节 这种类型只作为一 ...
- 【转载】 迁移学习与fine-tuning有什么区别
原文地址: https://www.cnblogs.com/fangpengchengbupter/p/8276204.html ----------------------------------- ...
- web自动化01-自动化解决的问题-环境搭建-元素定位
自动化测试 概念:由程序代码代替人工完成验证系统功能的过程 解决的问题: 回归测试 压力测试 兼容性测试 提高测试效率,提升产品质量 自动化测试分类 web自动化测试 移动自动化测试 接口自动化测试 ...
- Node.js报错TypeError: Cannot read property 'isDirectory' of undefined
截图如下: 原因如下:记住"./uploads" 后要加一个/ fs.stat("./uploads/" + files[i], function(err, s ...
- cursor -- 定义鼠标样式
cursor -- 定义鼠标样式 取值: [ [<uri> ,]* [ auto | crosshair | default | pointer | move | e-resize | n ...
- 第十八章 并发登录人数控制——《跟我学Shiro》
目录贴:跟我学Shiro目录贴 在某些项目中可能会遇到如每个账户同时只能有一个人登录或几个人同时登录,如果同时有多人登录:要么不让后者登录:要么踢出前者登录(强制退出).比如spring securi ...
- Egret入门学习日记 --- 问题汇总
问题1: 图片无法拖入到 EXML 文件的问题 在日记 第六篇 有记载:https://www.cnblogs.com/dmc-nero/p/11188975.html 位于 3.6节 内容. 问题2 ...
- 机器学习第一章——NFL的个人理解
第一篇博客,想给自己的学习加深记忆.看到书中第一个公式时,本来想直接看证明结果就好,然鹅...作者在备注上写:这里只用到一些非常基础的数学知识,只准备读第一章且有“数学恐惧”的读者可跳过...嘤嘤嘤, ...
- python面向对象学习笔记(一)
粘贴一些自学过程中的笔记大纲,源文本在pycharm里面写的,有点乱整理一下,部分内容有待补充,书写不一定100%正确,全当数据备份了. 1.面向对象的特性 #你写代码时什么使用面向对象 #处理比较复 ...
- Matlab给曲线添加加参考线
声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 对于Matlab的使用情况常常是这样子的,很多零碎的函数名字很难记忆,经常用过后过一段时间就又忘记了,又得去网 ...