【问题标题】:Oracle query to get a relational dataset result from multimensional tableOracle查询从多维表中获取关系数据集结果
【发布时间】:2019-06-30 16:04:38
【问题描述】:

我有一个多维/非关系的数据表。我正在尝试编写一个动态写出所有列名称并相关排列数据的查询。

该示例是一个显示 5 本书的简单表格。这些列显示了书中页面的大小。我正在寻找的结果集将有 3 列:BOOK_ID、PAGE、PAGE_SIZE。我已经包含了简单的代码来构建表格。

我已经设法通过使用联合查询来解决问题,但这对于大量列来说是不合理的。该数据集有近 100 列。

CREATE TABLE 
    BOOK_PAGE_SIZE 
        ( 
          BOOK_ID VARCHAR2(5)
        , SIZE_PAGE_1 NUMBER 
        , SIZE_PAGE_2 NUMBER
        , SIZE_PAGE_3 NUMBER
        , SIZE_PAGE_4 NUMBER
        , SIZE_PAGE_5 NUMBER
        );


INSERT INTO BOOK_PAGE_SIZE  VALUES ('T7001',10,35,0,0,0);
INSERT INTO BOOK_PAGE_SIZE  VALUES ('T7002',45,84,78,0,0);
INSERT INTO BOOK_PAGE_SIZE  VALUES ('T7003',28,65,12,32,0);
INSERT INTO BOOK_PAGE_SIZE  VALUES ('T7004',94,74,69,21,76);
INSERT INTO BOOK_PAGE_SIZE  VALUES ('T7005',91,23,14,61,46);

结果集:

  BOOK_ID  PAGE_NUMBER  PAGE_SIZE
   T70001     Page 1       10
   T70001     Page 2       35
   T70001     Page 3        0
   T70001     Page 4        0
   T70001     Page 5        0
   T70002     Page 1       45
   T70002     Page 2       84
   T70002     Page 3       78
   T70002     Page 4        0
   T70002     Page 5        0
   T70003     Page 1       28
   T70003     Page 2       65
   T70003     Page 3       12
   T70003     Page 4       32
   T70003     Page 5        0
   T70004     Page 1       94
   T70004     Page 2       74
   T70004     Page 3       69
   T70004     Page 4       21
   T70004     Page 5       76
   T70005     Page 1       91
   T70005     Page 2       23
   T70005     Page 3       14
   T70005     Page 4       61
   T70005     Page 5       46

【问题讨论】:

    标签: sql oracle unpivot


    【解决方案1】:

    你可以使用unpivot

    select *
      from  
      (
       with book_page_size(book_id,size_page_1,size_page_2,size_page_3,size_page_4,size_page_5) as
       (
        select 'T7001', 10, 35,  0,  0,  0 from dual union all
        select 'T7002', 45, 84, 78,  0,  0 from dual union all
        select 'T7003', 28, 65, 12, 32,  0 from dual union all
        select 'T7004', 94, 74, 69, 21, 76 from dual union all
        select 'T7005', 91, 23, 14, 61, 46 from dual 
       )
       select *
         from book_page_size a
      ) 
      unpivot (page_size for page_number in (size_page_1 as 'Page 1',
                                             size_page_2 as 'Page 2',
                                             size_page_3 as 'Page 3',
                                             size_page_4 as 'Page 4',
                                             size_page_5 as 'Page 5'))
      order by book_id, page_number;
    

    Demo

    【讨论】:

      【解决方案2】:

      正如 Barbaros Özhan 回答的那样,UNPIVOT 看起来是完成这项工作的好工具,而且它需要的代码更少。此外,您可以使用 SQL 查询来生成您想要的查询!我经常这样做。我创建了一个包含 20 个 SIZE_PAGE* 列的表来演示。

      select 'select book_id, ''Page ''||page_number as page_number, page_size from book_page_size' txt from dual union all
      select 'unpivot (' from dual union all
      select '  page_size for page_number in (' from dual union all
      select '    ' || column_name || ' as ' || replace(column_name, 'SIZE_PAGE_') ||
      case when lead(column_id) over(order by column_id) is not null
        then ','
      end
      from user_tab_columns
      where table_name = 'BOOK_PAGE_SIZE'
      and column_name != 'BOOK_ID'
      union all
      select ')) u' from dual union all
      select 'order by u.book_id, u.page_number' from dual;
      

      运行这个我得到以下查询:

      select book_id, 'Page '||page_number as page_number, page_size from book_page_size
      unpivot (
        page_size for page_number in (
          SIZE_PAGE_1 as 1,
          SIZE_PAGE_2 as 2,
          SIZE_PAGE_3 as 3,
          SIZE_PAGE_4 as 4,
          SIZE_PAGE_5 as 5,
          SIZE_PAGE_6 as 6,
          SIZE_PAGE_7 as 7,
          SIZE_PAGE_8 as 8,
          SIZE_PAGE_9 as 9,
          SIZE_PAGE_10 as 10,
          SIZE_PAGE_11 as 11,
          SIZE_PAGE_12 as 12,
          SIZE_PAGE_13 as 13,
          SIZE_PAGE_14 as 14,
          SIZE_PAGE_15 as 15,
          SIZE_PAGE_16 as 16,
          SIZE_PAGE_17 as 17,
          SIZE_PAGE_18 as 18,
          SIZE_PAGE_19 as 19,
          SIZE_PAGE_20 as 20
      )) u
      order by u.book_id, u.page_number
      

      当我运行查询时,结果是:

      BOOK_ID   PAGE_NUMBER  PAGE_SIZE   
      BK001     Page 1               1 
      BK001     Page 2               2 
      BK001     Page 3               3 
      BK001     Page 4               4 
      BK001     Page 5               5 
      BK001     Page 6               6 
      BK001     Page 7               7 
      BK001     Page 8               8 
      BK001     Page 9               9 
      BK001     Page 10             10 
      BK001     Page 11             11 
      BK001     Page 12             12 
      BK001     Page 13             13 
      BK001     Page 14             14 
      BK001     Page 15             15 
      BK001     Page 16             16 
      BK001     Page 17             17 
      BK001     Page 18             18 
      BK001     Page 19             19 
      BK001     Page 20             20 
      

      【讨论】:

      • 漂亮,这真的很有帮助。非常感谢!
      【解决方案3】:

      你可以使用一些联合所有

          select  BOOK_ID,  'Page 1'  PAGE_NUMBER, SIZE_PAGE_1 PAGE_SIZE
          from  BOOK_PAGE_SIZE 
          union all  
          select  BOOK_ID,  'Page 2'  , SIZE_PAGE_2
          from  BOOK_PAGE_SIZE 
          union all  
          select  BOOK_ID,  'Page 3'  , SIZE_PAGE_3
          from  BOOK_PAGE_SIZE 
          union all  
          select  BOOK_ID,  'Page 4'  , SIZE_PAGE_4
          from  BOOK_PAGE_SIZE 
          union all  
          select  BOOK_ID,  'Page 5'  , SIZE_PAGE_5
          from  BOOK_PAGE_SIZE 
          order by BOOK_ID PAGE_NUMBER, PAGE_SIZE
      

      但你不应该使用你应该规范化你的架构的列集

      【讨论】:

      • 这是我的第一个想法,但是当您查看超过 100 列时,这变得不合理。好主意,这就是我目前的想法。
      • 理想情况下,我希望表标准化,但是输出数据的系统使用这种结构。我们正在努力进行开发以改变这一点,但同时需要一个可行的解决方法。我之前提到的你的答案是有效的,只是太费力了。