SQL在同一键上运行总计

时间:2018-11-28 10:22:47

标签: sql sql-server

edit:当用户Larna请求为子查询表创建/插入时,我也添加了这些。

以下查询返回:

    DocNum  ItemCode    Planned Qty   WhsCode   BinCode    QuantityToPick
    901903  A00001      12.000000     98        98-A001    7.000000
    901903  A00001      12.000000     98        98-A002    5.000000  --sum of 5 and 7 makes 12
    901904  A00001      17.000000     98        98-A001    7.000000
    901904  A00001      17.000000     98        98-A002    6.000000
    901904  A00001      17.000000     98        98-A003    4.000000  --sum of 7,6 and 4 makes 17



But I want to have this result:

    DocNum  ItemCode    Planned Qty    WhsCode  BinCode    QuantityToPick
    901903  A00001      12.000000      98       98-A001    7.000000
    901903  A00001      12.000000      98       98-A002    5.000000  --sum of 5 and 7 makes 12

-- continue from bin code 98A002 for the new docnum as we had 5 out of 6 where consumed 
    901904  A00001      17.000000      98       98-A002    1.000000 
    901904  A00001      17.000000      98       98-A003    12.000000
    901904  A00001      17.000000      98       98-A004    4.000000  --sum of 1,12 and 4 makes 17

因此,基本上,我想继续使用第一个DocNum,ItemCode,Quantity eat部分地-- Create Tables for Subquerys + insert relevant data CREATE TABLE [dbo].[WOR1](-- Removed the unimportant columns [DocEntry] [int] NOT NULL, [LineNum] [int] NOT NULL, [ItemCode] [nvarchar](50) NULL, [PlannedQty] [numeric](19, 6) NULL, [IssuedQty] [numeric](19, 6) NULL, [wareHouse] [nvarchar](8) NULL ) INSERT INTO [dbo].[WOR1] VALUES(154 ,0 ,'A00001' ,12.000000 ,0.000000, '01') ,(154 ,1 ,'P10001' ,12.000000 ,0.000000, '01') ,(154 ,2 ,'L10001' ,12.000000 ,0.000000, '01') ,(155 ,0 ,'A00001' ,17.000000 ,0.000000, '01') ,(155 ,1 ,'P10001' ,17.000000 ,0.000000, '01') ,(155 ,2 ,'L10001' ,17.000000 ,0.000000, '01') CREATE TABLE [dbo].[OWOR](-- Removed the unimportant columns [DocEntry] [int] NOT NULL, [DocNum] [int] NOT NULL, [Status] [char](1) NULL ) INSERT INTO [dbo].[OWOR] VALUES( 154, 901903, 'R') ,( 155, 901904, 'R') CREATE TABLE [dbo].[OIBQ](-- Removed the unimportant columns [ItemCode] [nvarchar](50) NOT NULL, [BinAbs] [int] NOT NULL, [OnHandQty] [numeric](19, 6) NULL, [WhsCode] [nvarchar](8) NULL ) INSERT INTO [dbo].[OIBQ] VALUES('A00001', 7, 15.000000, '98') ,('A00001', 2, 7.000000, '98') ,('A00001', 3, 6.000000, '98') ,('A00001', 4, 12.000000, '98') CREATE TABLE [dbo].[OBIN](-- Removed the unimportant columns [AbsEntry] [int] NOT NULL, [BinCode] [nvarchar](228) NOT NULL, [WhsCode] [nvarchar](8) NULL ) INSERT INTO [dbo].[OBIN] VALUES(1, '98-SYSTEM-BIN-LOCATION', '98') ,(2, '98-A001', '98') ,(3, '98-A002', '98') ,(4, '98-A003', '98') ,(5, '98-A004', '98') ,(6, '98-A005', '98') ,(7, '98-A006', '98') 之后的中断处 并继续使用第二个DocNum,ItemCode,Quantity来“吃掉”第二个垃圾箱的剩余数量,然后剩余的剩余垃圾箱直到我达到0

