Oracle 10g: агрегация - PullRequest
       2

Oracle 10g: агрегация

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

Получил следующие таблицы:

Таблица T

DATE_A    | DATE_B    | ERRCODE 
----------+-----------+--------
01/MAY/13 | 01/JUN/15 | X
01/DEC/17 | 01/FEB/18 | Y

Таблица U

ERRCODE | ERRDESC
--------+-------------------------------------------
X       | Conflicting from : {1} and to Period : {2}
Y       | Periods : {1} and {2} overlap

Следующий код:

select period, wm_concat(errcode) as issues
from ((select DATE_A as period, errcode from T where DATE_A is not null) union all
      (select DATE_B, errcode from T where DATE_B is not null)
     ) di
group by period
order by period;

преобразует Table T следующим образом:

PERIOD    | ISSUES
----------+--------
01/MAY/13 | X
01/JUN/15 | X
01/DEC/17 | Y
01/FEB/18 | Y

Я хотел бы преобразовать приведенный выше код так, чтобы:

  • заменяет ERRCODE из таблицы T на соответствующую ERRDESC из таблицы U
  • заменить {1} и {2} в ERRDESC соответственно DATE_A и DATE_B
  • Вставить результат в Table V

Итак, я попробовал это:

INSERT INTO v (
    period,
    issues
)
    SELECT
        period,
        wm_concat(issue) AS issues
    FROM
        (
            SELECT
                t.date_a AS period,
                replace( (
                    SELECT
                        u.errdesc AS issue
                    FROM
                        u
                    WHERE
                        t.errcode = u.errcode
                ),'{1}', t.date_a) AS issue
            FROM
                t
            WHERE
                t.date_a IS NOT NULL
            UNION ALL
            SELECT
                t.date_b,
                replace( (
                    SELECT
                        u.errdesc AS issue
                    FROM
                        u
                    WHERE
                        t.errcode = u.errcode
                ),'{2}', t.date_b)
            FROM
                t
            WHERE
                t.date_b IS NOT NULL
        ) di
    GROUP BY
        period;

Но я получаю это (Table V):

PERIOD    | ISSUES
----------+--------
01/MAY/13 | Conflicting from : 01/MAY/13 and to Period : {2}
01/JUN/15 | Conflicting from : {1} and to Period : 01/JUN/15
01/DEC/17 | Periods : 01/DEC/17 and {2} overlap
01/FEB/18 | Periods : {1} and 01/FEB/18 overlap

Вместо результата, который я ищу (Table V):

PERIOD    | ISSUES
----------+--------
01/MAY/13 | Conflicting from : 01/MAY/13 and to Period : 01/JUN/15
01/JUN/15 | Conflicting from : 01/MAY/13 and to Period : 01/JUN/15
01/DEC/17 | Periods : 01/DEC/17 and 01/FEB/18 overlap
01/FEB/18 | Periods : 01/DEC/17 and 01/FEB/18 overlap

Причина в том, что все селекторы до объединения не знают о date_b, а селекторы после не знают о date_a.

Вопрос

Как изменить последний код, чтобы получить ожидаемый результат?

Примечание

CREATE TABLE T
   (     
    "DATE_A" DATE, 
    "DATE_B" DATE, 
    "ERRCODE" VARCHAR2(2)
   )  ;

Insert into T (DATE_A,DATE_B,ERRCODE) values (to_date('01/MAY/13','DD/MON/RR'),to_date('01/JUN/15','DD/MON/RR'),'X');
Insert into T (DATE_A,DATE_B,ERRCODE) values (to_date('01/DEC/17','DD/MON/RR'),to_date('01/FEB/18','DD/MON/RR'),'Y');

CREATE TABLE U
   (     
    "ERRCODE"  VARCHAR2(2), 
    "ERRDESC"  VARCHAR2(100)
   )  ;

Insert into U (ERRCODE, ERRDESC) values ('X','Conflicting from : {1} and to Period : {2}');
Insert into U (ERRCODE, ERRDESC) values ('Y','Periods : {1} and {2} overlap');

