【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小时内,总共出现了几次?

这个是网上的解答:


  1. declare @table1 table(name nvarchar,createdate smalldatetime)
  2. insert into @table1
  3. select ‘a‘,‘2011-03-01 10:00:00‘
  4. union all select ‘a‘,‘2011-03-01 11:00:00‘
  5. union all select ‘a‘,‘2011-03-01 14:00:00‘
  6. union all select ‘b‘,‘2011-03-01 13:00:00‘
  7. union all select ‘b‘,‘2011-03-01 13:20:00‘
  8. union all select ‘b‘,‘2011-03-01 14:00:00‘
  9. select name,
  10. createdate,
  11. (select count(createdate)
  12. from @table1 b
  13. where a.name=b.name and
  14. a.createdate<=b.createdate and
  15. dateadd(hh,2,a.createdate) >= b.createdate
  16. ) as count
  17. from @table1 a
  18. where not exists
  19. (select 1 from
  20. @table1 b
  21. where a.name=b.name and
  22. a.createdate>b.createdate and
  23. a.createdate<dateadd(hh,2,b.createdate))
  24. 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‘开始的下个区间了,而这里显然是有问题的。

以下是我写的解法,虽然效率不是太高,但是能解决这个问题:


  1. declare @table1 table(name nvarchar,createdate smalldatetime)
  2. insert into @table1
  3. select ‘a‘,‘2011-03-01 10:00:00‘
  4. union all select ‘a‘,‘2011-03-01 11:00:00‘
  5. union all select ‘a‘,‘2011-03-01 12:00:00‘
  6. union all select ‘b‘,‘2011-03-01 13:10:00‘
  7. union all select ‘b‘,‘2011-03-01 13:20:00‘
  8. union all select ‘b‘,‘2011-03-01 14:30:00‘
  9. union all select ‘b‘,‘2011-03-01 15:15:00‘
  10. union all select ‘b‘,‘2011-03-01 16:00:00‘
  11. union all select ‘b‘,‘2011-03-01 17:00:00‘
  12. ;with aa --按照name分区,同时按照createdate排序编号
  13. as
  14. (
  15. select name,
  16. createdate,
  17. ROW_NUMBER() over(partition by name
  18. order by createdate) as k1
  19. from @table1
  20. ),
  21. r
  22. as
  23. (
  24. select v.name,
  25. starts=v.k1, --区间开始的编号
  26. ends=isnull(
  27. min(case when v.k1<a.k1
  28. and DATEADD(hour,2,v.createdate) <= a.createdate
  29. then a.k1
  30. else null
  31. end)-1,
  32. max(case when v.k1<a.k1
  33. then a.k1
  34. else v.k1
  35. end)
  36. ), --区间结尾的编号
  37. isnull(
  38. min(case when v.k1<a.k1
  39. and DATEADD(hour,2,v.createdate) <= a.createdate
  40. then a.k1
  41. else null
  42. end)-1,
  43. max(case when v.k1<a.k1
  44. then a.k1
  45. else v.k1
  46. end)
  47. ) - v.k1 as diff --区间结尾编号与区间开始编号之间的差值
  48. from aa v
  49. inner join aa a
  50. on v.name = a.name --只关联name相等的
  51. group by v.name,
  52. v.k1
  53. having isnull(
  54. min(case when v.k1<a.k1
  55. and DATEADD(hour,2,v.createdate) <= a.createdate
  56. then a.k1
  57. else null
  58. end)-1,
  59. max(case when v.k1<a.k1
  60. then a.k1
  61. else v.k1
  62. end)
  63. ) >=v.k1
  64. and
  65. isnull(
  66. max(case when v.k1>a.k1 and
  67. DATEADD(hour,-2,v.createdate) >= a.createdate
  68. then v.k1 - 1
  69. else null
  70. end) + 1,
  71. min(case when v.k1>a.k1
  72. then a.k1
  73. else v.k1
  74. end)
  75. ) = v.k1
  76. )
  77. --select * from r
  78. select aa.name,
  79. aa.createdate,
  80. diff + 1
  81. from r
  82. inner join aa
  83. on aa.name = r.name
  84. and aa.k1 =r.starts
  85. where not exists
  86. (select 1
  87. from r rr
  88. where rr.name = r.name and
  89. rr.starts <> r.starts and
  90. rr.starts < r.starts and
  91. (rr.ends = r.ends or
  92. rr.ends = r.starts)
  93. )

