生成一系列日期并与另一个日期范围进行比较并转动它

时间:2013-12-10 11:18:36

标签: sql sql-server

我有一种情况,我必须生成一系列日期(比如开始日期和结束日期)。 现在我想在这些生成日期填写特定日期的记录。

;WITH DateRange AS
(
    SELECT @start_date DateValue
    UNION ALL
    SELECT DateValue + 1
    FROM   DateRange
    WHERE  DateValue + 1 <= @end_date
)

如果@start_date = '2013-01-01' and @end_date= '2013-01-05'

生成的日期为'01/01/2013,01/02/2013,01/03/2013,01/04/2013,01/05/2013'

现在我想转动它以填充特定日期的特定数据。 我怎样才能做到这一点?

修改 我有3列,即Duration,StartDate和EndDate。现在我想动态生成这些日期并按时填充持续时间的值。

例如:if Duration = 6@start_date = '2013-01-01' and @end_date= '2013-01-05' 我想生成一个持续时间等于6的日期列表。

更新2:

如果你不明白我的问题,请详细说明。

  1. 我必须传递@startDate和@EndDate作为参数
  2. 我在表格中有字段ID,StartDate和EndDate,持续时间和其他字段
  3. 现在,当我传递参数时,查询应该生成@startDate和@EndDate的日期范围
  4. 生成日期时,必须检查表中的日期StartDate和EndDate,并将Duration的值设置为从StartDate到EndDate的字段。
  5. enter image description here

    要求输出 如果@startDate='2013-01-01'@endDate='2013-01-07',则输出必须如下:

    enter image description here

    **

    注意:第一张图片中两行的Id都相同。

    **

    更新3:

    enter image description here enter image description here

4 个答案:

答案 0 :(得分:3)

[更新2013-12-18 11:22 UTC]
[更新2013-12-18 14:19 UTC]
[更新2013-12-19 11:11 UTC]

因为我不知道您正在使用的表的名称,所以我创建了一个名为yeahyeah的名称。你应该用你自己的表的名称替换它。我已插入您提到的值(从问题中显示的日期持续时间)。

程序应如下所示。我称之为pivotit

create procedure pivotit (@start_date date, @end_date date)
as

/*
step 1:
identify all the data you need to fill the pivoted table.
this is achieved by using your daterange generator and joining
it with your table. the result is kept in a dynamic table
*/

declare @acols table (i int, d date, l int);
;WITH DateRange AS
(
    SELECT @start_date DateValue
    UNION ALL
    SELECT dateadd(dd,1,DateValue)
    FROM   DateRange
    WHERE  dateadd(dd,1,DateValue) <= @end_date
)
insert into @acols (i, d, l)
select id, DateValue, Duration from DateRange
join yeahyeah on (    DateRange.DateValue >= yeahyeah.FromDate 
                  and DateRange.DateValue <= yeahyeah.ToDate);

/* 
step 2:
for pivot you need all the columns that will be adressed. so
we create a string with all the distinct dates from the dynamic 
table. these will then be put into a format like [1], [2], [3], ...
to create a dynamic select.
*/


declare @p varchar(max) = '';
declare @s varchar(max);

select @p = @p + ', [' + CONVERT(varchar,d) + ']' from (select distinct d from @acols) a;
set @p = SUBSTRING(@p,3,len(@p)-2);

/*
step 3:
create the dynamic select. 
alas neither the dynamic table nor the parameters are available from 
inside the dynamic sql. i might try to use bind variables, but was 
not 100% sure if that would work here. so put in the declares for start_ 
and end_date from the procedure parameters and build up the dynamic table 
once more.

then i use @p for the pivoted select. this is done by selecting the column
for the rows (id) and all the values from the pivot as columns (@p).

details on the whole pivot thing are here:
http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
basically you tell sql-server (explicitly) what you want as the columns (@p),
what rows you want (id) and how to aggregate the values in the intersections
(sum(l))

[update 2013-12-19]
i added a routine that makes a cartesian product that has all the combination
of dates and ids in @acols, finds the ones that are missing in @acols and inserts
them with duration 0. then the pivoted cells are complete and display the zero
instead of NULL. you cannot use isnull or coalesce here since not the value
of the cell is NULL, the intersection simply did not exist.

*/

