在多天内为结果创建多行

时间:2018-10-11 13:01:37

标签: sql sql-server split

我有一个简单的查询,以返回计划文件中尚未结束的所有行。

SELECT [Run_ID]
      ,[ProductionLineID]
      ,[RecipeNR]
      ,[RecipeDesc]
      ,[StartTimeBakery]
      ,[EndTimeBakery]
      ,[ItemID]
      ,[ItemDesc]
      ,[Boxes]
      ,[Products_In_Box]
      ,[Products]
      ,[Pallets]
      ,[Boxes_On_Pallet]
      ,[AUD_Timestamp]
  FROM [PP_Planning].[dbo].[Planning]

  Where endTimeBakery > GETDATE()

  order by ProductionLineID, StartTimeBakery

简化的示例结果:

StartTimeBakery           EndTimeBakery             Pallets
2018-10-12 03:00:00.000   2018-10-12 21:41:00.000   135
2018-10-12 22:00:00.000   2018-10-13 22:13:00.000   300
2018-10-13 23:59:00.000   2018-10-15 05:23:00.000   315

我要查找的是starttime-endtime跨越一天以上时的自动拆分。

想要的输出:

StartTimeBakery           EndTimeBakery             Pallets
2018-10-12 03:00:00.000   2018-10-12 21:41:00.000   135,00
2018-10-12 22:00:00.000   2018-10-12 23:59:59.999   24,77
2018-10-13 00:00:00.000   2018-10-13 22:13:00.000   275,22
2018-10-13 23:59:00.000   2018-10-13 23:59:59.999   0,18
2018-10-14 00:00:00.000   2018-10-14 23:59:59.999   257,14
2018-10-15 00:00:00.000   2018-10-15 05:23:00.000   57,68

推理/逻辑 我希望能够显示每天生产(计划)的托盘数量。在上面想要的结果中,我已将原始总金额除以开始和停止之间使用的时间,然后将其分配给每天计划的时间。

我不知道从哪里开始“拆分”。因此,我们将不胜感激。

4 个答案:

答案 0 :(得分:1)

如果未指定日期范围,则可以使用递归来拆分源并获取计算比例所需的值。参见以下演示:

DECLARE @table TABLE (StartTimeBakery DATETIME2(3), EndTimeBakery DATETIME2(3), Pallets INT);
INSERT INTO @table VALUES ('2018-10-12 03:00:00.000','2018-10-12 21:41:00.000',135);
INSERT INTO @table VALUES ('2018-10-12 22:00:00.000','2018-10-13 22:13:00.000',300);
INSERT INTO @table VALUES ('2018-10-13 23:59:00.000','2018-10-15 05:23:00.000',315);

WITH Split AS
(
    SELECT *, 0 N, DATEDIFF(DAY, StartTimeBakery, EndTimeBakery) Diff FROM @table
    UNION ALL
    SELECT StartTimeBakery,EndTimeBakery,Pallets,N+1,Diff FROM Split WHERE N<Diff
), SplitDates AS
(
    SELECT
        StartTimeBakery,
        EndTimeBakery,
        Pallets,
        CASE WHEN N=0 THEN StartTimeBakery ELSE DATEADD(DAY,N, CAST(StartTimeBakery AS Date)) END MyStart,
        CASE WHEN N=Diff THEN EndTimeBakery ELSE DATEADD(MILLISECOND, -1, CAST(DATEADD(DAY,N+1, CAST(StartTimeBakery AS Date)) AS datetime2(3))) END MyEnd,
        N,
        Diff
    FROM Split
), Proportions AS
(
    SELECT *, DATEDIFF(millisecond, MyStart, MyEnd) ThisMs, SUM(DATEDIFF(millisecond, MyStart, MyEnd)) OVER (PARTITION BY StartTimeBakery) GroupMs
    FROM SplitDates
)
SELECT MyStart StartTimeBakery, MyEnd EndTimeBakery, CAST(1.0*Pallets*ThisMs/GroupMs as decimal(15,2)) Pallets
FROM Proportions
ORDER BY MyStart

结果

StartTimeBakery             EndTimeBakery               Pallets
--------------------------- --------------------------- ---------
2018-10-12 03:00:00.000     2018-10-12 21:41:00.000     135.00
2018-10-12 22:00:00.000     2018-10-12 23:59:59.999     24.78
2018-10-13 00:00:00.000     2018-10-13 22:13:00.000     275.22
2018-10-13 23:59:00.000     2018-10-13 23:59:59.999     0.18
2018-10-14 00:00:00.000     2018-10-14 23:59:59.999     257.14
2018-10-15 00:00:00.000     2018-10-15 05:23:00.000     57.68

答案 1 :(得分:1)

这也可以通过递归CTE完成

示例片段:

declare @Table table (
 RunID int identity(1,1) primary key, 
 StartTimeBakery datetime, 
 EndTimeBakery datetime, 
 Pallets int
);