不过发现我的这个解法也是有问题的,最大的问题在与不能准确的确定上限在那里,还得继续考虑问题的解法。

下面这个也是有问题的:


  1. declare @table1 table(name nvarchar,createdate smalldatetime)
  2. insert into @table1
  3. select ‘a‘,‘2011-03-01 10:00:00‘
  4. union all select ‘a‘,‘2011-03-01 11:00:00‘
  5. union all select ‘a‘,‘2011-03-01 12:00:00‘
  6. --union all select ‘b‘,‘2011-03-01 13:10:00‘
  7. --union all select ‘b‘,‘2011-03-01 13:20:00‘
  8. --union all select ‘b‘,‘2011-03-01 14:30:00‘
  9. --union all select ‘b‘,‘2011-03-01 15:15:00‘
  10. --union all select ‘b‘,‘2011-03-01 16:00:00‘
  11. --union all select ‘b‘,‘2011-03-01 17:15:00‘
  12. ;with a --按照name分区,同时按照createdate排序编号
  13. as
  14. (
  15. select name,
  16. createdate,
  17. ROW_NUMBER() over(partition by name
  18. order by createdate) as k1
  19. from @table1
  20. ),
  21. c
  22. as
  23. (
  24. select a1.name,
  25. a1.createdate,
  26. a1.k1,
  27. MIN(a2.createdate) as nextCreatedate,
  28. MIN(a2.k1) as nextK1
  29. from a a1
  30. inner join a a2
  31. on a1.name = a2.name
  32. and a2.createdate < DATEADD(hour,2,a1.createdate)
  33. and a2.createdate >= a1.createdate
  34. and a1.k1 <= a2.k1
  35. group by a1.name,
  36. a1.createdate,
  37. a1.k1
  38. ),
  39. w
  40. as
  41. (
  42. select name,
  43. createdate,
  44. k1
  45. --null,
  46. --null,
  47. --null
  48. from a
  49. where k1 = 1
  50. union all
  51. select c.name,
  52. c.nextCreatedate,
  53. c.nextK1
  54. from W
  55. inner join a
  56. on a.name = w.name
  57. and dateadd(hour,2,w.createdate) <= a.createdate
  58. and w.k1 <= a.k1
  59. and w.createdate <> ‘2011-03-01 12:00:00‘
  60. inner join c
  61. on w.name = c.name
  62. and w.createdate = c.createdate
  63. and w.k1 = c.k1
  64. where w.k1 <=3
  65. )
  66. SELECT *
  67. FROM w