set @s = '
declare @start_date date = convert(date,'''+CONVERT(varchar,@start_date,112)+''',112);
declare @end_date date = convert(date,'''+CONVERT(varchar,@end_date,112)+''',112);
declare @acols table (i int, d date, l int);
;WITH DateRange AS
(
    SELECT @start_date DateValue
    UNION ALL
    SELECT dateadd(dd,1,DateValue)
    FROM   DateRange
    WHERE  dateadd(dd,1,DateValue) <= @end_date
)
insert into @acols (i, d, l)
select id, DateValue, Duration from DateRange
join yeahyeah on (    DateRange.DateValue >= yeahyeah.FromDate 
                  and DateRange.DateValue <= yeahyeah.ToDate);

with cart as 
(
     select distinct 
            a.i
          , b.d 
       from @acols a 
       join @acols b 
         on 1=1
)
insert into @acols (i, d, l)
select cart.i
     , cart.d
     , 0
  from cart 
  left outer join
       @acols a
    on cart.i = a.i
   and cart.d = a.d
 where a.i is null;

select id, '+@p+'
       from
( select convert(varchar,d) as d
       , l
       , i as id
    from @acols ) as sourcetable
  pivot ( 
    sum(l)
    for d in ('+@p+')
    )  as pivottable';

execute(@s);

创建程序后,您可以执行以下操作:

exec pivotit @start_date = '2013-01-01', @end_date = '2013-01-31'

然后会产生:

result with 0 and no zeroes

答案 1 :(得分:0)

您可以编写如下查询:

declare @start_date datetime,@end_date datetime ;
set @start_date ='2013-01-01' ;
set @end_date = '2013-01-05' ;
DECLARE @columns NVARCHAR(MAX),@sql NVARCHAR(MAX);
SET @columns = N'';

WITH DateRange AS
(
    SELECT @start_date DateValue
    UNION ALL
    SELECT DateValue + 1
    FROM   DateRange
    WHERE  DateValue + 1 <= @end_date
)
--Get column names for entire pivoting
SELECT @columns += N', ' + QUOTENAME(SpreadCol)
FROM (select distinct convert(varchar(10),DateValue,101) as SpreadCol 
from DateRange
) AS T;  

PRINT @columns;

然后在动态数据透视查询中使用@columns作为扩展列。

答案 2 :(得分:0)

使用SQL Server Reporting Services向导。

  • 在向导中,将查询设置为带有数据表的日期范围表的左连接。
  • 作为报告类型选择矩阵。
  • 将日期分配给列区域,将数据表的行ID分配给行区域,将数据表的值列分配给值区域。
  • 选择一种风格
  • 生成报告。

如果需要定期生成报告,可以将其发布到报告服务器上。用户可以导出为首选格式。它看起来也不错;)

如果您愿意,也可以绘制结果图表。

有关报告向导的详细信息,请参阅http://technet.microsoft.com/en-us/library/ms160326(v=sql.105).aspx

有关生成日期范围表的其他方法,请参阅SQL query to select dates between two dates

答案 3 :(得分:-1)

我的查询 - 日期范围可以是多长。如果你在页面中显示的方式很长。首先用其他样本数据然后将其转换为动态sql或者询问。

Declare @startDate date='2013-01-01' 
Declare @endDate date='2013-01-07'
Declare @t table(startdate date,enddate date,duration int)
insert into @t values('2013-01-01','2013-01-03',15),('2013-01-04','2013-01-06',10)

;WITH DateRange AS
(
    SELECT @startDate DateValue
    UNION ALL
    SELECT dateadd(day,1,DateValue)
    FROM   DateRange
    WHERE  dateadd(day,1,DateValue) < @endDate
)
select [2013-01-01],[2013-01-02],[2013-01-03],[2013-01-04],[2013-01-05],[2013-01-06]
from 
(select a.datevalue,  duration  from DateRange a
left join @t b on  a.DateValue >= b.startdate and a.DateValue<= b.enddate)AS SourceTable
PIVOT
(
 Min(duration) for datevalue in([2013-01-01],[2013-01-02],[2013-01-03],[2013-01-04],[2013-01-05],[2013-01-06])
) AS PivotTable