【问题标题】:Nested WHILE loop - SQL Server 2000嵌套的 WHILE 循环 - SQL Server 2000
【发布时间】:2016-11-15 02:49:36
【问题描述】:

在 SQL Server 2000 中,我希望能够列出 2 个日期之间的所有日期,包括每天的小时数,所以如果我有 @fromdate = 2016-07-01 00:00:00@todate = 2016-07-05 00:00:00,那么我需要一个列表:

2016-07-01 00:00:00
2016-07-01 01:00:00
2016-07-01 02:00:00
2016-07-01 03:00:00
2016-07-01 04:00:00
...
2016-07-04 23:00:00
2016-07-05 00:00:00

现在这个查询已经进行到一半了:

declare @fromdate as datetime
declare @todate as datetime

set @FromDate = '2016-07-11 00:00:00.000'
set @ToDate = '2016-07-21 00:00:00.000'

declare @i int, @j int

set @i = convert(int, @todate - @fromdate)
set @j = 0

while @i >= 0
begin
  while @j < 24
  begin
     select dateadd(hour, @j, @ToDate - @i) as date, @j as Hour
     set @j = @j + 1
  end

  set @i = @i - 1
end

它返回第一天的每小时拆分,但不会跳到第二天。如果我禁用内部while 循环,则外部循环无需数小时即可正常工作。欢迎提出任何建议,记住它是 SQL Server 2000,因此没有任何高级功能。

【问题讨论】:

  • 这会很慢,你不想快点吗?
  • How to generate a range of dates in SQL Server 的可能重复项只需将 day 更改为 hour
  • 特别是因为这是 sql 2000,您需要一个数字/计数表。顺便说一句,你会升级吗?它已经停止支持超过 6 年了。仅仅因为我们还有 14.4 调制解调器并不意味着我们应该继续使用它。 :)
  • Sql Server 2000 已经过时了。它不再获得任何补丁,即使是针对关键的安全问题,并且现在已经有一段时间没有了。继续使用它是非常不负责任的。升级此服务器是工作 1。

标签: sql sql-server loops while-loop sql-server-2000


【解决方案1】:

将您的问题视为学术问题,这就是您的代码不起作用的原因:

在内循环完成后,您需要将@j 重置为零。否则@j 停留在“24”并且内部循环不再执行。

正如其他人指出的那样,还有其他可能更好的方法来做你想做的事情。

【讨论】:

    【解决方案2】:

    我认为你可以做一些简单的事情。我没有检查 dateadd sintaxis,但每次只添加 1 小时,直到你到达目标日期

    declare @fromdate as datetime
    declare @todate as datetime
    declare @printDate as datetime
    
    set @FromDate = '2016-07-11 00:00:00.000'
    set @ToDate = '2016-07-21 00:00:00.000'
    set @printDate = @FromDate
    
    while @printDate <= @todate
    begin
         select @printDate as Hour
         set @printDate = dateadd(hour, 1, @printDate )
    end
    

    【讨论】:

      【解决方案3】:

      这将根据您的范围在表格中按小时为您提供您需要的日期。

      create table #dates(
      dates datetime)
      
      declare @fromdate as datetime
      declare @todate as datetime
      
      set @FromDate = '2016-07-11 00:00:00.000'
      set @ToDate = '2016-07-21 00:00:00.000'
      
      declare @ct int 
      set @ct = datediff(hour,@FromDate,@ToDate)
      
      while @ct > 0
        begin
          insert into #dates (dates)
          select dateadd(hour,@ct,@FromDate)
          set @ct = @ct - 1
        end
      
      select * from #dates
      

      --RESULTS
      2016-07-21 00:00:00.000
      2016-07-20 23:00:00.000
      2016-07-20 22:00:00.000
      2016-07-20 21:00:00.000
      2016-07-20 20:00:00.000
      2016-07-20 19:00:00.000
      2016-07-20 18:00:00.000
      2016-07-20 17:00:00.000
      2016-07-20 16:00:00.000
      ....etc...
      

      【讨论】:

        【解决方案4】:

        要添加,您可能还想使用表变量来加快速度并获得一个结果集:

        declare @table table (DateHour datetime, Hour int)
        declare @fromdate as datetime
        declare @todate as datetime
        
        set @FromDate = '2016-07-11 00:00:00.000'
        set @ToDate = '2016-07-21 00:00:00.000'
        
        declare @i int, @j int
        
        set @i = convert(int, @todate - @fromdate)
        set @j = 0
        while @i >= 0
        begin
          while @j <24
          begin
             insert @table
             values (dateadd(hour, @j, @ToDate - @i), @j) --as Hour
             set @j=@j+1
          end
        set @j=0
        set @i=@i-1
        end
        select * from @table
        

        【讨论】:

          【解决方案5】:

          为了演示计数表的概念,我将其放在一起。这将在 sql 2000 中正常工作。第一步是创建持久计数表。这只需要在您第一次使用这种表时完成。在更高版本的 sql 中,我会以不同的方式创建它,但它仍然有效。如果你愿意,你甚至可以添加一个触发器来禁止插入或删除,这样你就可以确保没有间隙。

          create Table MyTally
          (
              N int identity(1,1) 
          )
          GO
          
          insert MyTally
          DEFAULT VALUES
          go 10000 --This will cause the previous batch to loop that many times.
          

          现在我们有了一个包含 10,000 个递增值的表,我们可以使用它。

          declare @fromdate as datetime
          declare @todate as datetime
          
          set @FromDate = '2016-07-11 00:00:00.000'
          set @ToDate = '2016-07-21 00:00:00.000'
          
          select dateadd(hour, x.N - 1, DATEADD(day, t.N - 1, @FromDate))
          from cteTally t
          cross join 
          (
              select N
              from cteTally
              where N <= 24
          )x
          where t.N <= DATEDIFF(day, @FromDate, @todate) + 1
          

          这将创建这两个日期之间 11 天所需的 264 行。

          【讨论】: