2016-06-15 105 views
0

我有一家企業出租一種特定產品。我想知道特定地點缺貨時的分鐘數。計算時間戳重疊持續時間

第一個數據集具有交易歷史記錄,包括位置ID,租賃開始時間戳和租賃結束時間戳。

第二個數據集具有當天可用於出租的單元的位置ID,日期和數量。由於經常增加/移除單位,因此單位數量可能會日復一日地變化。

我需要計算每個位置每天有多少分鐘所有可用的單位出租。

例如:地點A在2/1/2016有3個單位。在2/1/2016有多少分鐘(如果有的話)是否有3個單位同時出租?

SQL是我需要使用的語言。

見試樣數據集合下面Y:下面

LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS 

A 30Jan2016 19:54:37.000 01Feb2016 10:00:24.053 

A 31Jan2016 16:30:23.000 01Feb2016 9:07:06.588 

A 01Feb2016 9:22:22.000 02Feb2016 10:00:23.716 

A 01Feb2016 9:36:11.000 01Feb2016 11:05:34.249 

A 01Feb2016 10:27:34.000 01Feb2016 12:59:29.883 

A 01Feb2016 10:40:38.000 01Feb2016 15:36:27.119 

A 01Feb2016 12:43:10.000 01Feb2016 14:23:15.914 

A 01Feb2016 13:28:20.000 01Feb2016 14:40:15.573 

A 01Feb2016 17:03:13.000 01Feb2016 19:02:57.413 

A 01Feb2016 17:17:12.000 01Feb2016 18:54:14.708 

樣品數據組Z:

LOC_ID, Date, Unit_Count 

A 01Feb2016 3 

A 02Feb2016 4 

A 03Feb2016 3 

B 01Feb2016 2 

B 02Feb2016 2 

B 03Feb2016 2 

由於位置A在2月1日3個總單元然後期望的輸出爲25分鐘,這是2月1日同一時間3個單位在地點A出租的總時間。在上午10:40和上午11:05之間,3個單位同時出租。

+0

瑞恩 - 請查看更新的描述,讓我知道,如果這有助於。謝謝! –

+0

你試過我的解決方案嗎? – Shago

回答

0

下面是一些T-SQL代碼(你沒有表明自己選用的DBMS)

-- DECLARING SAMPLE DATA 
DECLARE @Z table (LOC_ID char, Date date, Unit_Count int) 

INSERT @Z (LOC_ID, Date, Unit_Count) VALUES ('A', '2016-02-01', 3) 
INSERT @Z (LOC_ID, Date, Unit_Count) VALUES ('A', '2016-02-02', 4) 
INSERT @Z (LOC_ID, Date, Unit_Count) VALUES ('A', '2016-02-03', 3) 
INSERT @Z (LOC_ID, Date, Unit_Count) VALUES ('B', '2016-02-01', 2) 
INSERT @Z (LOC_ID, Date, Unit_Count) VALUES ('B', '2016-02-02', 2) 
INSERT @Z (LOC_ID, Date, Unit_Count) VALUES ('B', '2016-02-03', 2) 

DECLARE @Y table (LOC_ID char, ACT_RNTL_BGN_TS datetime, ACT_RNTL_END_TS datetime) 

INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-01-30 19:54:37.000', '2016-02-01 10:00:24.053') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-01-31 16:30:23.000', '2016-02-01 09:07:06.588') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-02-01 09:22:22.000', '2016-02-02 10:00:23.716') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-02-01 09:36:11.000', '2016-02-01 11:05:34.249') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-02-01 10:27:34.000', '2016-02-01 12:59:29.883') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-02-01 10:40:38.000', '2016-02-01 15:36:27.119') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-02-01 12:43:10.000', '2016-02-01 14:23:15.914') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-02-01 13:28:20.000', '2016-02-01 14:40:15.573') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-02-01 17:03:13.000', '2016-02-01 19:02:57.413') 
INSERT @Y (LOC_ID, ACT_RNTL_BGN_TS, ACT_RNTL_END_TS) VALUES ('A', '2016-02-01 17:17:12.000', '2016-02-01 18:54:14.708') 
; 

