当前位置:Gxlcms > 数据库问题 > 【Transact-SQL】统计某字段中的值第一次出现后的2小时内出现的次数

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

时间:2021-07-01 10:21:17 帮助过:9人阅读

@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‘开始的下个区间了,而这里显然是有问题的。

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

    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万+ 他的留言板 关注

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

    标签:col   关注   相等   from   访问   line   vat   temp   select   

    人气教程排行