как эффективно суммировать, когда строки должны быть в нескольких группах Oracle - PullRequest
0 голосов
/ 01 октября 2019

У меня есть несколько записей (более 1 миллиона), которые состоят из групп компаний, но некоторые записи принадлежат нескольким группам, и мне нужно получить общую сумму групп (основная (столбец C216) и вторичная (столбец LIST_OF_PARENT_CCN))

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

Я создал таблицу с группой компаний и суммами (RR_SRC_LEK_P5) и заполнил сумму курсором. Это решение работает, но медленно и неэффективно.

таблица RR_SRC_LEK_P5 выглядит следующим образом:

C216        LIST_OF_PARENT_CCN ESS_SUM
00004146    4523401            0
00005354    5487228, 2103188   0
00006203                       0
00007524    2196702, 2103188   0
00009164    2163921, 4523401   0

таблица RR_SRC_LEK_P6 содержит только общие суммы результата PARENT_CCN

PARENT_CCN ESS_SUM
4523401    258418650,7711
5487228    2534044,19664
2103188    13482783356,0255
2196702    9936875,58
2163921    141329781,3349

должно быть так, в столбце ESS_SUM есть только одно число

C216        LIST_OF_PARRENT_CCN ESS_SUM
00004146    4523401             258418650,7711
00005354    5487228, 2103188    2534044,19664 + 2534044,19664
00006203                        0
00007524    2196702, 2103188    9936875,58 + 13482783356,0255
00009164    2163921, 4523401    141329781,3349 + 4523401       

есть курсор, я использовал команду execute немедленный

 CREATE OR REPLACE PROCEDURE CURSOR_TEST AS 
    c_sql sys_refcursor;
    c_C216 RR_SRC_LEK_P5.C216%TYPE;
    c_LIST_OF_PARENT_CCN RR_SRC_LEK_P5.LIST_OF_PARENT_CCN%TYPE;

    BEGIN

         OPEN c_sql for 'select C216, LIST_OF_PARENT_CCN from RR_SRC_LEK_P5 where LIST_OF_PARENT_CCN is not null';
            LOOP 
              FETCH c_sql into c_C216, c_LIST_OF_PARENT_CCN; 
                EXIT WHEN c_sql%notfound;

                execute immediate 'update RR_SRC_LEK_P5 a set
                                   ESS_SUM = (select sum(ESS_SUM) from RR_SRC_LEK_P6 where PARENT_CCN in (' || c_LIST_OF_PARENT_CCN || '))
                                   where a.C216 = ''' || c_C216 || '''';

            END LOOP; 
          CLOSE c_sql;
          commit;
    END CURSOR_TEST;

есть ли лучший способ лучше, чем использовать курсор?

1 Ответ

4 голосов
/ 01 октября 2019

Вы можете использовать функцию aggregate с xmlquery:

Создание таблицы:

SQL> CREATE TABLE RR_SRC_LEK_P5  AS (
  2  SELECT '00004146' AS C216, '4523401' AS LIST_OF_PARENT_CCN, 0 AS ESS_SUM FROM DUAL UNION ALL
  3  SELECT '00005354',    '5487228, 2103188',   0 FROM DUAL UNION ALL
  4  SELECT '00006203',    NULL                  ,0 FROM DUAL UNION ALL
  5  SELECT '00007524',    '2196702, 2103188',   0 FROM DUAL UNION ALL
  6  SELECT '00009164',    '2163921, 4523401',   0 FROM DUAL);

Table created.

SQL> CREATE TABLE RR_SRC_LEK_P6 AS
  2  (SELECT 4523401 AS PARENT_CCN,    2584186507711 AS ESS_SUM  FROM DUAL UNION ALL
  3  SELECT 5487228,    253404419664    FROM DUAL UNION ALL
  4  SELECT 2103188,    134827833560255 FROM DUAL UNION ALL
  5  SELECT 2196702,    993687558       FROM DUAL UNION ALL
  6  SELECT 2163921,    1413297813349   FROM DUAL);

Table created.
SQL>

Просмотр текущих данных

SQL> select * from RR_SRC_LEK_P5;

C216     LIST_OF_PARENT_C    ESS_SUM
-------- ---------------- ----------
00004146 4523401                   0
00005354 5487228, 2103188          0
00006203                           0
00007524 2196702, 2103188          0
00009164 2163921, 4523401          0

SQL> select * from RR_SRC_LEK_P6;

PARENT_CCN                                 ESS_SUM
---------- ---------------------------------------
   4523401                           2584186507711
   5487228                            253404419664
   2103188                         134827833560255
   2196702                               993687558
   2163921                           1413297813349

SQL>

Запрос на обновление данных

SQL>
SQL> MERGE INTO RR_SRC_LEK_P5 P5
  2  USING ( SELECT P5.C216,
  3                  XMLQUERY(
  4                    LISTAGG(P6.ESS_SUM, '+') WITHIN GROUP (ORDER BY NULL)
  5                    RETURNING CONTENT ).GETNUMBERVAL() AS ESS_NEW
  6          FROM RR_SRC_LEK_P5 P5
  7          JOIN RR_SRC_LEK_P6 P6
  8              ON ( INSTR(', ' || P5.LIST_OF_PARENT_CCN || ',',
  9                         ', ' || P6.PARENT_CCN || ',') > 0 )
 10          GROUP BY P5.C216) RES
 11  ON ( P5.C216 = RES.C216 )
 12  WHEN MATCHED THEN
 13  UPDATE SET P5.ESS_SUM = RES.ESS_NEW;

4 rows merged.
SQL>

Обновленные данные

SQL> SELECT * FROM RR_SRC_LEK_P5;

C216     LIST_OF_PARENT_C                                 ESS_SUM
-------- ---------------- ---------------------------------------
00004146 4523401                                    2584186507711
00005354 5487228, 2103188                         135081237979919
00006203                                                        0
00007524 2196702, 2103188                         134828827247813
00009164 2163921, 4523401                           3997484321060

SQL>

DB <> Fiddle demo

Обновление

Для ваших настроек вам необходимо использовать следующий запрос:

MERGE INTO RR_SRC_LEK_P5 P5
    USING ( SELECT P5.C216,
                    XMLQUERY(
                      LISTAGG(
                      to_char(p6.ESS_SUM, 
                      'fm9999999999999999999999999999D099999999999999999',
                      'nls_numeric_characters = ''.,'''), '+') WITHIN GROUP (ORDER BY NULL)
                      RETURNING CONTENT ).GETNUMBERVAL() AS ESS_NEW
            FROM RR_SRC_LEK_P5 P5
            JOIN RR_SRC_LEK_P6 P6
                ON ( INSTR(', ' || P5.LIST_OF_PARENT_CCN || ',',
                          ', ' || P6.PARENT_CCN || ',') > 0 )
           GROUP BY P5.C216) RES
   ON ( P5.C216 = RES.C216 )
   WHEN MATCHED THEN
   UPDATE SET P5.ESS_SUM = RES.ESS_NEW;

Ура !!

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