【问题标题】:PL/SQL - SQL dynamic row and column parsingPL/SQL - SQL 动态行列解析
【发布时间】:2018-05-31 23:29:29
【问题描述】:

我浏览了论坛,并没有真正找到我需要的东西。

我有两张表一张表(Parse_Table)

File_ID|Start_Pos|Length|Description
------------------------------------
   1   |    1    |   9  |    Pos1
   1   |    10   |   1  |    Pos2
   1   |    11   |   1  |    Pos3
   2   |    1    |   4  |    Pos1
   2   |    5    |   7  |    Pos2

还有另一个需要解析的表,如 (Input_file)

String
ABCDEFGHI12
ASRQWERTQ45
123456789AB
321654852PO

我想得到结果,如果我把它放在哪里,它将使用这个特定的解析规范

select DESCRIPTION, Start_pos,Length from Parse_table where File_ID=1

并且能够解析输入文件

String      |    Pos1  |Pos2|Pos3
---------------------------------
ABCDEFGHI12 |ABCDEFGHI |  1 |  2
ASRQWERTQ45 |ASRQWERTQ |  4 |  5
123456789AB |123456789 |  A |  B
321654852PO |321654852 |  P |  O

或者,如果我输入 file_id=2,它会以不同的方式解析值。

我查看了使用 Pivot 函数,但看起来列数是静态的,至少据我所知。

提前感谢您的支持,请让我知道我可以在 SQL 中做什么。

【问题讨论】:

  • @a_horse_with_no_name 您好,感谢您的快速回复,我正在使用 PL/SQL 开发人员
  • 文件 ID 的解析条目数是否有上限?列标题是否应该来自描述?是否有可以为您进行转换的报告层?
  • @AlexPoole 嗨,file_id 没有最大条目数,是的,列标题来自描述,我也不相信至少可以使用报告层据我所知。谢谢
  • 没有办法让你的输入文件file_id, string 在这种情况下这是一个真正简单的解决方案

标签: sql oracle pivot


【解决方案1】:

假设预期的最大字段数有上限,您可以使用标准解码技巧来“接近”地旋转表格。

SQL> create table t ( fid int, st int, len int, pos varchar2(10));

Table created.

SQL>
SQL> insert into t values (   1   ,    1    ,   9  ,    'Pos1');

1 row created.

SQL> insert into t values (   1   ,    10   ,   1  ,    'Pos2');

1 row created.

SQL> insert into t values (   1   ,    11   ,   1  ,    'Pos3');

1 row created.

SQL> insert into t values (   2   ,    1    ,   4  ,    'Pos1');

1 row created.

SQL> insert into t values (   2   ,    5    ,   7  ,    'Pos2');

1 row created.

SQL>
SQL> create table t1 ( s varchar2(20));

Table created.

SQL>
SQL> insert into t1 values ('ABCDEFGHI12');

1 row created.

SQL> insert into t1 values ('ASRQWERTQ45');

1 row created.

SQL> insert into t1 values ('123456789AB');

1 row created.

SQL> insert into t1 values ('321654852PO');

1 row created.

SQL>
SQL>
SQL> select
  2    t1.s,
  3    max(decode(t.seq,1,substr(t1.s,t.st,t.len))) c1,
  4    max(decode(t.seq,2,substr(t1.s,t.st,t.len))) c2,
  5    max(decode(t.seq,3,substr(t1.s,t.st,t.len))) c3,
  6    max(decode(t.seq,4,substr(t1.s,t.st,t.len))) c4,
  7    max(decode(t.seq,5,substr(t1.s,t.st,t.len))) c5,
  8    max(decode(t.seq,6,substr(t1.s,t.st,t.len))) c6
  9  from t1,
 10       ( select t.*, row_number() over ( partition by fid order by st ) as seq
 11         from t
 12         where fid = 1
 13       ) t
 14  group by t1.s
 15  order by 1;

S                    C1            C2            C3            C4            C5            C6
-------------------- ------------- ------------- ------------- ------------- ------------- -------------
123456789AB          123456789     A             B
321654852PO          321654852     P             O
ABCDEFGHI12          ABCDEFGHI     1             2
ASRQWERTQ45          ASRQWERTQ     4             5

4 rows selected.

SQL>
SQL> select
  2    t1.s,
  3    max(decode(t.seq,1,substr(t1.s,t.st,t.len))) c1,
  4    max(decode(t.seq,2,substr(t1.s,t.st,t.len))) c2,
  5    max(decode(t.seq,3,substr(t1.s,t.st,t.len))) c3,
  6    max(decode(t.seq,4,substr(t1.s,t.st,t.len))) c4,
  7    max(decode(t.seq,5,substr(t1.s,t.st,t.len))) c5,
  8    max(decode(t.seq,6,substr(t1.s,t.st,t.len))) c6
  9  from t1,
 10       ( select t.*, row_number() over ( partition by fid order by st ) as seq
 11         from t
 12         where fid = 2
 13       ) t
 14  group by t1.s
 15  order by 1;

S                    C1            C2            C3            C4            C5            C6
-------------------- ------------- ------------- ------------- ------------- ------------- -------------
123456789AB          1234          56789AB
321654852PO          3216          54852PO
ABCDEFGHI12          ABCD          EFGHI12
ASRQWERTQ45          ASRQ          WERTQ45

4 rows selected.

如果您真的希望该结果仅返回所需的列数和自定义列名,那么您就进入了动态 SQL 领域。你将如何解决这个问题取决于你提供数据的工具。如果它可以使用 REF CURSOR,那么一点点 PL/SQL 就可以解决问题。

【讨论】:

    【解决方案2】:

    可以从 SQL 语句返回未知数量的列,但它需要使用 PL/SQL、ANY 类型和 Oracle Data Cartridge 构建的代码。

    该代码很难编写,但您可以从我的开源项目 Method4 开始。下载,解压,@install,然后 编写 SQL 语句,生成 SQL 语句。

    查询

    select * from table(method4.dynamic_query(
        q'[
            --Create a SQL statement to query PARSE_FILE.
            select
                'select '||
                    listagg(column_expression, ',') within group (order by start_pos) ||
                    ' from parse_file'
                column_expressions
            from
            (
                --Create individual SUBSTR column expressions.
                select
                    parse_table.*,
                    'substr(string, '||start_pos||', '||length||') '||description column_expression
                from parse_table
                --CHANGE BELOW LINE TO USE A DIFFERENT FILE:
                where file_id = 2
                order by start_pos
            )
        ]'
    ));
    

    示例架构

    create table parse_table as
    select 1 file_id, 1  start_pos, 9 length, 'Pos1' description from dual union all
    select 1 file_id, 10 start_pos, 1 length, 'Pos2' description from dual union all
    select 1 file_id, 11 start_pos, 1 length, 'Pos3' description from dual union all
    select 2 file_id, 1  start_pos, 4 length, 'Pos1' description from dual union all
    select 2 file_id, 5  start_pos, 7 length, 'Pos2' description from dual;
    
    create table parse_file as
    select 'ABCDEFGHI12' string from dual union all
    select 'ASRQWERTQ45' string from dual union all
    select '123456789AB' string from dual union all
    select '321654852PO' string from dual;
    

    结果

    FILE_ID = 1:

    POS1        POS2   POS3
    ----        ----   ----
    ABCDEFGHI   1      2
    ASRQWERTQ   4      5
    123456789   A      B
    321654852   P      O
    

    FILE_ID = 2

    POS1   POS2
    ----   ----
    ABCD   EFGHI12
    ASRQ   WERTQ45
    1234   56789AB
    3216   54852PO
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-29
      • 2012-04-03
      • 2019-01-23
      相关资源
      最近更新 更多