如何比较SQL Server中的时隙?

时间:2014-11-16 15:15:23

标签: sql-server

我有一张表[pricelist]

startHour
endHour
Price

和另一个包含[actualuse]

的表格
startDate
endDate
user

我的数据

pricelist

startHour | endHour | price
----------------------------
00:00     | 07:59   | 10
08:00     | 15:59   | 20
16:00     | 23:59   | 5

actualUse

startDate        | endDate         | jobId
-------------------------------------------
12/10/2014 08:30 | 12/10/2014 15:20| 1
12/10/2014 07:30 | 12/10/2014 18:20| 2
12/10/2014 07:30 | 13/10/2014 16:20| 3
12/10/2014 09:30 | 13/10/2014 00:20| 4

我试图获取每个gob所有属于pricelist的行。例如,对于jobId 1,我将获得

startDate        | endDate         | jobId  |price
---------------------------------------------------
12/10/2014 08:30 | 12/10/2014 15:20| 1      |20

for jobId 2

startDate        | endDate         | jobId  |price
---------------------------------------------------
12/10/2014 07:30 | 12/10/2014 07:59| 2      |10    
12/10/2014 08:00 | 12/10/2014 15:59| 2      |20
12/10/2014 16:00 | 12/10/2014 18:20| 2      |5

for jobId 3

startDate        | endDate         | jobId  |price
---------------------------------------------------
12/10/2014 07:30 | 12/10/2014 07:59| 3      |10
12/10/2014 08:00 | 12/10/2014 15:59| 3      |20
12/10/2014 16:00 | 12/10/2014 23:59| 3      |5
13/10/2014 00:00 | 13/10/2014 07:59| 3      |10
13/10/2014 08:00 | 13/10/2014 15:59| 3      |20
13/10/2014 16:00 | 13/10/2014 16:20| 3      |5

1 个答案:

答案 0 :(得分:1)

这是一个可行的解决方案。我知道光标有点难看,但我不得不创建另一个表,日期范围之间的每个可能日期。你也许能够重构一些日期计算(我假设你正在使用TIME数据类型)

/*
create table pricelist
(
    startHour time,
    endHour time,
    price decimal(18,2)
)

create table actualuse
(
    startDate datetime,
    endDate datetime,
    jobId int
)

insert pricelist values
('00:00','07:59',10),
('08:00','15:59',20),
('16:00','23:59',5)

set dateformat dmy
insert actualuse values
('12/10/2014 08:30','12/10/2014 15:20',1),
('12/10/2014 07:30','12/10/2014 18:20',2),
('12/10/2014 07:30','13/10/2014 16:20',3),
('12/10/2014 09:30','13/10/2014 00:20',4)

*/

BEGIN TRY DROP TABLE #actualUseDays END TRY
BEGIN CATCH END CATCH

CREATE TABLE #actualUseDays (
    startDate DATETIME
    ,endDate DATETIME
    ,jobId INT
    )

DECLARE @startDate DATETIME
    ,@endDate DATETIME
    ,@jobId INT;

DECLARE cur CURSOR FORWARD_ONLY FOR SELECT * FROM actualuse

OPEN cur;

FETCH NEXT FROM cur INTO @startDate ,@endDate ,@jobId

WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT #actualUseDays
    SELECT @startDate
        ,iif(CAST(@endDate AS DATE) <> CAST(@startDate AS DATE), DATEADD(day, DATEDIFF(day, '19000101', cast(@startDate AS DATE)), CAST(CAST('23:59:59' AS TIME) AS 
                    DATETIME2(7))), @endDate)
        ,@jobId

    UNION

    SELECT CAST(DATEADD(DAY, number + 1, @startDate) AS DATE) [Date]
        ,iif(CAST(@endDate AS DATE) <> CAST(DATEADD(DAY, number + 1, @startDate) AS DATE), DATEADD(day, DATEDIFF(day, '19000101', CAST(DATEADD(DAY, number + 1, 
                            @startDate) AS DATE)), CAST(CAST('23:59:59' AS TIME) AS DATETIME2(7))), @endDate)
        ,@jobId
    FROM master..spt_values
    WHERE type = 'P'
        AND DATEADD(DAY, number + 1, CAST(@startDate AS DATE)) < @endDate

    FETCH NEXT FROM cur INTO @startDate ,@endDate ,@jobId
END

CLOSE cur;
DEALLOCATE cur;

/*
#actualUseDays now contains : 

startDate               endDate                 jobId
----------------------- ----------------------- -----------
2014-10-12 08:30:00.000 2014-10-12 15:20:00.000 1
2014-10-12 07:30:00.000 2014-10-12 18:20:00.000 2
2014-10-12 07:30:00.000 2014-10-12 23:59:59.000 3
2014-10-13 00:00:00.000 2014-10-13 16:20:00.000 3
2014-10-12 09:30:00.000 2014-10-12 23:59:59.000 4
2014-10-13 00:00:00.000 2014-10-13 00:20:00.000 4
*/

SELECT iif(CAST(a.startDate AS TIME) > p.startHour, startDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(startDate AS DATE)), CAST(startHour AS DATETIME2(7)))) AS 
    startDate
    ,iif(CAST(a.endDate AS TIME) < p.endHour, endDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(endDate AS DATE)), CAST(endHour AS DATETIME2(7)))) AS endDate
    ,jobId
    ,price
FROM #actualUseDays a
INNER JOIN pricelist p
    ON CAST(a.startDate AS TIME) <= p.endHour
        AND CAST(a.endDate AS TIME) >= p.startHour
ORDER BY jobId
    ,iif(CAST(a.startDate AS TIME) > p.startHour, startDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(startDate AS DATE)), CAST(startHour AS DATETIME2(7))))

结果:

startDate                   endDate                     jobId       price
--------------------------- --------------------------- ----------- ---------------------------------------
2014-10-12 08:30:00.0000000 2014-10-12 15:20:00.0000000 1           20.00
2014-10-12 07:30:00.0000000 2014-10-12 07:59:00.0000000 2           10.00
2014-10-12 08:00:00.0000000 2014-10-12 15:59:00.0000000 2           20.00
2014-10-12 16:00:00.0000000 2014-10-12 18:20:00.0000000 2           5.00
2014-10-12 07:30:00.0000000 2014-10-12 07:59:00.0000000 3           10.00
2014-10-12 08:00:00.0000000 2014-10-12 15:59:00.0000000 3           20.00
2014-10-12 16:00:00.0000000 2014-10-12 23:59:00.0000000 3           5.00
2014-10-13 00:00:00.0000000 2014-10-13 07:59:00.0000000 3           10.00
2014-10-13 08:00:00.0000000 2014-10-13 15:59:00.0000000 3           20.00
2014-10-13 16:00:00.0000000 2014-10-13 16:20:00.0000000 3           5.00
2014-10-12 09:30:00.0000000 2014-10-12 15:59:00.0000000 4           20.00
2014-10-12 16:00:00.0000000 2014-10-12 23:59:00.0000000 4           5.00
2014-10-13 00:00:00.0000000 2014-10-13 00:20:00.0000000 4           10.00