CREATE TABLE V
   (     
    "PERIOD"  DATE, 
    "ISSUES"  VARCHAR2(100)
   )  ;

commit;

Ответы [ 2 ]

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

Получил работу с простым решением (ниже):

INSERT INTO v (
    period,
    issues
)
    SELECT
        period,
        wm_concat(issue) AS issues
    FROM
        (
            SELECT
                date_a AS period,
                replace(replace( (
                    SELECT 
                        u.errdesc AS issue
                    FROM
                        u
                    WHERE
                        t.errcode = u.errcode
                ),'{1}',t.date_a),'{2}',t.date_b) AS issue
            FROM
                t
            WHERE
                date_a IS NOT NULL
            UNION ALL
            SELECT
                date_b,
                replace(replace( (
                    SELECT 
                        u.errdesc AS issue
                    FROM
                        u
                    WHERE
                        t.errcode = u.errcode
                ),'{1}',t.date_a),'{2}',t.date_b)
            FROM
                t
            WHERE
                date_b IS NOT NULL
        ) di
    GROUP BY
        period;

EDIT:

Однако решение Boneist лучше.

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

Я бы сделал так, чтобы сначала объединить две таблицы и заполнить значения в столбце описания ошибки, а затем разбить их на две строки, например:

INSERT INTO v (period, issues)
WITH t AS (SELECT to_date('01/05/2013', 'dd/mm/yyyy') date_a, to_date('01/06/2015', 'dd/mm/yyyy') date_b, 'X' errcode FROM dual UNION ALL
           SELECT to_date('01/12/2017', 'dd/mm/yyyy') date_a, to_date('01/02/2018', 'dd/mm/yyyy') date_b, 'Y' errcode FROM dual),
     u AS (SELECT 'X' errcode, 'Conflicting from : {1} and to Period : {2}' errdesc FROM dual UNION ALL
           SELECT 'Y' errcode, 'Periods : {1} and {2} overlap' errdesc FROM dual),
 dummy AS (SELECT LEVEL rn FROM dual CONNECT BY LEVEL <= 2),
   res AS (SELECT t.date_a,
                  t.date_b,
                  REPLACE(REPLACE(u.errdesc, '{1}', to_char(t.date_a, 'dd/MON/yyyy', 'nls_date_language = english')), '{2}', to_char(t.date_b, 'dd/MON/yyyy', 'nls_date_language = english')) errdesc
           FROM   t
                  INNER JOIN u ON t.errcode = u.errcode)
SELECT CASE WHEN d.rn = 1 THEN res.date_a
            WHEN d.rn = 2 THEN res.date_b
       END period,
       errdesc
FROM   res
       CROSS JOIN dummy d
ORDER BY res.date_a, d.rn;

PERIOD      ERRDESC
----------- --------------------------------------------------------------------------------
01/05/2013  Conflicting from : 01/MAY/2013 and to Period : 01/JUN/2015
01/06/2015  Conflicting from : 01/MAY/2013 and to Period : 01/JUN/2015
01/12/2017  Periods : 01/DEC/2017 and 01/FEB/2018 overlap
01/02/2018  Periods : 01/DEC/2017 and 01/FEB/2018 overlap

Это своего рода разворот; если бы вы были в 11g или выше, вы могли бы воспользоваться командой UNPIVOT, чтобы разбить строки на две части. Он работает путем создания фиктивного подзапроса, который содержит необходимое количество строк, которые вы хотите вывести для каждой из ваших входных строк - в вашем случае это 2.

Затем мы можем перекрестно соединить это с основным набором результатов, что означает, что строки дублируются. Тогда нужно просто решить, какие столбцы показывать в каждой строке, и вуаля!

Просто пара заметок о датах:

  • Пожалуйста, всегда явно конвертируйте ваши даты в строки, а не полагайтесь на параметр nls_date_format; то, что вы могли бы иметь в своем сеансе, может полностью отличаться от того, что было у другого.
  • Годы имеют четыре цифры. Пожалуйста, не используйте 2 цифры и не заставляйте Oracle угадывать, особенно если вы знаете информацию заранее! Может случиться, что вы получите неожиданный результат от использования маски формата 'RR'.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...