使用分隔符解析值在Oracle 10g中使用REGEXP_SUPSTR

时间:2016-12-07 20:52:55

标签: oracle oracle10g regexp-substr

我有一个名为TVL_DETAIL的表,其中包含列TVL_CD_LIST。列TVL_CD_LIST包含三个记录:
TVL_CD_LIST:
M1180_Z6827
K5900_Z6828
I2510

我尝试使用以下代码尝试仅返回值(因此不包括下划线):

TABLE_DATE_RANGE_STRICT()

我期望在不同的行中看到的是:
M1180
Z6827
K5900
Z6828
I2510

但它只返回I2510(这是不包含下划线的原始值)。

我做错了什么?任何帮助表示赞赏。谢谢!

2 个答案:

答案 0 :(得分:0)

要回答您的问题,您正在查询与子元素匹配的列表,并且只会在列表由一个元素组成的情况下发生。你真正想要选择的是子元素本身。

注意:解释使用正则表达式'[^_]+'解析字符串的原因在这里很糟糕:https://stackoverflow.com/a/31464699/2543416

您要解析列表,选择元素:

SQL> with TVL_DETAIL(TVL_CD_LIST) as (
     select 'M1180_Z6827' from dual union
     select 'K5900_Z6828' from dual union
     select 'I2510' from dual
   )
   SELECT distinct regexp_substr(TVL_CD_LIST, '(.*?)(_|$)', 1, level, NULL, 1) element
   FROM TVL_DETAIL
   CONNECT BY level <= LENGTH(regexp_replace(TVL_CD_LIST, '[^_]', '')) + 1;
   -- 11g  CONNECT BY level <= regexp_count(TVL_CD_LIST, '_') + 1;

ELEMENT
-----------
Z6827
K5900
M1180
I2510
Z6828

SQL>

如果您想要按行和行中的元素进行跟踪,这很酷:

SQL> with TVL_DETAIL(row_nbr, TVL_CD_LIST) as (
     select 1, 'M1180_Z6827' from dual union
     select 2, 'K5900_Z6828' from dual union
     select 3, 'I2510' from dual
   )
   SELECT row_nbr, column_value substring_nbr,
          regexp_substr(TVL_CD_LIST, '(.*?)(_|$)', 1, column_value, NULL, 1) element
   FROM TVL_DETAIL,
     TABLE(
       CAST(
         MULTISET(SELECT LEVEL
                  FROM dual
                  CONNECT BY level <= LENGTH(regexp_replace(TVL_CD_LIST, '[^_]', '')) + 1
                  -- 11g CONNECT BY LEVEL <= REGEXP_COUNT(TVL_CD_LIST, '_')+1
                  ) AS sys.OdciNumberList
           )
     )
   order by row_nbr, substring_nbr;

   ROW_NBR SUBSTRING_NBR ELEMENT
---------- ------------- -----------
         1             1 M1180
         1             2 Z6827
         2             1 K5900
         2             2 Z6828
         3             1 I2510

SQL>

编辑:糟糕,编辑为使用10g作为REGEXP_COUNT,直到11g才可用。

答案 1 :(得分:0)

您使用的查询会创建列表,但您使用in子句将记录列表与其自身列进行比较,因此M1180Z6827不能等于{对于M1180_Z6827,{1}}等等。 K5900_Z6828只有一个值,因此匹配。

如果您的要求与您在所需输出中提到的完全一致,则可以使用以下查询。

I2510

输出:

SQL> WITH tvl_detail AS
      2   (SELECT 'M1180_Z6827' tvl_cd_list FROM dual
      3    UNION ALL
      4    SELECT 'K5900_Z6828' FROM dual
      5    UNION ALL
      6    SELECT 'I2510' FROM dual)
      7   ---------------------------
      8   --- End of data preparation
      9   ---------------------------
     10  SELECT regexp_substr(tvl_cd_list, '[^_]+', 1, LEVEL) AS tvl_cd_list
     11    FROM tvl_detail
     12  CONNECT BY regexp_substr(tvl_cd_list, '[^_]+', 1, LEVEL) IS NOT NULL
     13         AND PRIOR tvl_cd_list = tvl_cd_list
     14         AND PRIOR sys_guid() IS NOT NULL;