但是我对如何执行此操作有些困惑。 有人有任何建议/解决方案吗?

SELECT

WOPICK.DocNum,
WOPICK.ItemCode,
WOPICK.Quantity as 'Planned Qty', 
BINSTOCK.WhsCode,
BINSTOCK.BinCode,

CASE WHEN (BINSTOCK.Quantity -(BINSTOCK.RunningTotalQty - WOPICK.Quantity)) <BINSTOCK.Quantity 
    THEN (BINSTOCK.Quantity -(BINSTOCK.RunningTotalQty - WOPICK.Quantity)) 
    ELSE BINSTOCK.Quantity END as 'QuantityToPick'-- FinalQty


FROM (
    SELECT IBQ.ItemCode, SUM(IBQ.OnHandQty)as 'Quantity',BIN.WhsCode,  BIN.BinCode ,
    SUM(SUM(OnHandQty)) OVER (PARTITION BY IBQ.ItemCode 
                                        ORDER BY IBQ.ItemCode,BIN.BinCode ) as 'RunningTotalQty'
    FROM OIBQ IBQ INNER JOIN OBIN BIN on IBQ.BinAbs = BIN.AbsEntry
    GROUP BY    IBQ.ItemCode, BIN.WhsCode,  BIN.BinCode 
) BINSTOCK
INNER JOIN ( 
    SELECT distinct WOR.DocNum, WOR1.LineNum, WOR1.ItemCode, WOR1.PlannedQty - WOR1.IssuedQty as 'Quantity' 
    FROM OWOR WOR 
    INNER JOIN  WOR1 WOR1 on WOR.DocEntry = WOR1.DocEntry 
    INNER JOIN OIBQ IBQ on IBQ.ItemCode = WOR1.ItemCode
    where WOR.Status = 'R'
) WOPICK on BINSTOCK.ItemCode = WOPICK.ItemCode 
WHERE BINSTOCK.RunningTotalQty - BINSTOCK.Quantity < WOPICK.Quantity
order by WOPICK.LineNum;

查询子查询:

  CREATE TABLE [dbo].[BINSTOCK](
    ItemCode NVARCHAR(10) NOT NULL
    ,Quantity DECIMAL (19,6) NOT NULL
    ,WhsCode INT NOT NULL
    ,BinCode NVARCHAR (10) NOT NULL
    ,RunningTotalQty DECIMAL (19,6) NOT NULL
    )

 INSERT INTO [dbo].[BINSTOCK]
    VALUES('A00001' , 7.000000, 98, '98-A001' , 7.000000),
    ('A00001' , 6.000000, 98, '98-A002' , 13.000000),
    ('A00001' , 12.000000, 98, '98-A003' , 25.000000),
    ('A00001' , 15.000000, 98, '98-A006' , 40.000000)

 CREATE TABLE [dbo].[WOPICK](
    DocNum INT NOT NULL
    ,LineNum INT NOT NULL
    ,ItemCode NVARCHAR (10) NOT NULL
    ,Quantity DECIMAL (19,6) NOT NULL
    )

   INSERT INTO [dbo].[WOPICK]
    VALUES(901903,0,'A00001',12.000000),
    (901904,0,'A00001',17.000000)

不带子查询的查询

-SIMPLIFIED版本(表BINSTOCK和WOPICK中的子查询结果)

SELECT
WOPICK.DocNum,
WOPICK.ItemCode,
WOPICK.Quantity as 'Planned Qty', 
BINSTOCK.WhsCode,
BINSTOCK.BinCode,

CASE WHEN (BINSTOCK.Quantity -(BINSTOCK.RunningTotalQty - WOPICK.Quantity)) <BINSTOCK.Quantity 
    THEN (BINSTOCK.Quantity -(BINSTOCK.RunningTotalQty - WOPICK.Quantity)) 
    ELSE BINSTOCK.Quantity END as 'QuantityToPick'-- FinalQty


FROM  BINSTOCK
INNER JOIN WOPICK on BINSTOCK.ItemCode = WOPICK.ItemCode 
WHERE BINSTOCK.RunningTotalQty - BINSTOCK.Quantity < WOPICK.Quantity
order by WOPICK.LineNum;

count

2 个答案:

答案 0 :(得分:2)

这实际上比第一次听起来容易。但是,您将首先需要处理一些问题-您还需要针对所需数量进行总计:

SELECT OWOR.docNum, WOR1.itemCode, plannedQty,
       SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode 
                                         ORDER BY OWOR.docEntry) - (plannedQty - issuedQty) AS prevTotalNeeded,
       SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode 
                                         ORDER BY OWOR.docEntry) AS runningTotalNeeded
      FROM OWOR
      JOIN WOR1
        ON WOR1.docEntry = OWOR.docEntry
      WHERE OWOR.status = 'R'

....结合“需要运行的前一列”(并假设以前的总数量),我们现在正在查看overlapping range query

与您的BINSTOCK(稍作修改)结合在一起:

SELECT *

FROM (SELECT itemCode, whsCode, binCode, quantity,
             SUM(quantity) OVER (PARTITION BY itemCode ORDER BY binCode) - quantity AS prevTotalQuantity, 
             SUM(quantity) OVER (PARTITION BY itemCode ORDER BY binCode) AS runningTotalQuantity
      FROM (SELECT OIBQ.itemCode, OIBQ.whsCode, OBIN.binCode, SUM(OIBQ.onHandQty) AS quantity
            FROM OIBQ
            JOIN OBIN
              ON OBIN.absEntry = OIBQ.binAbs
            GROUP BY OIBQ.itemCode, OIBQ.whsCode, OBIN.binCode) TotalQuantity
) BINSTOCK
JOIN (SELECT OWOR.docNum, WOR1.itemCode, plannedQty,
             SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode ORDER BY OWOR.docEntry) - (plannedQty - issuedQty) AS prevTotalNeeded,
             SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode ORDER BY OWOR.docEntry) AS runningTotalNeeded
      FROM OWOR
      JOIN WOR1
        ON WOR1.docEntry = OWOR.docEntry
      WHERE OWOR.status = 'R') WOPICK
  ON WOPICK.itemCode = BINSTOCK.itemCode
     AND WOPICK.prevTotalNeeded <= BINSTOCK.runningTotalQuantity
     AND WOPICK.runningTotalNeeded >= BINSTOCK.prevTotalQuantity

...将产生下表:

itemCode | whsCode | binCode | quantity  | prevTotalQuantity | runningTotalQuantity | docNum | itemCode | plannedQty | prevTotalNeeded | runningTotalNeeded
:------- | :------ | :------ | :-------- | :---------------- | :------------------- | -----: | :------- | :--------- | :-------------- | :-----------------
A00001   | 98      | 98-A001 | 7.000000  | 0.000000          | 7.000000             | 901903 | A00001   | 12.000000  | 0.000000        | 12.000000         
A00001   | 98      | 98-A002 | 6.000000  | 7.000000          | 13.000000            | 901903 | A00001   | 12.000000  | 0.000000        | 12.000000         
A00001   | 98      | 98-A002 | 6.000000  | 7.000000          | 13.000000            | 901904 | A00001   | 17.000000  | 12.000000       | 29.000000         
A00001   | 98      | 98-A003 | 12.000000 | 13.000000         | 25.000000            | 901904 | A00001   | 17.000000  | 12.000000       | 29.000000         
A00001   | 98      | 98-A006 | 15.000000 | 25.000000         | 40.000000            | 901904 | A00001   | 17.000000  | 12.000000       | 29.000000         

...。然后,通过明智的CASE语句,我们可以将重叠的三个四个(不是三个)条件转换为最终的总计:

