2

一个名为的表VolumeRequest按帐户存储日期范围内的卷请求。

AccountId   StartDate                       EndDate                   DailyVolume
670         2013-07-01 00:00:00.000         2013-07-31 00:00:00.000   10
670         2013-07-01 00:00:00.000         2013-07-31 00:00:00.000   1050
670         2013-07-10 00:00:00.000         2013-07-10 00:00:00.000   -350
670         2013-07-24 00:00:00.000         2013-07-26 00:00:00.000   -350
673         2013-06-01 00:00:00.000         2013-07-31 00:00:00.000   233

我需要每天显示请求,其中在给定日期范围(例如 7 月)内按帐户按天计算量,报告如下所示。需要针对给定的报告日期修剪卷请求的日期开始日期和结束日期

AccountId   Date                         Volume
670         2013-07-01 00:00:00.000      1060
670         2013-07-02 00:00:00.000      1060
.
.
670         2013-07-10 00:00:00.000      710
.
.
670         2013-07-24 00:00:00.000      710
670         2013-07-25 00:00:00.000      710
670         2013-07-26 00:00:00.000      710
.
.
670         2013-07-31 00:00:00.000      1060
673         2013-07-01 00:00:00.000      233
.
.
673         2013-07-31 00:00:00.000      233

现在我正在使用表变量和循环来实现它,我知道这不是一个好的编码方式。

DECLARE @sDate DATETIME, @eDate DATETIME , @volume DECIMAL (10, 4),  rstartdate DATETIME, @renddate   DATETIME , @loopcount   INT
SET @sdate = '4/1/2013'
SET @edate = '4/30/2013'

DECLARE @VolumeRequest TABLE 
  ( 
     ID        INT IDENTITY (1, 1) PRIMARY KEY, 
     Aid       INT, 
     Startdate DATETIME, 
     Enddate   DATETIME, 
     volume    DECIMAL (14, 4) 
  ) 
DECLARE @DailyRequest TABLE 
  ( 
     ID        INT IDENTITY (1, 1) PRIMARY KEY, 
     Accountid INT, 
     ReadDate  DATETIME, 
     Volume    DECIMAL (14, 4) 
  ) 

    INSERT INTO @VolumeRequest 
      SELECT Accountid, 
             ( CASE 
                 WHEN @sdate > startdate THEN @sdate 
                 ELSE startdate 
               END ), 
             ( CASE 
                 WHEN @edate < enddate THEN @edate 
                 ELSE enddate 
               END ), 
             dailyvolume 
      FROM   VolumeRequest 
      WHERE  Startdate <= @edate 
             AND Enddate >= @sdate 
             AND isnull (deprecated, 0) != 1 

      --loop to breakdown the volume requests into daily requests 
      SET @loopcount = 1

      WHILE @loopcount <= (SELECT MAX(ID) 
                                FROM   @VolumeRequest) 
        BEGIN 
            SELECT @volume = volume, 
                   @rstartdate = Startdate, 
                   @renddate = Enddate 
            FROM   @VolumeRequest 
            WHERE  ID = @loopcount 

            WHILE @rstartdate <= @renddate 
              BEGIN 
                  INSERT INTO @DailyRequest 
                  SELECT @currentaid, 
                         @rstartdate, 
                         @volume 

                  SET @rstartdate = DATEADD(day, 1, @rstartdate) 
              END 

            SET @LoopCount = @LoopCount + 1 
        END

我正在寻找不涉及循环或游标的方法。我发现了一个类似的问题。那里的答案对我没有帮助。

4

2 回答 2

2

我喜欢使用 Dates 表,例如

CREATE TABLE #Dates(
    DateId INT,
    CalendarDate DATETIME)

填写您需要的任何范围的日期。我使用此表连接到诸如 VolumeRequest 之类的表以检索您请求的输出。

SELECT
    v.AccountId,
    d.CalendarDate,
    SUM(v.DailyVolume)
FROM
    #Dates d INNER JOIN
    VolumeRequest v ON
        d.CalendarDate >= v.StartDate AND
        d.CalendarDate <= v.EndDate
group by
    d.CalendarDate,
    v.AccountId

为了填充#Dates 表,我使用如下内容:

declare @startdate datetime = '6/1/13', @enddate datetime = '7/31/13'

create table #Dates(CalendarDate datetime)

insert into #Dates(CalendarDate)
select
    dateadd(dd, rid-1, @startdate) as calendardate
from (
    select
        ROW_NUMBER() over(order by o.object_id) as rid
    From
        sys.objects o cross apply
        sys.objects o2
) dates
where
    dateadd(dd, rid-1, @startdate) >= @startdate and dateadd(dd, rid-1, @startdate) <= @enddate

修改以满足您的日期范围需求。

于 2013-08-09T17:05:07.600 回答
1

SQLFiddle 演示

使用 WITH 子句和递归,我们生成Days了包含 MIN 和 MAX 日期之间的所有日期的表。然后生成Accounts具有 distinct 的表AccountID。最后加入所有这些表并用 SUM 分组。

WITH MINMAX as 
( SELECT MIN(StartDate) as MinDate,
         MAX(EndDate) as MaxDate
  from T
),
DAYS as
( SELECT MinDate as D from MINMAX
  UNION ALL
  SELECT D+1 as D FROM DAYS WHERE D+1<=
    (
      SELECT MaxDate FROM MINMAX  
     )
),
Accounts as 
(
  select distinct AccountID from T
) 

select A.AccountId,Days.D,sum(T.DailyVolume) from Days
CROSS JOIN Accounts A 
JOIN T on A.AccountID=T.AccountID
          AND
          Days.D between T.StartDate and T.EndDate
GROUP BY A.AccountId,Days.D
ORDER BY A.AccountId,Days.D
OPTION (MAXRECURSION 10000)
于 2013-08-09T17:16:15.193 回答