查找SQL Server中某个时间范围内某些特殊项的计数

时间:2018-03-13 10:06:47

标签: sql sql-server

想象一下,有人执行任务,组织应该在执行任务期间支付他的膳食费用,但不能在此之后支付费用,例如,如果他在早上8点之后开始执行任务,他将无法获得任何支付。 如果他在晚上9点之后完成任务,这将是相同的,这不是晚餐时间,午餐时间结束于12:00

这里有桌子:

ID  Date        DepartureTime              breakfast  Lunch  Dinner
1   2018-03-13  2018-03-13 13:12:32.000    True       False  True
2   2018-03-14  NULL                       True       True   False
3   2018-03-15  NULL                       False      True   True
4   2018-03-16  NULL                       True       True   False
5   2018-03-17  2018-03-17 13:00:00.000    False      True   True

我需要一个查询,我可以计算出有资格获得支付的膳食数量,

我认为应该通过创建时间范围并使用CASE WHEN

来解决

这里真实意味着他吃了那顿饭,虚假意味着他没有吃饭。 答案应该是:

早餐:2;午餐:4;晚餐:2

2 个答案:

答案 0 :(得分:1)

enter image description here

SELECT *
,B=CASE WHEN (cast(DepartureTime AS time) between '00:00:00' AND '08:00:00' OR DepartureTime IS NULL) AND [Breakfast]='True'  THEN 1 END
,L=CASE WHEN (cast(DepartureTime AS time) between '08:00:01' AND '13:00:00' OR DepartureTime IS NULL) AND [Lunch]='True'  THEN 1 END
,D=CASE WHEN (cast(DepartureTime AS time) between '13:00:01' AND '20:00:00' OR DepartureTime IS NULL) AND [Dinner]='True'  THEN 1 END
FROM MissionToEat

fiddle

答案 1 :(得分:0)

1)将每餐与时间间隔(或只是确切的时间)联系起来。例如:

  • 早餐:早上8点至上午10点
  • 午餐:从早上12点到下午2点
  • 晚餐:晚上7点至晚上10点

此处示例:

IF OBJECT_ID('tempdb..#MealTime') IS NOT NULL
    DROP TABLE #MealTime

CREATE TABLE #MealTime (
    Meal VARCHAR(100),
    StartTime TIME,
    EndTime TIME)

INSERT INTO #MealTime (
    Meal,
    StartTime,
    EndTime)
SELECT
    Meal = 'Breakfast',
    StartTime = '08:00',
    EndTime = '10:00'
UNION ALL
SELECT
    Meal = 'Lunch',
    StartTime = '12:00',
    EndTime = '14:00'
UNION ALL
SELECT
    Meal = 'Dinner',
    StartTime = '19:00',
    EndTime = '22:00'

2)确定DepartureTime是否代表每一行的开头或结尾,并创建时间间隔以使步骤3)更容易:

;WITH Limits AS
(
    SELECT
        MinimumID = MIN(M.ID),
        MaximumID = MAX(M.ID)
    FROM
        OperationDetails AS M
)
SELECT
    M.*,
    StartTime = CONVERT(TIME,
        CASE 
            WHEN L1.MinimumID IS NOT NULL THEN M.DepartureTime
            ELSE '00:00' END),
    EndTime = CONVERT(TIME,
        CASE 
            WHEN L2.MaximumID IS NOT NULL THEN M.DepartureTime
            ELSE '23:59' END)
FROM
    OperationDetails AS M
    LEFT JOIN Limits AS L1 ON M.ID = L1.MinimumID
    LEFT JOIN Limits AS L2 ON M.ID = L2.MaximumID

3)如果每餐都被吃掉并且时间重叠,则计算每餐:

;WITH Limits AS
(
    SELECT
        MinimumID = MIN(M.ID),
        MaximumID = MAX(M.ID)
    FROM
        OperationDetails AS M
),
MissionTimes AS
(
    SELECT
        M.*,
        StartTime = CONVERT(TIME,
            CASE 
                WHEN L1.MinimumID IS NOT NULL THEN M.DepartureTime
                ELSE '00:00' END),
        EndTime = CONVERT(TIME,
            CASE 
                WHEN L2.MaximumID IS NOT NULL THEN M.DepartureTime
                ELSE '23:59' END)
    FROM
        OperationDetails AS M
        LEFT JOIN Limits AS L1 ON M.ID = L1.MinimumID
        LEFT JOIN Limits AS L2 ON M.ID = L2.MaximumID
)
SELECT
    AmountBreakfastToPay = COUNT(CASE WHEN M.Breakfast = 'true' AND M.StartTime <= BR.EndTime AND M.EndTime >= BR.StartTime THEN 1 END),
    AmountLunchToPay = COUNT(CASE WHEN M.Lunch = 'true' AND M.StartTime <= LU.EndTime AND M.EndTime >= LU.StartTime THEN 1 END),
    AmountDinnerToPay = COUNT(CASE WHEN M.Dinner = 'true' AND M.StartTime <= DI.EndTime AND M.EndTime >= DI.StartTime THEN 1 END)
FROM
    MissionTimes AS M
    INNER JOIN #MealTime AS BR ON BR.Meal = 'Breakfast'
    INNER JOIN #MealTime AS LU ON LU.Meal = 'Lunch'
    INNER JOIN #MealTime AS DI ON DI.Meal = 'Dinner'