下面的解法是正确的,不过用的是T-SQL,不是纯sql了:


  1. declare @table1 table(name nvarchar(100),createdate smalldatetime)
  2. declare @table2 table(name nvarchar(100),createdate smalldatetime,rnum bigint)
  3. declare @temp table(name nvarchar(100),createdate smalldatetime,rnum bigint)
  4. declare @i int = 1;
  5. insert into @table1
  6. select ‘a‘,‘2011-03-01 10:00:00‘
  7. union all select ‘a‘,‘2011-03-01 11:00:00‘
  8. union all select ‘a‘,‘2011-03-01 12:00:00‘
  9. union all select ‘b‘,‘2011-03-01 13:10:00‘
  10. union all select ‘b‘,‘2011-03-01 13:20:00‘
  11. union all select ‘b‘,‘2011-03-01 14:30:00‘
  12. union all select ‘b‘,‘2011-03-01 15:15:00‘
  13. union all select ‘b‘,‘2011-03-01 16:00:00‘
  14. union all select ‘b‘,‘2011-03-01 17:16:00‘
  15. union all select ‘b‘,‘2011-03-01 17:15:00‘
  16. ;with a --按照name分区,同时按照createdate排序编号
  17. as
  18. (
  19. select name,
  20. createdate,
  21. ROW_NUMBER() over(partition by name
  22. order by createdate) as k1
  23. from @table1
  24. )
  25. insert into @table2
  26. select * from a
  27. insert into @temp
  28. select name,
  29. createdate,
  30. rnum
  31. from @table2
  32. where rnum = 1
  33. --select * from @temp
  34. while @i <= (select MAX(rnum) from @table2)
  35. begin
  36. insert into @temp
  37. select t2.name,
  38. min(t2.createdate),
  39. @i +1
  40. from @temp t1
  41. inner join @table2 t2
  42. on t1.name = t2.name
  43. and t2.createdate >= dateadd(hour,2,t1.createdate)
  44. where t1.rnum = @i
  45. group by t2.name
  46. set @i = @i + 1
  47. end
  48. ;with r
  49. as
  50. (
  51. select name,
  52. createdate
  53. from @temp
  54. group by name,
  55. createdate
  56. )
  57. select r.name,
  58. r.createdate,
  59. COUNT(1)
  60. from r
  61. inner join @table1 t
  62. on t.name = r.name
  63. and t.createdate >= r.createdate
  64. and t.createdate <DATEADD(HOUR,2,r.createdate)
  65. group by r.name,
  66. r.createdate

其实这个问题是个递归问题,由上一个找到下一个,但是得构造一下:


  1. declare @table1 table(name nvarchar,createdate smalldatetime)
  2. insert into @table1
  3. select ‘a‘,‘2011-03-01 10:00:00‘
  4. union all select ‘a‘,‘2011-03-01 11:00:00‘
  5. union all select ‘a‘,‘2011-03-01 12:00:00‘
  6. union all select ‘a‘,‘2011-03-01 12:20:00‘
  7. union all select ‘b‘,‘2011-03-01 13:10:00‘
  8. union all select ‘b‘,‘2011-03-01 13:20:00‘
  9. union all select ‘b‘,‘2011-03-01 14:30:00‘
  10. union all select ‘b‘,‘2011-03-01 15:15:00‘
  11. union all select ‘b‘,‘2011-03-01 16:00:00‘
  12. union all select ‘b‘,‘2011-03-01 17:20:00‘
  13. union all select ‘b‘,‘2011-03-01 17:15:00‘
  14. union all select ‘b‘,‘2011-03-01 19:16:00‘
  15. union all select ‘b‘,‘2011-03-01 17:15:00‘
  16. ;with a --按照name分区,同时按照createdate排序编号
  17. as
  18. (
  19. select name,
  20. createdate,
  21. ROW_NUMBER() over(partition by name
  22. order by createdate) as k1
  23. from @table1
  24. ),
  25. c --对于每个时间,找到大于这个时间2小时的时间中最小那个时间
  26. as
  27. (
  28. select a1.name,
  29. a1.createdate,
  30. a1.k1,
  31. MIN(a2.createdate) as nextCreatedate,
  32. MIN(a2.k1) as nextK1
  33. from a a1
  34. inner join a a2
  35. on a1.name = a2.name
  36. and a2.createdate >= DATEADD(hour,2,a1.createdate)
  37. group by a1.name,
  38. a1.createdate,
  39. a1.k1
  40. union all
  41. select a.name,null,null,a.createdate,1 --构造递归运行时需要的层级
  42. from a
  43. where k1 = 1
  44. ),
  45. w --递归查询
  46. as
  47. (
  48. select c.name,
  49. c.createdate,
  50. c.k1,
  51. c.nextCreatedate,
  52. c.nextK1,
  53. 1 as lev
  54. from c
  55. where createdate is null
  56. and k1 is null
  57. union all
  58. select c.name,
  59. c.createdate,
  60. c.k1,
  61. c.nextCreatedate,
  62. c.nextK1,
  63. lev + 1
  64. from W
  65. inner join c
  66. on w.name = c.name
  67. and w.nextCreatedate = c.createdate
  68. )
  69. SELECT distinct name,
  70. nextCreatedate,
  71. nextK1
  72. FROM w


不想长大啊

