Как продублировать строку с условием - PullRequest
0 голосов
/ 27 августа 2018

У меня есть набор данных:

SELECT '1' ID, '30' CurrQty, '100' ReqQty FROM dual
UNION ALL SELECT '1' ID, '30' CurrQty, '100' ReqQty FROM dual
UNION ALL SELECT '1' ID, '20' CurrQty, '100' ReqQty FROM dual
UNION ALL SELECT '2' ID, '100' CurrQty, '100' ReqQty FROM dual

ID CURRQTY REQQTY
-- ------- ------
1  30      100   
1  30      100   
1  20      100   
2  100     100   

Я бы хотел получить что-то вроде этого:

ID | CurrQty | ReqQty
1  |   30    | 100
1  |   30    | 100
1  |   20    | 100
1  |   20    | 100   - created a new line ReqQty - Sum(CurrQty)
2  |  100    | 100

Если Sum(CurrQty) для того же Id меньше ReqQty, то создайте новую строку с другим ReqQty - Sum(CurrQty).

Я пробовал что-то подобное, но он создавал дубликаты для каждой строки, и я хочу создать только 1 новую строку в группе Id:

WITH levels AS (
   SELECT LEVEL AS lvl
   FROM DUAL
   CONNECT BY LEVEL <= 2)
   SELECT * FROM (
SELECT id, CurrQty, ReqQty, SUM (CurrQty) OVER (PARTITION BY ID) AS sum_for_id
FROM (
SELECT '1' ID, '30' CurrQty, '100' ReqQty FROM dual
UNION ALL SELECT '1' ID, '30' CurrQty, '100' ReqQty FROM dual
UNION ALL SELECT '1' ID, '20' CurrQty, '100' ReqQty FROM dual
UNION ALL SELECT '2' ID, '100' CurrQty, '100' ReqQty FROM dual
)) INNER JOIN LEVELS ON (lvl = 1 OR sum_for_id <ReqQty)

ID CURRQTY REQQTY SUM_FOR_ID        LVL
-- ------- ------ ---------- ----------
1  30      100            80          1
1  30      100            80          1
1  20      100            80          1
2  100     100           100          1
1  30      100            80          2
1  30      100            80          2
1  20      100            80          2

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Как ни странно, в выходных данных вы не выделяете «добавленные» строки - как вы собираетесь отличать их от исходных в отчете или при дальнейшей обработке?

Во всяком случае, это не мое дело. Затем: Почему количество строк, а не чисел? Это действительно не имеет смысла; в моих смоделированных данных я изменил это.

Вы не сказали, что вы хотите, чтобы произошло, когда reqqty меньше суммы currqty или как следует обрабатывать любые возможные null. Я предположил, что нигде нет null, и если reqqty меньше суммы currqty, вам не нужно ничего делать для этого клиента (кроме вывода исходных строк).

Является ли reqqty одинаковым во всех строках для данного клиента? Это единственный способ, которым ваш вопрос имеет смысл; но если то, что вы показываете, является базовой таблицей (а не результатом какого-либо соединения), то ваша таблица нарушает третью нормальную форму. Вы можете рассмотреть это.

Вот очень простой и быстрый способ сделать то, что вам нужно. Я не заказывал вывод, так как ты мало об этом говорил.

with
  dataset(id, currqty, reqqty) as (
    select '1',  30, 100 from dual union all
    select '1',  30, 100 from dual union all
    select '1',  20, 100 from dual union all
    select '2', 100, 100 from dual
  )
select     id, currqty, reqqty
  from     dataset
union all
select     id, min(reqqty) - sum(currqty) as currqty, min(reqqty) as reqqty
  from     dataset
  group by id
  having   sum(currqty) < min(reqqty)
-- ORDER BY <whatever>; ORDER BY applies to the result of UNION ALL.
;

ID    CURRQTY     REQQTY
-- ---------- ----------
1          30        100
1          30        100
1          20        100
2         100        100
1          20        100
0 голосов
/ 27 августа 2018

Вы можете сделать это в два этапа. Сначала вы можете увидеть, достигли ли вы требования с помощью функции аналитической суммы:

-- CTE for sample data
with your_table (id, currqty, reqqty) as (
            select 1, 30, 100 from dual
  union all select 1, 30, 100 from dual
  union all select 1, 20, 100 from dual
  union all select 2, 100, 100 from dual
)
-- actual query
select id, currqty, reqqty,
  sum(currqty) over (partition by id) as totalqty
from your_table;

ID    CURRQTY     REQQTY   TOTALQTY
-- ---------- ---------- ----------
 1         30        100         80
 1         30        100         80
 1         20        100         80
 2        100        100        100

, а затем используйте его в качестве CTE, добавив вторую аналитическую функцию, чтобы выбрать любую строку для каждого идентификатора, чтобы использовать ее в качестве основы для дополнительного (при необходимости), и объединяя два запроса вместе:

with your_table (id, currqty, reqqty) as (
            select 1, 30, 100 from dual
  union all select 1, 30, 100 from dual
  union all select 1, 20, 100 from dual
  union all select 2, 100, 100 from dual
),
cte (id, currqty, reqqty, totalqty, rn) as (
  select id, currqty, reqqty,
    sum(currqty) over (partition by id),
    row_number() over (partition by id order by null)
  from your_table
)
select id, currqty, reqqty
from cte
union all
select id, reqqty - totalqty, reqqty
from cte
where totalqty < reqqty
and rn = 1;

ID    CURRQTY     REQQTY
-- ---------- ----------
 1         30        100
 1         30        100
 1         20        100
 2        100        100
 1         20        100

Первая ветвь объединения просто получает ваши исходные данные через CTE. Вторая ветвь ищет только одну строку для любого идентификатора, где сумма не соответствует требованию, и генерирует новую строку для этого идентификатора для разницы.

Если вы не хотите использовать вторую аналитическую функцию, вместо этого вы можете использовать запрос distinct:

...
select id, currqty, reqqty
from cte
union all
select distinct id, reqqty - totalqty, reqqty
from cte
where totalqty < reqqty;

Кстати, я предположил, что все ваши значения на самом деле являются числами, а не строками; хранение количеств или числовых идентификаторов или любых других числовых значений в виде строки не имеет большого смысла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...