SQL Показывает доступный запас в зависимости от веса и первых 4 символов кода

#sql #sql-server

#sql #sql-сервер

Вопрос:

DDL и DML:

 CREATE TABLE Product 
(
    id int not null,
    code varchar(20),
    description varchar(40),
    searchref1 varchar(20),
    weightKG decimal(10, 2)
);

INSERT INTO Product (id, code, description, searchref1, weightKG)
VALUES (1, '0001101', 'ProductOne', '1kg', 1),
       (2, '0001050', 'ProductOne', '500g', 0.5),
       (3, '0001400', 'ProductOne', '10 x 1kg', 10),
       (4, '0080101', 'ProductTwo', '1kg', 1),
       (5, '0080050', 'ProductTwo', '500g', 0.5),
       (6, '0001WIP', 'ProductOne Work in progress', '1kg', 1),
       (7, '0080WIP', 'ProductTwo Work in progress', '1kg', 1);
 
CREATE TABLE SalesOrderLine 
(
    id int not null,
    productID int,
    requiredQty int
);

INSERT INTO SalesOrderLine (id, productID, requiredQty)
VALUES (1, 1, 21), (2, 2, 5), (3, 3, 8), (4, 5, 1);

CREATE TABLE Stock 
(
    id int not null,
    productID int,
    inStock int
);

INSERT INTO Stock (id, productID, inStock)
VALUES (1, 6, 10), (2, 7, 2);
 

Ссылка на скрипку SQL: http://sqlfiddle.com /#!18/a68d49/28

У меня есть SalesOrderLine таблица, подобная:

 SELECT
    code, searchref1, requiredQty, weightKG
FROM 
    SalesOrderLine sol
JOIN 
    Product P ON p.id = sol.productid;

code       searchref1     requiredQty   weightKG
------------------------------------------------
0001101    1kg            21            1
0001050    500g           5             0.5
0001400    10 x 1kg       8             10
0080050    500g           1             0.5
 

Теперь я могу сгруппировать коды продуктов по первым 4 кодам. Пока я это делаю, я могу получить общую сумму weightKG * requiredQty .

Запрос

 SELECT
    LEFT(code, 4) AS code, SUM(weightKG * requiredQty) AS TotalKg
FROM  
    SalesOrderLine sol
JOIN 
    Product P ON p.id = sol.productid
GROUP BY 
    LEFT(code, 4)
 

Результат:

 code    TotalKg
---------------
0001    103.5
0080    0.5
 

Пока я знаю, сколько kg всего требуется для конкретного продукта.

Проблема: теперь я застрял с этим..

У меня есть другая таблица, которая называется Stock :

Запрос

 SELECT 
    LEFT(p.code, 4) AS code, p.searchref1, inStock  
FROM 
    stock s 
JOIN 
    product p ON s.productID = p.id;

code    searchref1  inStock
---------------------------
0001    1kg         10
0080    1kg         2
 

Теперь мне нужно получить этот вывод таблицы:

 code    TotalKg   inStock1KgOnly  remaining
-------------------------------------------
0001    103.5     10              93.5          
0080    0.5       0               0.5
 

Причина 0080 в том, что отображается как 0 , потому что в строке SalesOrderLine нет 1kg заказов и не имеет отношения к запасу. Оставшееся показывает, сколько запасов необходимо создать для конкретного 1kg создания .

remaining Столбец — это просто простое вычисление TotalKg - inStock1KgOnly .

Моя попытка запроса:

 SELECT 
    t1.code, t1.totalKg, 
    t2.inStock AS inStock1KgOnly, 
    (t1.TotalKg - t2.inStock) AS Remaining 
FROM
    (SELECT
         LEFT(code, 4) AS code, SUM(weightKG * requiredQty) AS TotalKg
     FROM 
         SalesOrderLine sol
     JOIN 
         Product P ON p.id = sol.productid
     GROUP BY 
         LEFT(code, 4)) t1 
JOIN 
    (SELECT LEFT(p.code, 4) as Code, inStock
     FROM product p
     JOIN stock s ON s.productID = p.id) t2 ON (t1.code = t2.code)
 

