简体   繁体   中英

Show rows <= according to another table quantity SQL (T-SQL)

EDITED

I've been trying to get the simplest way to get a query from different tables, but only showing the quantity according to another table

-- Edited:

-- I want to create a Pickroute Report -- the pickroute will have an idorder, article, quantity and location

-- Example

-- If I have an order that needs 25 ITEM01 -- I will take 10 from LOC01 and 15 from LOC02 -- All the locatios have a sequence -- Once I complete the 25 I need to update the IDORDER column in SPLITTABLE

Let me explain

I have the following tables

SALESORDER table:

 IDORDER   ARTICLE   QUANTITY
 ----------------------------
    1      ITEM01       25
    1      ITEM02       10
    2      ITEM01       20
    3      ITEM01       5
    3      ITEM03       4

INVENTORY table:

  ARTICLE   QUANTITY   LOCATION   SEQUENCE
  ---------------------------------------
  ITEM01       10       LOC01        1
  ITEM01       30       LOC02        2
  ITEM01       30       LOC03        3
  ITEM02       2        LOC02        2
  ITEM02       10       LOC03        3
  ITEM03       1        LOC01        1
  ITEM03       5        LOC02        2

What I am trying to get is the following

OPORDER table:

  ARTICLE   QUANTITY   LOCATION   IDORDER
  ----------------------------------------
   ITEM01      10        LOC01       1
   ITEM01      15        LOC02       1
   ITEM02       2        LOC02       1
   ITEM02       8        LOC03       1
   ITEM01      15        LOC02       2
   ITEM01       5        LOC03       2
   ITEM01       5        LOC03       3
   ITEM03       1        LOC01       3
   ITEM03       4        LOC02       3

Now let me show you what I'm doing to get it done (at least trying to do it).

Schema :

SALESORDER

DROP TABLE IF EXISTS SALESORDER

CREATE TABLE SALESORDER 
(
     IDORDER INT,
     ARTICLE VARCHAR(50), 
     QUANTITY INT
);

INSERT SALESORDER (IDORDER, ARTICLE, QUANTITY) 
VALUES (1, 'ITEM01', 25), (1, 'ITEM02', 10),
       (2, 'ITEM01', 20), (3, 'ITEM01', 5),
       (3, 'ITEM03', 4)

INVENTORY

DROP TABLE IF EXISTS INVENTORY

CREATE TABLE INVENTORY 
(
     ARTICLE VARCHAR(50), 
     QUANTITY INT,
     LOCATION VARCHAR(50),
     SEQUENCE INT
);

