繁体   English   中英

如何为开始日期和结束日期之间的每个工作日创建多行

[英]How to create multiple rows for every workingday between an start and end date

我想为我的开始日期和结束日期之间的每个工作日创建一行。 这样就可以将生产量分配到实际周,而不仅仅是开始周。

我现在所拥有的:

SELECT DISTINCT
      PH.ProdHeaderOrdNr,
      PH.ProdstatusCode,
      PH.partcode,
      PH.description,
      PBOM.subpartcode,
      PBOM.description as N'Description subpart',
      PBOO.qty,
      PBOO.producedqty,
      PBOO.machcycletime,
      PBOO.qty-PBOO.producedqty as N'to produce',
      case when(PBOO.qty-PBOO.producedqty)*(1+(convert(decimal(4,2),PBOM.waste)/100))<=0 
           then 0 
           else (PBOO.qty-PBOO.producedqty)*(1+(convert(decimal(4,2),PBOM.waste)/100)) 
           end as N'amount subpart needed',
      (DATEDIFF(dd, PBOO.startdate, PBOO.enddate) + 1)
              -(DATEDIFF(wk, PBOO.startdate, PBOO.enddate) * 2)
              -(CASE WHEN DATENAME(dw, PBOO.startdate) = 'Sunday' THEN 1 ELSE 0 END)
              -(CASE WHEN DATENAME(dw, PBOO.enddate) = 'Saturday' THEN 1 ELSE 0 END)
              As NoOfWeekDays,
      case when PBOO.machcycletime *((PBOO.qty-PBOO.producedqty)/PBOO.qty)/3600<=0 
           then 0 
           else  Round(PBOO.machcycletime *((PBOO.qty-PBOO.producedqty)/PBOO.qty)/3600,2) 
           end as N'hours remaining',
      PBOO.startdate,
      PBOO.enddate,
      datepart(year,PBOO.startdate) as N'Year',
      datepart(isoww,PBOO.startdate) as N'Week'

FROM
         dbo.T_ProductionHeader  AS PH,
         dbo.T_ProdBillofMat as PBOM,
         dbo.T_Part as P,
         dbo.T_ProdBillOfOper as PBOO,
         dbo.T_MachGrp as M

Where
    PH.ProdHeaderDossierCode = PBOM.ProdHeaderDossierCode    AND
    PH.ProdHeaderDossierCode = PBOO.ProdHeaderDossierCode AND
    PBOO.MachGrpCode = M.MachGrpCode AND
    M.DeptCode = '0720' and
    PH.ProdStatusCode BETWEEN 30 and 40 AND
    PBOM.LineNr = '10' and
    left(PH.partcode,1) in ('P', 'H')and
    PBOO.finishedInd = 0

导致:

每个生产订单有 1 行的结果表

我想得到下一个结果:

n 行数,其中 N 等于从开始到结束日期的工作日数,以下列的值分布在这些工作日内

  • “生产”
  • “所需的金额子部分”
  • “剩余小时数”

添加的列

  • “运行日期”(工作日的日期)
  • “运行年份”(运行日期的年份)
  • “运行周”(运行日期的等周)

我删除了“NoOfWeekDays”列

每个生产订单的行数为 N 的结果表

我试图创建一个 CTE,但无法让它工作。


根据 KumarHarsh 的回答:

我得到以下结果:基于 KumarHarsh 的结果

这是我当前的 sql 代码:

With CTE As
(
 Select PH.ProdHeaderOrdNr,
      PH.ProdstatusCode,
      PH.partcode,
      PH.description,
      PBOM.subpartcode,
      PBOM.description as N'DescriptionSubpart',
      PBOO.qty,
      PBOO.producedqty,
      PBOO.machcycletime,
      PBOO.qty-PBOO.producedqty as N'ToProduce',
      case when(PBOO.qty-PBOO.producedqty)*(1+(convert(decimal(4,2),PBOM.waste)/100))<=0 
           then 0 
           else (PBOO.qty-PBOO.producedqty)*(1+(convert(decimal(4,2),PBOM.waste)/100)) 
           end as N'AmountSubpartNeeded',
      (DATEDIFF(dd, PBOO.startdate, PBOO.enddate) + 1)
              -(DATEDIFF(wk, PBOO.startdate, PBOO.enddate) * 2)
              -(CASE WHEN DATENAME(dw, PBOO.startdate) = 'Sunday' THEN 1 ELSE 0 END)
              -(CASE WHEN DATENAME(dw, PBOO.enddate) = 'Saturday' THEN 1 ELSE 0 END)
              As NoOfWeekDays,
      case when PBOO.machcycletime *((PBOO.qty-PBOO.producedqty)/PBOO.qty)/3600<=0 
           then 0 
           else  Round(PBOO.machcycletime *((PBOO.qty-PBOO.producedqty)/PBOO.qty)/3600,2) 
           end as N'HoursRemaining',
      PBOO.startdate as N'Startdate',
      PBOO.enddate as N'Enddate',
      datepart(year,PBOO.startdate) as N'Year',
      datepart(isoww,PBOO.startdate) as N'Week'
From
         dbo.T_ProductionHeader  AS PH,
         dbo.T_ProdBillofMat as PBOM,
         dbo.T_Part as P,
         dbo.T_ProdBillOfOper as PBOO,
         dbo.T_MachGrp as M 
where
             PH.ProdHeaderDossierCode = PBOM.ProdHeaderDossierCode    AND
    PH.ProdHeaderDossierCode = PBOO.ProdHeaderDossierCode AND
    PBOO.MachGrpCode = M.MachGrpCode AND
    M.DeptCode = '0720' and
    PH.ProdStatusCode BETWEEN 30 and 40 AND
    PBOM.LineNr = '10' and
    left(PH.partcode,1) in ('P', 'H')and
    PBOO.finishedInd = 0
)

Select c.*
,ca.RunningDates, 
c.toproduce/c.NoOfWeekDays as N'ProductionPerWorkDay',
c.amountsubpartneeded/c.NoOfWeekDays as N'AmountSubPartNeededPerWorkDay',
c.HoursRemaining/c.NoOfWeekDays as N'HoursRemainingPerWorkDay'
from
CTE C
cross apply(select cd.yeardate as RunningDates from dbo.T_DayOfYear CD where cd.yeardate>=c.Startdate and cd.yeardate<=c.enddate)ca

感谢 KumarHarsch 的最终工作代码。

    with CTE As
(
Select PH.ProdHeaderOrdNr,
      PH.ProdstatusCode,
      PH.partcode,
      PH.description as N'Omschrijving',
      PBOM.subpartcode,
      left(p.partgrpcode,1)as N'artikelgroeptype',
      PBOM.description as N'Draad',
      PBOO.qty,
      PBOO.producedqty,
      PBOO.machcycletime,
      PBOO.MachGrpCode,
      pbom.waste,
      PBOO.qty-PBOO.producedqty as N'ToProduce',

      (DATEDIFF(dd, PBOO.startdate, PBOO.enddate) + 1)
              -(DATEDIFF(wk, PBOO.startdate, PBOO.enddate) * 2)
              -(CASE WHEN DATENAME(dw, PBOO.startdate) = 'Sunday' THEN 1 ELSE 0 END)
              -(CASE WHEN DATENAME(dw, PBOO.enddate) = 'Saturday' THEN 1 ELSE 0 END)
              As NoOfWeekDays,
      PBOO.startdate as N'Startdate',
      PBOO.enddate as N'Enddate'
From
         ((dbo.T_ProductionHeader  AS PH
         inner join  dbo.T_ProdBillofMat as PBOM on  PH.ProdHeaderDossierCode = PBOM.ProdHeaderDossierCode)
         inner join dbo.T_ProdBillOfOper as PBOO on PH.ProdHeaderDossierCode = PBOO.ProdHeaderDossierCode),
         dbo.T_MachGrp as M,
         dbo.T_part as P  
where

    PBOO.MachGrpCode = M.MachGrpCode AND
    M.DeptCode = '0720' and
    PH.ProdStatusCode in ( 11, 30, 40 ) AND
    PBOM.LineNr = '10' and
    left(PH.partcode,1) in ('P', 'H')and
    PBOO.finishedInd = 0 and
    p.partcode = pbom.subpartcode

    )

Select c.*
,ca.RunningDates,
cf.ndagen,
      datepart(year,ca.RunningDates) as N'Year_Run',
      datepart(isoww,ca.RunningDates) as N'Week_Run',