发布了416 篇原创文章 · 获赞 135 · 访问量 94万+

他的留言板
关注

原文地址:https://www.cnblogs.com/lonelyxmas/p/12019942.html

时间: 2024-10-11 11:37:00

【Transact-SQL】统计某字段中的值第一次出现后的2小时内出现的次数的相关文章

利用Entity Framework修改指定字段中的值

利用Entity Framework修改指定字段中的值一般我们编辑某些模型的时候会用到类似这样的代码: [HttpPost] public ActionResult Edit(Article model) { if (model.Id == 0) { return HttpNotFound(); } using (db) { db.Entry(model).State = EntityState.Modified; db.SaveChanges(); } return RedirectToAct

sql server查找字段中含有汉字

/***************************************************************%%%% 描述: SQL语句查询字段中是否包含汉字%%****************************************************************%% 编写:[email protected] 2007-12-17%% 说明:如有转载请注明来处http://blog.sina.com.cn/houkuan***************

统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数,其他字符出现的次数。

/** * A:案例演示 * 需求:统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数,其他字符出现的次数. * [email protected]#$%^ * 分析:字符串是有字符组成的,而字符的值都是有范围的,通过范围来判断是否包含该字符 * 如果包含就让计数器变量自增 */ public static void main(String[] args) { String s = "[email protected]#$%^"; int big = 0; int smal

SQL(replace)替换字段中指定的字符

语法:update 表名 set 字段名=REPLACE(字段名,'修改前的字符','修改后的字符') 例 Product商品表中Name 名字字段中描述中将'AAA' 修改成 'BBB' SQL语句如下 update Product set Name=REPLACE(Name,'AAA','BBB') 注意的是这样会将Name字段中所有的AAA修改成BBB,所以修改前要确认是否可用这种方式修改

hadoop中的hive查询cdn访问日志指定时间段内url访问次数最多的前10位(结合python语言)

hadoop环境描述: master节点:node1 slave节点:node2,node3,node4 远端服务器(python连接hive):node29 需求:通过hive查询到cdn日志中指定时间段内url访问次数最多的前10个url ps:用pig查询可以查询文章: http://shineforever.blog.51cto.com/1429204/1571124 说明:python操作远程操作需要使用Thrift接口: hive源码包下面自带Thrift插件: [[email pr

java 利用反射修改对象中的list类型字段中的值。

这两天没事学习下了反射.通过反射我们可以修改对象中的字段的值. 就如下面这段代码 Grade grade=new Grade(); Field f=Grade.class.getDeclaredField("name"); f.setAccessible(true); f.set(grade, "三年级一班"); 这是so easy的,这时我想到了要是list类型的字段该怎么通过反射修改呢. 于是我就尝试了下,最终做了出来. 先准备两个类. public class

利用MySQL统计一列中不同值的数量方法示例

前言 本文实现的这个需求其实十分普遍,举例来说,我们存在一个用户来源表,用来标记用户从哪个渠道注册进来.表结构如下所示- 其中 origin 是用户来源,其中的值有 iPhone .Android .Web 三种,现在需要分别统计由这三种渠道注册的用户数量. 解决方案1 ? 1 2 3 4 5 6 7 8 9 SELECT count(*) FROM user_operation_log WHERE origin = 'iPhone'; SELECT count(*) FROM user_ope

sql替换数据库字段中的字符

方法一:varchar和nvarchar类型是支持replace,所以如果你的text不超过8000可以先转换成前面两种类型再使用replace 替换 text ntext 数据类型字段的语句 . update 表名 set 字段名=replace(cast(与前面一样的字段名 as varchar(8000)) ,'原本内容','想要替换成什么') 方法二: update [表名] set 字段名 = replace(与前面一样的字段名,'原本内容','想要替换成什么')

dede中sql调用自定义字段中的图片

[field:id runphp='yes']$aid = @me;$row = $GLOBALS['dsql']->GetOne("Select tu2 From `#@__addonarticle` where aid='$aid' ");@me = "{$row['tu2']}";[/field:id] `#@__addonarticle` 这个地方不是单引号 自定义字段 选择 图片 仅地址