Вывод

 code    totalKg inStock1KgOnly  Remaining
------------------------------------------
0001    103.5   10              93.5
0080    0.5     2               -1.5
 

Комментарии:

1. Начните с product в качестве управляющей таблицы, внутреннего соединения stock , левого соединения SalesOrderLine . Вы также можете записать его как правильное соединение, но это просто вызовет у вас мигрень

2. Где бы вы создали эти объединения в текущем запросе?

3. Думая об этом, я в замешательстве. Вы хотите, чтобы в результате были получены все продукты или только продукты весом 1 кг, и мы должны группировать по code или left(code,4) ? Включает ли это продукты без заказов или только продукты с заказами? Только продукты с запасом или даже без?

4. @Charlieface i.stack.imgur.com/UcQwr.png Это то, что нужно.

Ответ №1:

Отредактировано, чтобы вывести требования, не объясненные явно.

Это должно охватить вас…

 WITH TEMP_Product AS
(
SELECT
  p.Id AS ProductId
  ,LEFT(p.code, 4) AS Code
  ,p.weightKg AS WeightKg
FROM Product p
)
,TEMP_SalesOrderLine AS
(
SELECT 
  p.Code
  ,SUM(l.RequiredQty * p.WeightKg) AS TotalKg
FROM SalesOrderLine l
INNER JOIN TEMP_Product p ON l.ProductId = p.ProductId
GROUP BY p.Code
)
,TEMP_Stock AS
(
SELECT DISTINCT
  p.Code
  ,s.InStock
  ,SUM(s.InStock * p.WeightKg) OVER (PARTITION BY p.Code) AS InStockKg
FROM Stock s
INNER JOIN TEMP_Product p ON p.ProductId = s.ProductId
)
,TEMP_Summary AS
(
SELECT
  l.Code
  ,l.TotalKg
  ,FLOOR(l.TotalKg) AS FloorKg
  ,s.InStockKg
  ,(l.TotalKg - s.InStockKg) AS Delta
FROM TEMP_SalesOrderLine l
INNER JOIN TEMP_Stock s ON l.Code = s.Code
)
SELECT
  s.Code
  ,s.TotalKg
  ,CASE WHEN (s.FloorKg < 1) THEN 0 
        ELSE CASE WHEN (s.Delta >= 0) THEN s.InStockKg
                  ELSE s.TotalKg END 
   END AS InStockKg
  ,CASE WHEN (s.FloorKg < 1) THEN s.TotalKg
        ELSE CASE WHEN (s.Delta < 0) THEN 0 
                  ELSE s.Delta END
   END AS Remaining
FROM TEMP_Summary s;
 

Результаты:

0.5

 INSERT INTO SalesOrderLine (id, productID, requiredQty)
VALUES (1, 1, 21), (2, 2, 5), (3, 3, 8), (4, 5, 1);
 

0.5

1.0

 INSERT INTO SalesOrderLine (id, productID, requiredQty)
VALUES (1, 1, 21), (2, 2, 5), (3, 3, 8), (4, 5, 2);
 

1.0

2.5

 INSERT INTO SalesOrderLine (id, productID, requiredQty)
VALUES (1, 1, 21), (2, 2, 5), (3, 3, 8), (4, 5, 5);
 

2.5

Комментарии:

1. 0080 отображается как 2 тогда, когда должно быть указано 0 . Потому что есть 0 1kg упорядоченный.

2. Обновлено с помощью выведенной логики. Дайте мне знать, как это работает для вас.

3. Можете ли вы помочь в этом? Если я выполняю этот запрос INSERT INTO SalesOrderLine (id, productID, requiredQty) VALUES (1, 1, 21), (2, 2, 5), (3, 3, 8), (4, 5, 1); , 001 столбец for Code InStockKg отображается как 103.50 , но так и должно быть 101 . Это связано с тем, 001 что размеры кода 1kg , упорядоченные в total 101kg , не включают 500g . Надеюсь, это поможет i.stack.imgur.com/UcQwr.png 500g Продукт просто войдет в оставшуюся колонку