Наборы из одной таблицы, сгруппированные по столбцу - PullRequest
0 голосов
/ 05 апреля 2019

У меня есть таблица:

+-------+-------+----------+
| GROUP | State | Priority |
+-------+-------+----------+
|   1   |  MI   |     1    |
|   1   |  IA   |     2    |
|   1   |  CA   |     3    |
|   1   |  ND   |     4    |
|   1   |  AZ   |     5    |
|   2   |  IA   |     2    |
|   2   |  NJ   |     1    |
|   2   |  NH   |     3    |

And so on...

Как мне написать запрос, который делает все наборы состояний по группам в порядке приоритета? Вот так:

+-------+--------------------+
| GROUP |        SET         |
+-------+--------------------+
|   1   | MI                 |
|   1   | MI, IA             |
|   1   | MI, IA, CA         |
|   1   | MI, IA, CA, ND     |
|   1   | MI, IA, CA, ND, AZ |
|   2   | NJ                 |
|   2   | NJ, IA             |
|   2   | NJ, IA, NH         |
+-------+--------------------+

Это похоже на мой вопрос здесь , и я попытался изменить это решение, но у меня всего лишь сорок ваттная лампа, а это проблема в шестьдесят ватт ...

Ответы [ 2 ]

2 голосов
/ 05 апреля 2019

Эта проблема на самом деле выглядит проще, чем ответ на заданный вами вопрос, который является отличным решением этой проблемы.Тем не менее, при этом используются те же иерархические запросы, что и connect by

. В случае, когда priority всегда является непрерывной последовательностью чисел, это будет работать

SELECT t.grp, level, ltrim(SYS_CONNECT_BY_PATH(state,','),',')   as "set"  
   from  t 
   start with priority = 1
 connect by   priority = prior priority + 1
            and grp = prior grp

Однакоесли это не всегда так, нам потребуется row_number() для определения последовательности на основе порядка приоритета (который не обязательно должен быть последовательным целым числом)

with t2 AS
( 
  select t.*, row_number() 
        over ( partition by grp order by priority) as rn from t
)
SELECT t2.grp, ltrim(SYS_CONNECT_BY_PATH(state,','),',')   as "set"
   from  t2 
   start with priority = 1
 connect by   rn = prior rn + 1
            and grp = prior grp

DEMO

0 голосов
/ 06 апреля 2019

Я понимаю, что на этот вопрос уже дан ответ, но я хотел посмотреть, смогу ли я сделать это, используя стандартный синтаксис ANSI.«connect by» - только функция Oracle, для нескольких баз данных будут работать следующие функции:

WITH
    -- ASET is just setting up the sample dataset
    aset AS
        (SELECT 1 AS grp, 'MI' AS state, 1 AS priority FROM DUAL
         UNION ALL
         SELECT 1 AS grp, 'IA', 2 FROM DUAL
         UNION ALL
         SELECT 1 AS grp, 'CA', 3 FROM DUAL
         UNION ALL
         SELECT 1 AS grp, 'ND', 4 FROM DUAL
         UNION ALL
         SELECT 1 AS grp, 'AZ', 5 FROM DUAL
         UNION ALL
         SELECT 2 AS grp, 'IA', 2 FROM DUAL
         UNION ALL
         SELECT 2 AS grp, 'NJ', 1 FROM DUAL
         UNION ALL
         SELECT 2 AS grp, 'NH', 3 FROM DUAL),
    bset AS
        -- In BSET we convert the ASET records into comma separated values
        (  SELECT grp, LISTAGG( state, ',' ) WITHIN GROUP (ORDER BY priority) AS set1
             FROM aset
         GROUP BY grp),
    cset ( grp
         , set1
         , set2
         , pos ) AS
        -- CSET breaks our comma separated values up into multiple rows
        -- Each row adding the next CSV value
        (SELECT grp                                                         AS grp
              , set1                                                        AS set1
              , SUBSTR( set1 || ',', 1, INSTR( set1 || ',', ',' ) - 1 )     AS set2
              , 1                                                           AS pos
           FROM bset
         UNION ALL
         SELECT grp              AS grp
              , set1             AS set1
              , SUBSTR( set1 || ','
                      , 1
                      ,   INSTR( set1 || ','
                               , ','
                               , 1
                               , pos + 1 )
                        - 1 )    AS set2
              , pos + 1          AS pos
           FROM cset
          WHERE INSTR( set1 || ','
                     , ','
                     , 1
                     , pos + 1 ) > 0)
  SELECT grp, set2
    FROM cset
ORDER BY grp, pos;
...