Я хотел бы решить абстрактную проблему, которая неоднократно возникала в моей истории SQL.Эту абстрактную проблему можно лучше понять, если мы представим, что мы являемся сбытовой компанией, и поговорим о деталях (продуктах), которые мы хотим продать, которые необходимы для них в разные даты в разных количествах.С другой стороны, у нас есть наши «возможности заполнения», например, количества, поступающие со склада, производства, закупки в разные даты и количества.
Я бы хотел удовлетворить эти потребности, упорядоченные к необходимой дате и доступной датеиспользуя только один запрос (без процедуры, без временных таблиц).
В качестве технической базы можно предположить, что у вас есть две таблицы:
- NEED_TABLE, в которой перечислены несколько потребностей, требуемая дата и количества.
- FILL_TABLE, в котором перечислены несколько «заливок», доступные даты и количества.
В моем примере есть две потребности:
- Необходимость A:нам нужно партно 123 в кол-во 4 на дату 01/02/2019
- нужен Б: нам нужно партно 123 в кол-во 2 на дату 06/02/2019
И у нас есть два«заполняет» в разных количествах:
- Заполнить X: у нас есть партно 123 в кол-во 2 в заказе на покупку, доступно 01/01/2019
- Заполнить Y: у нас парно 123в кол-во 4 в заказе на поставку, доступно 06/01/2019
Результат должен быть:
- Мне нужно partno 123 с номером 4 в 1/2/2019 («Нужна A»), который заполняется заказом на покупку в количестве 2 («Заполнить X»)) и другим заказом на покупку в кол-во 2 («Заполнить Y» - частично).
- Мне нужно partno 123 с кол-во 2 от 02.06.2009 («Need B»), который заполняется покупкойпорядок в кол-во 2 («Заполнить Y» - частично).
SQL-запрос:
with
NEED_TABLE
as
(select 'A' NEED_ID, 123 partno, to_date('01/02/2019', 'MM/DD/YYYY') DATE_NEEDED, 4 NEED_QTY from dual
union all
select 'B' NEED_ID, 123 partno, to_date('06/02/2019', 'MM/DD/YYYY') DATE_NEEDED, 2 NEED_QTY from dual),
FILL_TABLE
as
(select 'X' FILL_ID, 123 partno, to_date('01/01/2019', 'MM/DD/YYYY') DATE_AVAILABLE, 2 FILL_QTY from dual
union all
select 'Y' FILL_ID, 123 partno, to_date('06/01/2019', 'MM/DD/YYYY') DATE_AVAILABLE, 4 FILL_QTY from dual)
select NEED_TABLE.NEED_ID
, NEED_TABLE.PARTNO
, NEED_TABLE.DATE_NEEDED
, NEED_TABLE.NEED_QTY
, FILL_TABLE.FILL_ID
, FILL_TABLE.DATE_AVAILABLE
, FILL_TABLE.FILL_QTY
/* all following is wrong/incomplete */
, lag(need_QTY - fill_QTY, 1, need_QTY)
over(
partition by NEED_ID
order by DATE_NEEDED, DATE_AVAILABLE) REAL_NEED_QTY
, greatest(
lag(need_QTY - fill_QTY, 1, need_QTY)
over(
partition by NEED_ID
order by DATE_NEEDED, DATE_AVAILABLE)
- FILL_QTY
, 0) LEFT_NEED_QTY
, abs(
least(
lag(need_QTY - fill_QTY, 1, need_QTY)
over(
partition by NEED_ID
order by DATE_NEEDED, DATE_AVAILABLE)
- FILL_QTY
, 0)) LEFT_FILL_QTY
from NEED_TABLE, FILL_TABLE
order by DATE_NEEDED, DATE_AVAILABLE;
Если вы проверите результат этого запроса, все будет хорошо дляпервый NEED_ID "A".Но так как он продолжается с NEED_ID «B», он не помнит, что FILL_IDs X и Y уже были уменьшены, а для заполнения требуется «A».
Я ожидаю такой результат:
NEED_ID A is filled by FILL_ID X qty 2
NEED_ID A is filled by FILL_ID Y qty 2
(NEED_ID A is filled by FILL_ID X qty 0)
NEED_ID B is filled by FILL_ID Y qty 2
NEED_TABLE:
| NEED_ID | PARTNO | DATE_NEEDED | NEED_QTY |
|---------|--------|-------------|----------|
| A | 123 | 01/02/2019 | 4 |
| B | 123 | 06/02/2019 | 2 |
FILL_TABLE:
| FILL_ID | PARTNO | DATE_AVAILABLE | FILL_QTY |
|---------|--------|----------------|----------|
| X | 123 | 01/01/2019 | 2 |
| Y | 123 | 06/01/2019 | 4 |
Ожидаемый результат запроса:
| NEED_ID | PARTNO | DATE_NEEDED | NEED_QTY | FILL_ID | DATE_AVAILABLE | FILL_QTY | ***REAL_FILL*** | "WHY?" |
|---------|--------|-------------|----------|---------|----------------|----------|-----------------|---------------------------------------------------------------------|
| A | 123 | 01/02/2019 | 4 | X | 01/01/2019 | 2 | 2 | A needs 4, gets partially filled by X by 2 |
| A | 123 | 01/02/2019 | 4 | Y | 06/01/2019 | 4 | 2 | A still needs 2, gets completely filled by Y by 2 |
| B | 123 | 06/02/2019 | 2 | X | 01/01/2019 | 2 | 0 | B needs 2, can't get filled by X, because A already used that qty |
| B | 123 | 06/02/2019 | 2 | Y | 06/01/2019 | 4 | 2 | B still needs 2, gets completely filled by remaining qty of Y, by 2 |
Любая помощь очень ценится - спасибо!