【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 **** *** ...
随机推荐
- 解决Mac OS编译安装时出现 cannot find openssl's <evp.h> 错误的问题
踩坑 最近通过pecl安装mongodb扩展时,提示以下错误 ...... configure: error: Cannot find OpenSSL's <evp.h> ...... 根 ...
- VS中卸载Visual Assist X
Tools=>Extensions and updates=>找到Visual Assist X 卸载:
- sqlalchemy连接 MySQL(转)
from sqlalchemy import create_engine,Table,Column,Integer,String,MetaData,ForeignKey engine=create_e ...
- ps 快捷键大全
一.工具箱(多种工具共用一个快捷键的可同时按[Shift]加此快捷键选取)矩形.椭圆选框工具 [M]移动工具 [V]套索.多边形套索.磁性套索 [L]魔棒工具 [W]裁剪工具 [C]切片工具.切片选择 ...
- 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_06-SpringSecurityOauth2研究-Oauth2授权码模式-申请令牌
3.3 Oauth2授权码模式 3.3.1 Oauth2授权模式 Oauth2有以下授权模式: 授权码模式(Authorization Code) 隐式授权模式(Implicit) 密码模式(Reso ...
- .The server quit without updating PID file (/var/lib/mysql/pc.pid).
启动Mysql是报错 [root@pc mysql]# mysql startERROR 2002 (HY000): Can't connect to local MySQL server throu ...
- 重新认识Java 8的HashMap
[转自]美团技术博客 HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型.随着JDK(Java Developmet Kit)版本的更新,JDK1.8对HashMap底层的实 ...
- DELPHI中 screen.Cursor:=crhourglass; adoQuery.close; adoquery.Open; screen.Cursor:=crdefault;啥意思
鼠标忙这段代码大概是用来演示鼠标的用法的.具体解释如下: 使鼠标指针为沙漏状.(以表示程序正忙)screen.Cursor:=crhourglass; 把(打开的)数据库关闭.adoQuery.clo ...
- MySQL中创建存储过程示例
在这个示例中需要用到一张名为test_table的表,我们使用show create table test_table查看表的创建过程: CREATE TABLE `test_table` ( `id ...
- ELK之elasticsearch删除索引
参考文档:https://www.cnblogs.com/Dev0ps/p/9493576.html elasticsearch使用时间久了会产生大量索引占用磁盘空间,可以删除索引来释放 查看当前所有 ...
