在表格中的日期范围与其他数据

时间:2016-08-29 16:53:14

标签: sql-server

对于培训课程,用户在主表startdt, enddt, time range, requester name中插入cal_tr_requests等信息。如果培训时间超过一天,enddt将在startdt之后。我创建了另一个表cal_tr_Multidate以插入所有日期classId和主表的时间范围。因此,如果cal_tr_requests输入此内容:

ClassID -- req_start_Date---req_end_date ---req_time--requsetor_name
1234567    2016-08-30        2016-08-31    8:00-10:00  test

然后cal_tr_Multidates表将输入:

ClassID --- ReserveDt ---- ReserveTm
1234567     2016-08-30     8:00-10:00
1234567     2016-08-31     8:00-10:00

我在使用循环创建存储过程时遇到问题。这就是我所拥有的:

Alter PROCEDURE [dbo].[AddTrainingRoomRq_test]

@req_start_date DateTime,
@req_end_date DateTime,
@req_times text,
@requestor_name text

AS
BEGIN

Declare 

@ClassID int,
@Multidates int
--Create the ClassID as a random number
Set @ClassID =  (SELECT CAST(RAND() * 1000000000 AS INT) AS [RandomNumber])

INSERT INTO cal_tr_requests
           (ClassID, req_start_date, req_end_date, req_times, requestor_name, date_of_req)
VALUES        (@ClassID,@req_start_date,@req_end_date,@req_times,@requestor_name,getdate())

set @Multidates = (select datediff(d, req_start_date, req_end_date)
                    from cal_tr_requests
                    where ClassID =  @ClassID)

if @Multidates = 0
Insert into Cal_tr_Multidates (ClassID, ReserveDt,ReserveTm)
               Values(@ClassID, @req_start_date, @req_times)

else if  @Multidates > 0
 While @Multidates = 0
 begin

--do the insert for all dates with classid and reserveTm

End
END

有人可以指出我正确的方向吗? 提前谢谢。

2 个答案:

答案 0 :(得分:1)

我的目的不是为您提供针对您的具体问题的完整解决方案,而是为了展示您应该能够实施以解决您的挑战的校长。

此站点上发布的许多t-sql解决方案确实有效,但它们通常无法扩展。我可以修复你的循环以使其工作,但用t-sql来解决这个问题并不是一个好方法。可扩展的t-sql是基于集合的,而不是程序性的。

这是一个基于集合的方法的示例,用于获取两个其他日期之间的所有日期:

DECLARE @dateBegin DATE = '20160830';
DECLARE @dateEnd DATE = '20160905';

WITH E1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))     AS t(N))
    ,E2 AS (SELECT N = 1 FROM E1 AS a, E1 AS b)
    ,E4 AS (SELECT N = 1 FROM E2 AS a, E2 AS b)
    ,E8 AS (SELECT N = 1 FROM E4 AS a, E4 AS b)
    ,cteTally AS (SELECT N = 0 UNION ALL
                SELECT N = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM     E8)
SELECT includedDates = DATEADD(DAY, cte.N, '20000101')
FROM cteTally AS cte
WHERE cte.N >= DATEDIFF(DAY, '20000101', @dateBegin)
    AND cte.N <= DATEDIFF(DAY, '20000101', @dateEnd);

您在此处看到的大部分代码都是构建内联计数表。您可以使用数据库中的静态数字表执行相同的操作,这对于重用很有用,但在性能方面不会产生太大差异。

在任何情况下,我们在这里做的事情都会避免循环(对于SQL Server而言不合适),而是使用一组简单的数据来确定我们的日期。

祝你好运。

答案 1 :(得分:0)

以下是处理日期的递归CTE示例:

DECLARE @req_start_date DateTime,
        @req_end_date DateTime

SET @req_start_date = '2016-08-15'
SET @req_end_date = '2016-08-31'

;WITH X AS 
    (
        SELECT @req_start_date AS VAL
        UNION ALL
        SELECT DATEADD(DD,1,VAL) FROM X
        WHERE VAL < @req_end_date
    )

SELECT *
FROM X
OPTION(MAXRECURSION 0)

这里是你的proc(摆脱了Sean上面所说的text类型),并且不需要@multidates if/else块作为start=end日期:

时,CTE只会返回1行
ALTER PROCEDURE [dbo].[AddTrainingRoomRq_test]
(
@req_start_date DateTime,
@req_end_date DateTime,
@req_times VARCHAR(100),
@requestor_name VARCHAR(100)
)
AS
BEGIN
    DECLARE @ClassID INT

    --Create the ClassID as a random number
    Set @ClassID =  (SELECT CAST(RAND() * 1000000000 AS INT) AS [RandomNumber])

    INSERT INTO cal_tr_requests (ClassID, req_start_date, req_end_date, req_times, requestor_name, date_of_req)
    VALUES (@ClassID,@req_start_date,@req_end_date,@req_times,@requestor_name,getdate())

    ;WITH X AS 
    (
        SELECT @req_start_date AS VAL
        UNION ALL
        SELECT DATEADD(DD,1,VAL) FROM X
        WHERE VAL < @req_end_date
    )

    INSERT INTO Cal_tr_Multidates (ClassID, ReserveDt,ReserveTm)    
    SELECT @ClassID, VAL, @req_times
    FROM X
    OPTION(MAXRECURSION 0)

END