【问题标题】:Convert 1 column to 2 columns in Oracle SQL在 Oracle SQL 中将 1 列转换为 2 列
【发布时间】:2020-09-04 01:24:10
【问题描述】:

我们得到以下格式的数据,我可以使用正则表达式查询进行转换。数据是与管道连接的任务的开始和结束数据。

数据:

|2020/04/26|2020/05/02|2020/05/03|2020/05/10 

查询:

select   REGEXP_SUBSTR (:p, '[^|]+', 1, level) as periods from dual
connect by  level <= length (regexp_replace(:p, '[^|]+'))

结果:

2020/04/26
2020/05/02
2020/05/03
2020/05/10

我们需要将它与开始日期和结束日期分开。开始日期和结束日期组合的数量是动态的。但是开始日期会有结束日期,我们不会为空。

预期结果

START DATE      END DATE 
2020/04/26      2020/05/02
2020/05/03      2020/05/10

提前致谢。

【问题讨论】:

  • 在继续之前,您应该尝试修复损坏的数据模型。

标签: sql oracle date oracle11g recursive-query


【解决方案1】:

如果您有一个或多个输入行,则该解决方案将起作用(而如果您向其输入多于一行数据,分层查询将生成呈指数增长的重复行数)。

将日期对转换为 XML,然后使用XMLTABLE 进行转换:

SELECT id,
       x.*
FROM   test_data t
       CROSS JOIN
       XMLTABLE(
         ( LTRIM(
             REGEXP_REPLACE(
               t.value,
               '\|(\d{4}/\d{2}/\d{2})\|(\d{4}/\d{2}/\d{2})',
               ',<row><start>\1</start><end>\2</end></row>'
             ),
             ','
           )
         )
         COLUMNS
           start_date DATE PATH '/row/start',
           end_date   DATE PATH '/row/end'
       ) x

所以,对于您的测试数据:

CREATE TABLE test_data ( id, value ) AS
SELECT 1, '|2020/04/26|2020/05/02|2020/05/03|2020/05/10' FROM DUAL UNION ALL
SELECT 2, '|2020/06/01|2020/06/02' FROM DUAL

这个输出:

身份证 | START_DATE |结束日期 -: | :--------- | :-------- 1 | 20 年 4 月 26 日 | 20 年 5 月 2 日 1 | 20 年 5 月 3 日 | 20 年 5 月 10 日 2 | 01-JUN-20 | 20 年 6 月 2 日

db小提琴here


或者,如果您只有一个输入,您可以成对拆分数据:

SELECT REGEXP_SUBSTR ( :p, '\|(\d{4}/\d{2}/\d{2})\|(\d{4}/\d{2}/\d{2})', 1, level, NULL, 1 ) as start_date,
       REGEXP_SUBSTR ( :p, '\|(\d{4}/\d{2}/\d{2})\|(\d{4}/\d{2}/\d{2})', 1, level, NULL, 2 ) as end_date
FROM   DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( :p, '\|(\d{4}/\d{2}/\d{2})\|(\d{4}/\d{2}/\d{2})' )

哪些输出:

START_DATE |结束日期 :--------- | :--------- 2020/04/26 | 2020/05/02 2020/05/03 | 2020/05/10

db小提琴here

或使用:

SELECT *
FROM   XMLTABLE(
         ( LTRIM(
             REGEXP_REPLACE(
               :p,
               '\|(\d{4}/\d{2}/\d{2})\|(\d{4}/\d{2}/\d{2})',
               ',<row><start>\1</start><end>\2</end></row>'
             ),
             ','
           )
         )
         COLUMNS
           start_date DATE PATH '/row/start',
           end_date   DATE PATH '/row/end'
       )

db小提琴here

【讨论】:

    【解决方案2】:

    你可以做算术和条件聚合:

    select 
        max(case when mod(lvl, 2) = 0 then periods end) start_date,
        max(case when mod(lvl, 2) = 1 then periods end) end_date
    from (
        select 
            regexp_substr (:p, '[^|]+', 1, level) as periods,
            level - 1 as lvl
        from dual
        connect by  level <= length (regexp_replace(:p, '[^|]+'))
    ) t
    group by trunc(lvl / 2)
    

    Demo on DB Fiddle

    START_DATE |结束日期 :--------- | :--------- 2020/04/26 | 2020/05/02 2020/05/03 | 2020/05/10

    【讨论】:

      猜你喜欢
      • 2012-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-21
      • 2015-04-17
      • 1970-01-01
      相关资源
      最近更新 更多