从日期范围内的表中选择所有日期,并且每个空日期包括1行

时间:2012-01-19 12:37:31

标签: sql sql-server-2008 stored-procedures

我正在尝试重构ASP.Net网站中的一些代码,并且遇到了我正在编写的存储过程的问题。

我想要做的是获取日期范围,然后从表格中选择该范围内的所有数据但是如果日期不存在我还需要选择一行。

我在下面的代码中看到的这个想法是创建一个临时表,并用我日期范围内的所有日期填充它,然后将其加入到我选择的表中但是这不起作用。我在这里做错了吗? tempDate列在此连接中始终为null,但是我已经检查了该表,并且它确实包含数据。

-- Parameters
DECLARE @DutyDate datetime='2012-01-01 00:00:00'
DECLARE @InstructorID nvarchar(2) = N'29'

DECLARE @datesTBL TABLE (tempDate DATETIME)

-- Variables
DECLARE @StartDate DATETIME 
DECLARE @EndDate DATETIME

SELECT 
    @StartDate =StartDate, 
    @EndDate = EndDate
FROM 
    DutyPeriodTbl 
WHERE 
(StartDate <= @DutyDate) 
AND 
(EndDate >= @DutyDate)


DECLARE @d DATETIME = @StartDate 
WHILE @d<=@EndDate
BEGIN
    INSERT INTO @datesTBL VALUES (CONVERT(DATETIME, @d, 102))
    SET @d=DATEADD(day,1,@d)
END

SELECT 
    dt.tempDate ,
    InstructorID,           EventStart, 
    EventEnd,               cancelled, 
    cancelledInstructor, 
    EventType,              DevName, 
    Room,                   SimLocation, 
    ClassLocation,          Event, 
    Duration,               TrainingDesc, 
    Crew,                   Notes, 
    LastAmended,            InstLastAmended, 
    ChangeAcknowledged,     Type, 
    OtherType,              OtherTypeDesc, 
    CourseType 
FROM 
    OpsInstructorEventsView iv
LEFT OUTER JOIN
    @datesTBL dt 
ON
    CONVERT(DATETIME, iv.EventStart, 102) = CONVERT(DATETIME, dt.tempDate, 102) 
WHERE 
    InstructorID = @InstructorID 
AND 
    EventStart BETWEEN CONVERT(DATETIME, @StartDate, 102) AND CONVERT(DATETIME, @EndDate, 102)
ORDER BY 
    EventStart 

2 个答案:

答案 0 :(得分:3)

有几种方法可以处理丢失的行,但所有这些方法都是为了让另一组数据与当前结果相结合。

这可能来自您的结果,由CTE或其他流程(例如您的示例)或(我的偏好)创建,使用永久模板加入。

您案例中的模板可能只是一个日期表,就像您的@datesTBL一样。不同之处在于它是事先创建的,例如,100年的日期。

您的查询可能与您的示例类似,但我会尝试以下内容...

SELECT 
    dt.tempDate ,
    InstructorID,           EventStart, 
    EventEnd,               cancelled, 
    cancelledInstructor, 
    EventType,              DevName, 
    Room,                   SimLocation, 
    ClassLocation,          Event, 
    Duration,               TrainingDesc, 
    Crew,                   Notes, 
    LastAmended,            InstLastAmended, 
    ChangeAcknowledged,     Type, 
    OtherType,              OtherTypeDesc, 
    CourseType 
FROM 
  @datesTBL dt 
LEFT OUTER JOIN
  OpsInstructorEventsView iv
    ON  iv.EventStart >= dt.tempDate
    AND iv.EventStart <  dt.tempDate + 1
    AND iv.InstructorID = @InstructorID 
WHERE
      dt.tempDate >= @StartDate
  AND dt.tempDate <= @EndDate
ORDER BY
  dt.tempDate,
  iv.EventStart

这会将日历模板放在LEFT上,因此您可以更轻松地查询许多查询,因为您知道日历的日期字段始终填充,始终是仅日期(无时间部分)值,是订单,对GROUP BY等很简单

答案 1 :(得分:0)

嗯,想法是一样的,但我会编写函数,返回包含句点中所有日期的表。看看这个:

Create Function [dbo].[Interval]
(
    @DateFrom Date,
    @DateTo Date
)
Returns @tab Table
    (
        MyDate DateTime
    )
As
Begin
    Declare @Days int
    Declare @i int
    Set @Days = DateDiff(Day, @DateFrom, @DateTo)

    Set @i = 0;
    While (@Days > @i)
    Begin
        Insert Into @tab(MyDate)
            Values (DateAdd(Day, @i, @DateTo))
        Set @i = @i + 1
    End
    return
End

并在需要时重复使用该功能..

Select *
From [dbo].[Interval]('2011-01-01', GETDATE())