INSERT INVENTORY (ARTICLE, QUANTITY,LOCATION,SEQUENCE) 
VALUES ('ITEM01', 10, 'LOC01',1), ('ITEM01', 30, 'LOC02',2),
       ('ITEM01', 30, 'LOC03',3), ('ITEM02', 2, 'LOC02',2),
       ('ITEM02', 10, 'LOC03',3), ('ITEM03', 1, 'LOC01',1),
       ('ITEM03', 5, 'LOC02',2)`

What I'm doing is:

first split into one piece table from the inventory

SPLITTABLE

DROP TABLE IF EXISTS SPLITTABLE

CREATE TABLE SPLITTABLE 
(
     ARTICLE VARCHAR(50), 
     QUANTITY INT,
     LOCATION VARCHAR(50), 
     IDORDER INT,
     SEQUENCE INT
);

SPLIT

WITH RTE (Vals) AS
(
    SELECT 1 
    UNION ALL

    SELECT 1 + Vals 
    FROM RTE 
    WHERE Vals < 500
)
INSERT INTO SPLITTABLE (ARTICLE, QUANTITY, LOCATION, IDORDER,SEQUENCE) 
    SELECT ARTICLE,1 AS QUANTITY,LOCATIONS,0 AS IDORDER, SEQUENCE
    FROM INVENTORY INV
    INNER JOIN RTE R ON R.Vals <= INV.Quantity
    OPTION (maxrecursion 0);

--Result

88 rows with quantity 1 --88 Because ITEM01 70 ITEM02 12 and ITEM03 6

SELECT * FROM SPLITTABLE

ARTICLE QUANTITY    LOCATION    IDORDER SEQUENCE
 ITEM01    1         LOC01         0       1
 ITEM01    1         LOC02         0       2
 ITEM01    1         LOC03         0       3
 ITEM02    1         LOC02         0       2
 ITEM02    1         LOC03         0       3
 ITEM03    1         LOC01         0       1
 ITEM03    1         LOC02         0       2
 ITEM01    1         LOC01         0       1
 ITEM01    1         LOC02         0       2

... until 88 rows(IDORDER is in 0 because it is not asigned yet)

After split I assign an Idorder(On the declare statements this is what I want to avoid)

DECLARE @LIMIT INT =25;
DECLARE @ORDER INT = 1;
DECLARE @ARTICLE VARCHAR(50)='ITEM01';

WITH CTE AS 
(
   SELECT  
       ARTICLE, QUANTITY, LOCATION, IDORDER,
       RUNNINGTOTAL = SUM(QUANTITY) OVER (PARTITION BY ARTICLE ORDER BY 
LOCATION
                                       ROWS UNBOUNDED PRECEDING)
FROM 
    SPLITTABLE
WHERE 
    ARTICLE = @ARTICLE AND IDORDER =0
 ), TOTAL AS
 (
 SELECT 
     ARTICLE, QUANTITY, LOCATION, IDORDER = @ORDER
 FROM 
     CTE 
 WHERE 
     RUNNINGTOTAL <= @LIMIT
 )
 UPDATE CTE 
 SET IDORDER = T.IDORDER 
 FROM TOTAL AS T  
 WHERE RUNNINGTOTAL <= @LIMIT;

--Result

25 rows from SPLITTABLE with ITEM01 marked as IDORDER 1

SELECT * FROM SPLITTABLE WHERE ARTICLE ='ITEM01' ORDER BY SEQUENCE ASC

ARTICLE QUANTITY    LOCATION    IDORDER SEQUENCE
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC01         1   1
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2
ITEM01     1          LOC02         1   2

-- The rest of the rows are in 0 because I only select ITEM01 and quantity 25 it --takes only 10 from the LOC01(sequence 1) and 15 from LOC02(sequence 2)

--After changing all the declare statements for each item, order and quantity I can see the result

--With this query you get what I want

SELECT ARTICLE,SUM(QUANTITY) AS QUANTITY,LOCATION,IDORDER FROM SPLITTABLE 
WHERE IDORDER<>0 GROUP BY ARTICLE,IDORDER,LOCATION ORDER BY IDORDER ASC

With these queries I get the information I need but I have some problems

  1. The split part takes all the articles into the SPLITTABLE the problem is when I have an order asking for 1 article but in the inventory for that article has > 1000 it takes a lot of time and resources

  2. Once the split is done, I assign idorder but I had to do it manually for each article and each order

I have to thank you in advance for all your comments and help

In case you need more information, let me know

You can use cursors.

I used table variables in the example so you'll have to change a code a little bit (remove @)

When there is not enough items in the inventory the NULL will be inserted into the LOCATION column, remove this if necessary.

I didn't add quantity limit, you'll have to make sure that the order can't contain more than the limit because it seems misleading to let the customer order more and then send less than he ordered. Unless I misunderstood the intent.

DECLARE @SALESORDER  TABLE  
(
     IDORDER INT,
     ARTICLE VARCHAR(50), 
     QUANTITY INT
);

INSERT @SALESORDER (IDORDER, ARTICLE, QUANTITY) 
VALUES (1, 'ITEM01', 25), (1, 'ITEM02', 10),(1, 'ITEM14', 1),(2, 'ITEM00', 10),
       (2, 'ITEM01', 70), (3, 'ITEM01', 5),
       (3, 'ITEM03', 4)




DECLARE @INVENTORY TABLE  
(
     ARTICLE VARCHAR(50), 
     QUANTITY INT,
     LOCATION VARCHAR(50)
);

INSERT @INVENTORY (ARTICLE, QUANTITY,LOCATION) 
VALUES ('ITEM01', 10, 'LOC01'), ('ITEM01', 30, 'LOC02'),
       ('ITEM01', 30, 'LOC03'), ('ITEM02', 2, 'LOC02'),
       ('ITEM02', 10, 'LOC03'), ('ITEM03', 1, 'LOC01'),
       ('ITEM03', 5, 'LOC02'), ('ITEM01', 0, 'LOC04')

DECLARE @SPLITTABLE TABLE  
(
     ARTICLE VARCHAR(50), 
     QUANTITY INT,
     LOCATION VARCHAR(50), 
     IDORDER INT
);
---------------------------------------------------------------------------
DECLARE so_cur CURSOR local fast_forward
FOR
SELECT so.ARTICLE,so.QUANTITY,so.IDORDER FROM  @SALESORDER as so 
ORDER BY so.ARTICLE,so.IDORDER
;

DECLARE inv_cur CURSOR local fast_forward
FOR
SELECT inv.ARTICLE,inv.QUANTITY,inv.[LOCATION] FROM  @INVENTORY as inv 
ORDER BY inv.ARTICLE,inv.[LOCATION]
;


declare @so_ARTICLE varchar(50);
declare @so_QUANTITY int; 
declare @so_IDORDER int; 

declare @inv_ARTICLE varchar(50);
declare @inv_QUANTITY int; 
declare @inv_LOCATION varchar(50);

declare @nextOrder bit = 1;
declare @nextInv bit = 1;
declare @outOfInv bit = 0;

open so_cur
open inv_cur

WHILE 1=1
BEGIN

    IF @nextOrder = 1
    BEGIN
        FETCH NEXT from so_cur
        INTO
        @so_ARTICLE, 
        @so_QUANTITY,
        @so_IDORDER
        ;
        SET @nextOrder = 0;
        if @@FETCH_STATUS = -1 break;
    END

    IF @outOfInv = 0 AND @nextInv = 1
    BEGIN
        FETCH NEXT from inv_cur
        INTO
        @inv_ARTICLE, 
        @inv_QUANTITY,
        @inv_LOCATION
        ;
        SET @nextInv = 0;
        if @@FETCH_STATUS = -1 
        BEGIN
            SET @outOfInv = 1;
            PRINT N'NOT ENOUGH ITEMS IN INVENTORY'
        END
    END

    IF @outOfInv = 0 AND @inv_ARTICLE < @so_ARTICLE
    BEGIN
        SET @nextInv = 1;
    END
    ELSE IF @outOfInv = 1 OR @inv_ARTICLE > @so_ARTICLE
    BEGIN
        PRINT N'NOT ENOUGH ITEMS IN INVENTORY, YOU MIGHT WANT TO INSERT LOCATION=NULL TO THE SPLITTABLE';
        INSERT INTO @SPLITTABLE (ARTICLE,QUANTITY,LOCATION,IDORDER) VALUES (@so_ARTICLE,@so_QUANTITY,NULL,@so_IDORDER) 
        SET @nextOrder = 1;
    END
    ELSE
    BEGIN
        IF @so_QUANTITY < @inv_QUANTITY
        BEGIN
            IF @so_QUANTITY >0 
            BEGIN
                INSERT INTO @SPLITTABLE (ARTICLE,QUANTITY,LOCATION,IDORDER) VALUES (@so_ARTICLE,@so_QUANTITY,@inv_LOCATION,@so_IDORDER) 
                SET @inv_QUANTITY -= @so_QUANTITY
            END
            SET @nextOrder = 1;
        END
        ELSE IF @so_QUANTITY = @inv_QUANTITY
        BEGIN
            IF @so_QUANTITY >0 
            BEGIN
                INSERT INTO @SPLITTABLE (ARTICLE,QUANTITY,LOCATION,IDORDER) VALUES (@so_ARTICLE,@so_QUANTITY,@inv_LOCATION,@so_IDORDER)
            END
            SET @nextOrder = 1;
            SET @nextInv = 1;
        END
        ELSE
        BEGIN
            IF @inv_QUANTITY >0
            BEGIN
                INSERT INTO @SPLITTABLE (ARTICLE,QUANTITY,LOCATION,IDORDER) VALUES (@so_ARTICLE,@inv_QUANTITY,@inv_LOCATION,@so_IDORDER)
                SET @so_QUANTITY -= @inv_QUANTITY
            END

            SET @nextInv = 1;
        END
    END

END

CLOSE so_cur;
DEALLOCATE so_cur;
CLOSE inv_cur;
DEALLOCATE inv_cur;
-----------------------------------------------------------------------
SELECT * FROM @SPLITTABLE ORDER BY IDORDER,ARTICLE

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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