SELECT WOPICK.docNum, WOPICK.itemCode, WOPICK.plannedQty,
       BINSTOCK.whsCode, BINSTOCK.binCode,
       CASE WHEN WOPICK.prevTotalNeeded < BINSTOCK.prevTotalQuantity
                 AND WOPICK.runningTotalNeeded > BINSTOCK.runningTotalQuantity
            THEN BINSTOCK.quantity
            WHEN WOPICK.prevTotalNeeded >= BINSTOCK.prevTotalQuantity
                 AND WOPICK.runningTotalNeeded <= BINSTOCK.runningTotalQuantity
            THEN WOPICK.neededQuantity
            WHEN WOPICK.runningTotalNeeded <= BINSTOCK.runningTotalQuantity
            THEN WOPICK.runningTotalNeeded - BINSTOCK.prevTotalQuantity
            WHEN WOPICK.prevTotalNeeded >= BINSTOCK.prevTotalQuantity
            THEN BINSTOCK.runningTotalQuantity - WOPICK.prevTotalNeeded
            END AS quantityToPick

FROM (SELECT itemCode, whsCode, binCode, quantity,
             SUM(quantity) OVER (PARTITION BY itemCode 
                                 ORDER BY binCode) - quantity AS prevTotalQuantity, 
             SUM(quantity) OVER (PARTITION BY itemCode 
                                 ORDER BY binCode) AS runningTotalQuantity
      FROM (SELECT OIBQ.itemCode, OIBQ.whsCode, OBIN.binCode, SUM(OIBQ.onHandQty) AS quantity
            FROM OIBQ
            JOIN OBIN
              ON OBIN.absEntry = OIBQ.binAbs
            GROUP BY OIBQ.itemCode, OIBQ.whsCode, OBIN.binCode) TotalQuantity
) BINSTOCK
JOIN (SELECT OWOR.docNum, WOR1.itemCode, plannedQty, plannedQty - issuedQty AS neededQuantity,
             SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode 
                                               ORDER BY OWOR.docEntry) - (plannedQty - issuedQty) AS prevTotalNeeded,
             SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode 
                                               ORDER BY OWOR.docEntry) AS runningTotalNeeded
      FROM OWOR
      JOIN WOR1
        ON WOR1.docEntry = OWOR.docEntry
      WHERE OWOR.status = 'R') WOPICK
  ON WOPICK.itemCode = BINSTOCK.itemCode
     AND WOPICK.prevTotalNeeded <= BINSTOCK.runningTotalQuantity
     AND WOPICK.runningTotalNeeded >= BINSTOCK.prevTotalQuantity

Fiddle example ...产生预期的结果:

docNum | itemCode | plannedQty | whsCode | binCode | quantityToPick
-----: | :------- | :--------- | :------ | :------ | :-------------
901903 | A00001   | 12.000000  | 98      | 98-A001 | 7.000000      
901903 | A00001   | 12.000000  | 98      | 98-A002 | 5.000000      
901904 | A00001   | 17.000000  | 98      | 98-A002 | 1.000000      
901904 | A00001   | 17.000000  | 98      | 98-A003 | 12.000000     
901904 | A00001   | 17.000000  | 98      | 98-A006 | 4.000000      

(已省略了排序,因为原来的排序似乎不寻常。根据您的源数据,有可能在OBIN内删除对BINSTOCK的引用)

答案 1 :(得分:1)

这显然是存储过程的工作。甚至尝试使用查询来疯狂。 (发条回答后:编辑:Doh!)

说:

WITH Bin AS (
  SELECT *, ROW_NUMBER() OVER(PARTITION BY ItemCode ORDER BY BinCode) AS BinRank
  FROM BINSTOCK
), Pick AS (
  SELECT *, ROW_NUMBER() OVER(PARTITION BY ItemCode ORDER BY DocNum) AS PickRank
  FROM WOPICK
), BinPick AS (
  SELECT
    b.ItemCode,
    b.Quantity AS BinQty,
    b.BinCode,
    b.BinRank,
    p.Quantity AS PickQty,
    p.DocNum,
    p.PickRank,
    CAST (
      CASE
        WHEN b.Quantity < p.Quantity
        THEN b.Quantity
        ELSE p.Quantity
        END
    AS DECIMAL) AS Picked,
    CAST (
      CASE
        WHEN b.Quantity < p.Quantity
        THEN p.Quantity - b.Quantity
        ELSE 0
        END
    AS DECIMAL) AS Required,
    CAST (
      CASE
        WHEN b.Quantity < p.Quantity
        THEN 0
        ELSE b.Quantity - p.Quantity
        END
    AS DECIMAL) AS Remaining,
    CAST (
      CASE
        WHEN b.Quantity < p.Quantity
        THEN null
        ELSE b.BinRank
        END
    AS NVARCHAR) AS LastFullBinRank
  FROM Bin b
  JOIN Pick p ON p.ItemCode = b.ItemCode
  WHERE b.BinRank = 1
  AND p.PickRank = 1
  UNION ALL
  SELECT
    ItemCode,
    BinQty,
    BinCode,
    BinRank,
    PickQty,
    DocNum,
    PickRank,
    CAST (
      CASE WHEN Remaining < Required
        THEN Remaining
        ELSE Required
        END
      AS DECIMAL) AS Picked,
    CAST (
      CASE WHEN Remaining < Required
        THEN Required - Remaining
        ELSE 0
        END
    AS DECIMAL) AS Required,
    CAST (
      CASE WHEN Remaining < Required
        THEN 0
        ELSE Remaining - Required
        END
    AS DECIMAL) AS Remaining,
    CAST (
      CASE WHEN Remaining < Required
        THEN null
        ELSE BinRank
        END
    AS NVARCHAR) AS LastFullBinRank
  FROM (
    SELECT
      b.ItemCode,
      b.Quantity AS BinQty,
      b.BinCode,
      b.BinRank,
      p.Quantity AS PickQty,
      p.DocNum,
      p.PickRank,
      bp.DocNum AS PrevDocNum,
      bp.Picked,
      bp.LastFullBinRank,
      CASE WHEN p.DocNum = bp.DocNum
        -- Same order.  Continue with required from previous.
        THEN bp.Required
        -- New order.  Required is new order quantity.
        ELSE p.Quantity
        END
      AS Required,
      CASE WHEN p.DocNum = bp.DocNum
        -- Same order.  Hence fresh bin.  Use quanity from this bin.
        THEN b.Quantity
        -- New order.  Hence used bin.  Use remaining carried over.
        ELSE bp.Remaining
        END
      AS Remaining
      FROM BinPick bp
      JOIN Pick p
        ON p.ItemCode = bp.ItemCode
        AND (
          -- Order complete.  Move to next order
          (bp.Required = 0 AND p.PickRank = bp.PickRank + 1)
          OR
          -- Order incomlete.  Continue with current Order
          (bp.Required > 0 AND p.PickRank = bp.PickRank)
        )
      JOIN Bin b
        ON b.ItemCode = bp.ItemCode
        AND (
          -- Order complete.  Resume at last full bin.
          (bp.Required = 0 AND b.BinRank = bp.LastFullBinRank)
          OR
          -- Order incomlete.  Move to next bin.
          (bp.Required > 0 AND bp.LastFullBinRank IS NULL AND b.BinRank = bp.BinRank + 1)
        )
  ) sub1
) SELECT * FROM BinPick

注意:我几乎没有对此进行测试。我将它留给有兴趣纠正任何错误的人,但是我认为该原则是正确的。使用递归CTE来标识下一个Bin / Order,并在列中维护一堆变量以跟踪您的工作!

请参见DB Fiddle