-- START OF QUERY 
WITH SplittedRentedIntervals AS (-- Intervals that span more than one day are splited. 
    SELECT Z.LOC_ID 
     , Z.Date 
     , BGN = CASE WHEN Y.ACT_RNTL_BGN_TS > CAST(Z.Date AS datetime) THEN Y.ACT_RNTL_BGN_TS ELSE CAST(Z.Date AS datetime) END 
     , [END] = CASE WHEN Y.ACT_RNTL_END_TS < CAST(DATEADD(DAY, 1, Z.Date) AS datetime) THEN Y.ACT_RNTL_END_TS ELSE CAST(DATEADD(DAY, 1, Z.Date) AS datetime) END 
    FROM @Z Z 
    JOIN @Y Y 
    ON Y.LOC_ID = Z.LOC_ID 
    AND (Z.Date = CAST(Y.ACT_RNTL_BGN_TS AS date) 
     OR Z.Date = CAST(Y.ACT_RNTL_END_TS AS date) 
     OR (Z.Date BETWEEN Y.ACT_RNTL_BGN_TS AND Y.ACT_RNTL_END_TS)) 
), Times AS (-- All times starting and ending any interval, including start and end of day. 
      SELECT DISTINCT LOC_ID, Date, TIME = BGN FROM SplittedRentedIntervals 
    UNION SELECT DISTINCT LOC_ID, Date, TIME = [END] FROM SplittedRentedIntervals 
    UNION SELECT LOC_ID, Date, TIME = CAST(Date AS datetime) FROM @Z 
    UNION SELECT LOC_ID, Date, TIME = CAST(DATEADD(DAY, 1, Date) AS datetime) FROM @Z 
), OrderedTimes AS (
    SELECT LOC_ID 
     , Date 
     , TIME 
     , NUM = ROW_NUMBER() OVER (PARTITION BY LOC_ID, Date ORDER BY TIME ASC) 
    FROM Times 
), Intervals AS (-- Intervals are conformed by two consecutives times. 
    SELECT OT1.LOC_ID 
     , OT1.Date 
     , BGN = OT1.TIME 
     , [END] = OT2.TIME 
    FROM OrderedTimes OT1 
    JOIN OrderedTimes OT2 
    ON OT2.LOC_ID = OT1.LOC_ID 
    AND OT2.Date = OT1.Date 
    AND OT2.NUM = OT1.NUM + 1 
), StockByInterval AS (-- Intersect all time intervals with rented intervals to calculate rented units. 
    SELECT I.LOC_ID 
     , I.Date 
     , I.BGN 
     , I.[END] 
     , STOCK = Z.Unit_Count 
       - (SELECT COUNT(*) 
        FROM SplittedRentedIntervals SRI 
        WHERE I.Date = SRI.Date 
        AND I.LOC_ID = SRI.LOC_ID 
        AND SRI.BGN < I.[END] 
        AND SRI.[END] > I.BGN) 
    FROM Intervals I 
    JOIN @Z Z 
    ON Z.Date = I.Date 
    AND Z.LOC_ID = I.LOC_ID 
), WithuotStock AS (-- Sum the minutes of intervals where there is no stock. 
    SELECT LOC_ID 
     , Date 
     , MinutesWithoutStock = SUM(DATEDIFF(MINUTE, BGN, [END])) 
    FROM StockByInterval 
    WHERE STOCK <= 0 -- Sample data has some intervals where there are more items rented than are available. 
    GROUP BY LOC_ID, Date 
) 
SELECT Z.LOC_ID 
    , Z.Date 
    , MinutesWithoutStock = ISNULL(WS.MinutesWithoutStock, 0) 
FROM @Z Z 
LEFT JOIN WithuotStock WS 
ON WS.Date = Z.Date 
AND WS.LOC_ID = Z.LOC_ID 
ORDER BY Z.LOC_ID, Z.Date 

樣本輸出

LOC_ID Date  MinutesWithoutStock 
------ ---------- ------------------- 
A  2016-02-01 374 
A  2016-02-02 0 
A  2016-02-03 0 
B  2016-02-01 0 
B  2016-02-02 0 
B  2016-02-03 0