SQL选择日期范围内的所有内容,每个日期都有多个值

时间:2014-12-09 12:01:21

标签: sql sql-server date

我已经尝试过搜索,但我不完全确定如果在其他地方已经回答了这个问题,请提前道歉。

我正在尝试选择多个值的日期范围(包括该日期没有值的地方)之间的所有内容。我还没有真正解释过,但下面是我所追求的输出的一个例子。

Date    Campaign    Channel Transaction
01/01/2015  a   Online  Sale
01/01/2015  b   Online  Sale
01/01/2015  c   Online  Sale
01/01/2015  a   Online  Cancellation
01/01/2015  b   Online  Cancellation
01/01/2015  c   Online  Cancellation
01/01/2015  a   Offline Sale
01/01/2015  b   Offline Sale
01/01/2015  c   Offline Sale
01/01/2015  a   Offline Cancellation
01/01/2015  b   Offline Cancellation
01/01/2015  c   Offline Cancellation
02/01/2015  a   Online  Sale
02/01/2015  b   Online  Sale
02/01/2015  c   Online  Sale
02/01/2015  a   Online  Cancellation
02/01/2015  b   Online  Cancellation
02/01/2015  c   Online  Cancellation
02/01/2015  a   Offline Sale
02/01/2015  b   Offline Sale
02/01/2015  c   Offline Sale
02/01/2015  a   Offline Cancellation
02/01/2015  b   Offline Cancellation
02/01/2015  c   Offline Cancellation

我可以选择日期范围之间的每一天,但是即使没有返回任何结果,也无法确定如何选择每一天的结果。

编辑 - 添加了我找到的解决方案

好的,所以我有一个似乎对我有用的解决方案。可能有更好的方法来做到这一点,任何建议都表示赞赏,但这是我现在正在做的事情

Declare @CC TABLE (Campaign varchar(50))
DECLARE @Channel Table (Channel Varchar(255))
DECLARE @TYPE TABLE (Transaction_Type varchar(255))
Insert Into @CC (Campaign) Values ('1')
Insert Into @CC (Campaign) Values ('2')
Insert Into @Channel (Channel) Values ('Online')
Insert Into @Channel (Channel) Values ('Inbound')
Insert Into @TYPE (Transaction_Type) Values ('Sale')
Insert Into @TYPE (Transaction_Type) Values ('Cancellation')
DECLARE 
@StartDate DATE = Dateadd(YY,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)), 
@EndDate DATE = Getdate() 
SELECT 
DATEADD(DAY, nbr - 1, @StartDate) as Dates,
Campaign, 
Channel, 
Transaction_Type 
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr  
FROM sys.columns c) nbrs,
@CC, @Channel, @TYPE WHERE nbr - 1 <= DATEDIFF(DAY, @StartDate, @EndDate)
Order by Dates asc, Campaign asc, Channel asc, Transaction_Type asc

3 个答案:

答案 0 :(得分:1)

您可以使用CTE进行此操作。

  DECLARE
    @start date = '1900-01-01',
    @end date = '1900-01-10';

with dateRange (myDate) AS (
    select @start myDate
    UNION ALL
    select DATEADD(DAY,1,myDate) from dateRange
    where
        myDate <= @end
)
select 
    * 
from dateRange D
inner join yourTable T on
    D.myDate = T.[Date]
OPTION (MAXRECURSION 365)

使用完整的外连接

DECLARE
    @start date = '1900-01-01',
    @end date = '1900-01-10';

with dateRange (myDate) AS (
    select @start myDate
    UNION ALL
    select DATEADD(DAY,1,myDate) from dateRange
    where
        myDate <= @end
)
select 
    * 
from dateRange D
full outer join @CC C ON
    1=1
full outer join @Channel CH ON
    1=1
full outer join @TYPE Ty ON
    1=1
left join yourTable T on
    D.myDate = T.[Date] and
    C.Campaign = T.[Campaign] and
    CH.Channel = T.[Channel] and
    Ty.[Transaction_Type] = T.[Transaction_Type]
OPTION (MAXRECURSION 365)

答案 1 :(得分:0)

使用纯SQL(并且没有递归CTE),我担心你需要a numbers table

基本理念是:

  • 确定n,即开始日期和结束日期之间的日期数,
  • 从您的号码表中选择号码1到n,然后
  • 将数字(以天为单位)添加到开始日期。

这应该会生成从开始日期到结束日期的日期列表,您可以将其加入到原始结果集中以填补空白&#34;。

答案 2 :(得分:0)

我正在使用表值函数返回范围(here)中的所有日期。

您可以进行小的更改(例如重命名,日期时间 - &gt;日期,删除字符列)以满足您的需求。

Create Function [dbo].[IntervalaDatumi]
(
    @DatumsNo DateTime,
    @DatumsLidz DateTime
)
Returns @tab Table
    (
        Datums DateTime,
        DatumsChar char(10)
    )
As
Begin
    Declare @Dienas int
    Declare @i int
    Set @Dienas = DateDiff(Day, @DatumsNo, @DatumsLidz)

    Set @i = 0;
    While (@Dienas > @i)
    Begin
        Insert Into @tab(Datums, DatumsChar)
            Values (DateAdd(Day, @i, @DatumsNo), Convert(Char(10), DateAdd(Day, @i, @DatumsNo), 104))
        Set @i = @i + 1
    End
    return
End