insert into @Table (StartTimeBakery, EndTimeBakery, Pallets) values
 (DATEADD(day,DATEDIFF(day,-1, GETDATE()),'03:00'), DATEADD(day,DATEDIFF(day,-1, GETDATE()),'21:41'), 135)
,(DATEADD(day,DATEDIFF(day,-1, GETDATE()),'22:00'), DATEADD(day,DATEDIFF(day,-2, GETDATE()),'22:13'), 300)
,(DATEADD(day,DATEDIFF(day,-2, GETDATE()),'23:59'), DATEADD(day,DATEDIFF(day,-4, GETDATE()),'05:23'), 315)
;


with RCTE as
(
    select 
    RunID, 
    StartTimeBakery as BaseStartTime, EndTimeBakery as BaseEndTime, Pallets as BasePallets,
    0 as Lvl, 
    StartTimeBakery as StartTime, 
    case 
    when cast(StartTimeBakery as date) =  cast(EndTimeBakery as date)
    then EndTimeBakery 
    else CONVERT(DATETIME,DATEADD(MILLISECOND, -10, DATEADD(DAY, 1, CONVERT(DATETIME2,CONVERT(DATE, StartTimeBakery))))) 
    end as EndTime, 
    Pallets
    from @Table
    where EndTimeBakery > GETDATE()

    union all

    select RunID, BaseStartTime, BaseEndTime, BasePallets,
    Lvl+1,
    CONVERT(DATETIME, DATEADD(DAY, 1, CONVERT(DATE,EndTime))),
    case when DATEADD(DAY, 1, EndTime) < BaseEndTime then DATEADD(DAY, 1, EndTime) else BaseEndTime end,
    Pallets
    from RCTE
    where EndTime < BaseEndTime
)
select 
StartTime AS StartTimeBakery,
EndTime AS EndTimeBakery,
CAST(Pallets * (CAST(DATEDIFF(second, StartTime, EndTime) AS FLOAT) / DATEDIFF(second, BaseStartTime, BaseEndTime)) AS DECIMAL(10,2)) as PercDiffMinutes
from RCTE
order by BaseStartTime, StartTime;

答案 2 :(得分:0)

仅进行一次拆分(例如,第二天的最大超车期,您可以尝试类似

WITH FORE as 
    (
    Select *, 
           StartTimeBakery StartTime1, 
           CASE WHEN CAST(EndTimeBakery as date) = CAST(StartTimeBakery as date) THEN 
                   EndTimeBakery 
                ELSE DATEADD(ms,-1,CAST(CAST(EndTimeBakery as date) 
                                                     as datetime)) END AS EndTime1
    ),
    AFTER as
    (
    Select *, 
          CAST(CAST(EndTimeBakery as date) as datetime) StartTime1,
          EndTimeBakery EndTime1  
                    WHERE CAST(EndTimeBakery as date) = CAST(StartTimeBakery as date)
    ),
    SPLITS AS 
    (
            SELECT * FROM FORE 
              UNION ALL 
               SELECT * FROM AFTER
    )

    SELECT * FROM SPLITS;

为便于说明,请选择所有轮班开始时间,结束时间仅限于一天结束时(如果轮班在此之前结束,则更早) 然后,选择在午夜运行的记录集,从00:00开始,在结束时间结束,然后将它们合并在一起。

如何选择在这些因素之间分配其他因素,您需要解决

答案 3 :(得分:0)

快速构建的东西,虽然不是很花哨的sql,但它可以工作。

    DECLARE @table TABLE (StartTime DATETIME, EndTime DATETIME, Qty INT)

INSERT INTO @table VALUES ('2018-10-12 03:00:00.000','2018-10-12 21:41:00.000',135)
INSERT INTO @table VALUES ('2018-10-12 22:00:00.000','2018-10-13 22:13:00.000',300)
INSERT INTO @table VALUES ('2018-10-13 23:59:00.000','2018-10-15 05:23:00.000',315)

SELECT StartTime, EndTime, Qty
  FROM @table
 WHERE DATEDIFF(DAY,StartTime,EndTime) = 0
UNION ALL
SELECT StartTime, DATEADD(SECOND,-1,DATEADD(dd,DATEDIFF(dd,0,StartTime)+1,0)), Qty*(CAST(DATEDIFF(SECOND,StartTime,DATEADD(SECOND,-1,DATEADD(dd,DATEDIFF(dd,0,StartTime)+1,0))) AS FLOAT)/CAST(DATEDIFF(SECOND,StartTime, EndTime) AS FLOAT))
  FROM @table
 WHERE DATEDIFF(DAY,StartTime,EndTime) <> 0
UNION ALL
SELECT DATEADD(dd,DATEDIFF(dd,0,EndTime),0), EndTime, Qty*(CAST(DATEDIFF(SECOND,DATEADD(dd,DATEDIFF(dd,0,EndTime),0),EndTime) AS FLOAT)/CAST(DATEDIFF(SECOND,StartTime, EndTime) AS FLOAT))
  FROM @table
 WHERE DATEDIFF(DAY,StartTime,EndTime) <> 0