case when c.producedqty>convert(decimal(6,2),((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2))) * (c.qty/cf.ndagen) then 0
              else (((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)) * (c.qty/cf.ndagen))  - (((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen)) - (case when c.producedqty>((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen) then (c.producedqty-(((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen))) else 0 end) end
              As ProductionPerWorkDay,
 case when c.producedqty>convert(decimal(6,2),((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2))) * (c.qty/cf.ndagen) then 0
              else (((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)) * (c.qty/cf.ndagen))  - (((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen)) - (case when c.producedqty>((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen) then (c.producedqty-(((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen))) else 0 end) end *(1+(convert(decimal(4,2),c.waste)/100)) 
              as subpartneededperworkday,
      case when c.machcycletime *((case when c.producedqty>convert(decimal(6,2),((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2))) * (c.qty/cf.ndagen) then 0
              else (((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)) * (c.qty/cf.ndagen))  - (((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen)) - (case when c.producedqty>((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen) then (c.producedqty-(((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen))) else 0 end) end)/c.qty)/3600<=0 
           then 0 
           else  Round(c.machcycletime *((case when c.producedqty>convert(decimal(6,2),((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2))) * (c.qty/cf.ndagen) then 0
              else (((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)) * (c.qty/cf.ndagen))  - (((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen)) - (case when c.producedqty>((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen) then (c.producedqty-(((DATEDIFF(dd, c.startdate, ca.RunningDates) + 1)
              -(DATEDIFF(wk, c.startdate, ca.RunningDates) * 2)-1) * (c.qty/cf.ndagen))) else 0 end) end)/c.qty)/3600,2) 
           end as N'HoursRemaining'           


from
CTE C
cross apply(select cd.capacityavailabledate as RunningDates from dbo.T_machgrpRealCapacity CD where cd.MachGrpCode = c.MachGrpCode and cd.capacityavailabledate>=c.Startdate and cd.capacityavailabledate<=c.enddate and DATENAME(dw, cd.capacityavailabledate) <> 'Sunday' and DATENAME(dw, cd.capacityavailabledate) <> 'Saturday' )ca
cross apply(select count(*) as ndagen from dbo.T_machgrpRealCapacity CD where cd.MachGrpCode = c.MachGrpCode and cd.capacityavailabledate>=c.Startdate and cd.capacityavailabledate<=c.enddate and DATENAME(dw, cd.capacityavailabledate) <> 'Sunday' and DATENAME(dw, cd.capacityavailabledate) <> 'Saturday' )cf

首先创建日历表。

以您想要的任何方式填充。

create table CalendarDate(Dates DateTime primary key)
insert into CalendarDate WITH (TABLOCK)  (Dates)
select top (1000000) 
DATEADD(day, ROW_NUMBER()over(order by (select null))-1,'1970-01-01') DT
from sys.objects

假设您的主要查询在 CTE 内(此脚本未经测试)

With CTE As
(
 Select ,
DATEDIFF(dd, PBOO.startdate, PBOO.enddate) + 1 as Diff
From 
)

Select c.*
,ca.RunningDates 
'to produce'/Datediff
'amount subpart needed'/Datediff
from
CTE C
cross apply(select Dates as RunningDates from CalendarDate CD where cd.dates>=c.Startdate and cd.dates<=c.enddate)ca

这是答案的一个重要部分。如果这是正确的,那么您可以继续进行。

我希望我的改变很清楚。

像“生产”这样的别名是错误的,它应该是一个词 ToProduce。

编辑 1,

create table #temp (startdt datetime,enddate datetime)
insert into #temp values('2010-01-01','2010-01-05')
,('2011-02-01','2011-02-06')

select t.*,ca.RunningDate from #temp t
cross apply(select cd.Dates as RunningDate 
from CalendarDate cd 
where cd.Dates>=t.startdt and cd.Dates<=t.enddate)ca

select t.*,cd.Dates as RunningDate from #temp t
inner join  CalendarDate cd 
on cd.Dates>=t.startdt and cd.Dates<=t.enddate

drop table #temp

检查你自己,它按预期工作正常。

然而,交叉应用导致只有第一行以相同的运行日期值无休止地显示

不是因为CROSS APPLY。原因一定是别的东西。调试并找到它。 you.Once 评论 CROSS APPLY 部分并检查结果或验证值 Calendar Table。

dbo.T_ProductionHeader AS PH,dbo.T_ProdBillofMat 作为 PBOM,

不好的做法。 明确提及 JOIN 语法。 意外加入笛卡尔积的风险较小。 逗号连接是上个世纪的事情。它也使其他人更容易理解。

dbo.T_ProductionHeader  AS PH inner join
 dbo.T_ProdBillofMat as PBOM on PH.ProdHeaderDossierCode = PBOM.ProdHeaderDossierCode    AND
    PH.ProdHeaderDossierCode = PBOO.ProdHeaderDossierCode AND

将额外的过滤器放在 where 子句上,例如PH.ProdStatusCode BETWEEN 30 and 40

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM