如何将多列中的数据分离并解析成单独的行(Oracle)

Posted

技术标签:

【中文标题】如何将多列中的数据分离并解析成单独的行(Oracle)【英文标题】:How do I separate and parse out data from multiple columns into separate rows (Oracle) 【发布时间】:2017-10-31 16:23:03 【问题描述】:

我在每列和每行中有多个值由逗号分隔的列。我试图将它们分成单独的行。如果其中一个值为空值(如下所示),只要该特定行的其他值之一仍然存在,我仍将包含空值。

我得到了什么

First_Name (John,  ,Phil)
Last_Name  (Smith,No, ) 
Location  (CA,GA,NY)

我想要什么

(John, Smith, CA)
( , No, GA)
(Phil, ,NY)

我已经尝试使用 regexp_substr 方法,但它没有返回任何在上面列出的 3 列中的任何一列中具有空值的行。

【问题讨论】:

显示您尝试过的查询。 选择 trim(regexp_substr(first_name,'[^,]+', 1, 1)) first_name, trim(regexp_substr(last_name,'[^,]+',1, 2)) 最后,name, trim(regexp_substr(location,'[^,]+', 1, 3)) location from table_name connect by regexp_substr(first_name,'[^,]+', 1, 1 is not null 那么,在First_Name 输入中,逗号之间是什么?它看起来像两个空格。理想情况下,如果名字“缺失”,逗号之间应该有 nothing,甚至没有 one 空格。 'John,,Phil'。同样,在Last_Name 中,第二个逗号应该在字符串的末尾(在末尾标记一个 NULL),它后面不应该有空格。字符串真的是这样的吗? 【参考方案1】:
with
  inputs ( id, first_name, last_name, location ) as (
    select 101, 'John,,Phil' , 'Smith,No,'   , 'CA,GA,NY' from dual union all
    select 102, 'Jo,Al,Ed,Li', 'Ng,Tso,,Roth', ',ZZ,,BB'  from dual 
  )
-- End of simulated inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your actual table and column names.
select id,
       regexp_substr(first_name, '([^,]*)(,|$)', 1, level, null, 1) as first_name,
       regexp_substr(last_name , '([^,]*)(,|$)', 1, level, null, 1) as last_name,
       regexp_substr(location  , '([^,]*)(,|$)', 1, level, null, 1) as location
from   inputs
connect by level <= regexp_count(first_name, ',') + 1
       and prior id = id
       and prior sys_guid() is not null
;

  ID FIRST_NAME  LAST_NAME    LOCATION
---- ----------- ------------ --------
 101 John        Smith        CA      
 101             No           GA      
 101 Phil                     NY      
 102 Jo          Ng                   
 102 Al          Tso          ZZ      
 102 Ed                               
 102 Li          Roth         BB 

【讨论】:

如果我们不插入数据而是从“暂存”表中逐列选择它们,解决方案会改变吗? @icerabbit - 我不明白这个问题。我提供的解决方案没有插入数据。你是说 WITH 子句吗?我非常清楚地标记它仅用于测试目的;您只需要select id, ... 中的代码,但您必须使用暂存表的名称和其中的列。或者你问如何存储这个查询的结果?如果是这样,请在此 SELECT 查询中使用 INSERT 语句。 抱歉,我误读了您的解决方案,并将您的解决方案与另一个解决方案混淆了。如果我想用回车代替逗号,我该怎么做?有专门的代码吗? @icerabbit - 回车的代码是chr(13)。但又一次,我不明白。数据是否在单列文本中,但文本本身(虽然从外部视图看是“单个值”)实际上延伸了几行,每行一个值?那里要非常小心;如果输入来自 Unix/Linux,那么只有换行符(不是回车符!) - 那是 chr(10),但如果它来自 Windows,它是回车符和换行符。但是,您使用什么来进行导入?所有这些都应该在导入数据时处理,而不是事后处理。 所以看起来给我的数据已经加载到表中了。发生的情况是,对于每个唯一标识符,我都有几个名字、姓氏和位置,它们都由一些我不确定的字符分隔。我可以在单个列中收到的 first_names 示例是:CarlosMonta【参考方案2】:

你可以试试这样的。

SET SERVEROUTPUT ON;
DECLARE 

TYPE etype IS TABLE OF VARCHAR2(100);
erec etype;
BEGIN

 for rec IN  ( SELECT first_name,last_name,location FROM Table1 )
 LOOP

 WITH fname
     AS (SELECT LEVEL   lvl,
                REGEXP_SUBSTR(rec.first_name, '[^,]+', 1, LEVEL)First_name
         FROM   DUAL
         CONNECT BY REGEXP_SUBSTR(rec.first_name, '[^,]+', 1, LEVEL) IS NOT NULL),
     lname
     AS (SELECT LEVEL lvl,
                REGEXP_SUBSTR(rec.last_name, '[^,]+', 1, LEVEL)Last_Name
         FROM   DUAL
         CONNECT BY REGEXP_SUBSTR(rec.last_name, '[^,]+', 1, LEVEL) IS NOT NULL),
     loc
     AS (SELECT LEVEL lvl,
                REGEXP_SUBSTR(rec.location, '[^,]+', 1, LEVEL)Location
         FROM   DUAL
         CONNECT BY REGEXP_SUBSTR(rec.location, '[^,]+', 1, LEVEL) IS NOT NULL)
SELECT first_name
       ||','
       || last_name
       ||','
       || location  BULK COLLECT INTO erec 
FROM   fname fn
       FULL OUTER join lname ln
                    ON fn.lvl = ln.lvl
       FULL OUTER join loc lo
                    ON ln.lvl = lo.lvl;  

FOR i IN 1..erec.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(erec(i));  
END LOOP;

END LOOP;     

END;
/

【讨论】:

当我将它用于更大的数据集时,我会返回多个不应该相互关联的名字、姓氏等(可能是由于完全外部连接? ) 例如我现在要返回 : (John, Smith, CA) (John, Smith, NY) (John, Smith, LA), etc. 不,它适用于您的原始问题。你修改了问题。 太棒了,那么我该如何处理更大的数据集呢? 欢迎。如果对您有用,请点赞并标记为最佳答案。谢谢! 假设我在我的设计中添加了一个唯一标识符(例如 ID),这会改变什么吗?这对性能有帮助吗?您不必回答,因为这会使原始问题进一步复杂化,但认为问起来不会有什么坏处。无论哪种方式,您都会得到我认为的“最佳答案”

以上是关于如何将多列中的数据分离并解析成单独的行(Oracle)的主要内容,如果未能解决你的问题,请参考以下文章

tidyr 在多列上使用单独的行

如何使用 Pandas 计算跨多列的行中的值?

WPF 中的多列列表框

Power Query中如何把多列数据合并?

VSCode Prettier 将 Condition 语句分隔成单独的行

多列并集为一列