【问题标题】:How to split the given string as per requirement using oracle如何使用oracle根据要求拆分给定的字符串
【发布时间】:2015-11-11 10:01:56
【问题描述】:

我需要拆分名称以插入数据库。下面给出了一些示例字符串。

Covey, Stephen J, Mr
Clinton, Hilary B,
Obama, Barack, Mr

我需要像下面这样拆分上面的字符串。

First_Name       Middle_Initial      Last_NAME     Title
 Stephen               J               Covey         Mr
 Hilary                B               Clinton
 Barack                                Obama         Mr

我可以使用 java 代码实现上述目标。是否可以直接在 sql select 中拆分这些字符串?

请注意,少数名字可能没有头衔或中间名首字母。我需要上面给出的输出。

【问题讨论】:

  • 你为什么不根据你的java代码创建一个函数?
  • 是的。它已经完成了。尝试了解是否可以使用 sql,以便我可以在 sql 中进行更改并测量性能
  • @SqlNerd 8 小时前您发布了同样的问题,例如:stackoverflow.com/questions/32063884/…
  • @Tarun 这是一个不同的问题,是的,它适用于相同的工作。但是,我也需要替代品。
  • @SqlNerd 这里会定期询问解析一个人的名字。这是一个例子,stackoverflow.com/questions/371490/…

标签: sql string oracle substring


【解决方案1】:

SQL Fiddle

Oracle 11g R2 架构设置

CREATE TABLE Names ( Name ) AS
          SELECT 'Covey, Stephen J, Mr' FROM DUAL
UNION ALL SELECT 'Clinton, Hilary B,' FROM DUAL
UNION ALL SELECT 'Obama, Barack, Mr' FROM DUAL

查询 1

SELECT REGEXP_SUBSTR( Name, '^(.*?),\s*(.*?)(\s+(\w))?,\s*(.*)$', 1, 1, NULL, 1 ) AS Last_Name,
       REGEXP_SUBSTR( Name, '^(.*?),\s*(.*?)(\s+(\w))?,\s*(.*)$', 1, 1, NULL, 2 ) AS First_Name,
       REGEXP_SUBSTR( Name, '^(.*?),\s*(.*?)(\s+(\w))?,\s*(.*)$', 1, 1, NULL, 4 ) AS Middle_Initial,
       REGEXP_SUBSTR( Name, '^(.*?),\s*(.*?)(\s+(\w))?,\s*(.*)$', 1, 1, NULL, 5 ) AS Title
FROM   Names

Results

| LAST_NAME | FIRST_NAME | MIDDLE_INITIAL |  TITLE |
|-----------|------------|----------------|--------|
|     Covey |    Stephen |              J |     Mr |
|   Clinton |     Hilary |              B | (null) |
|     Obama |     Barack |         (null) |     Mr |

查询 2

SELECT REGEXP_REPLACE( Name, '^(.*?),\s*(.*?)(\s+(\w))?,\s*(.*)$', '\1' ) AS Last_Name,
       REGEXP_REPLACE( Name, '^(.*?),\s*(.*?)(\s+(\w))?,\s*(.*)$', '\2' ) AS First_Name,
       REGEXP_REPLACE( Name, '^(.*?),\s*(.*?)(\s+(\w))?,\s*(.*)$', '\4' ) AS Middle_Initial,
       REGEXP_REPLACE( Name, '^(.*?),\s*(.*?)(\s+(\w))?,\s*(.*)$', '\5' ) AS Title
FROM   Names

Results

| LAST_NAME | FIRST_NAME | MIDDLE_INITIAL |  TITLE |
|-----------|------------|----------------|--------|
|     Covey |    Stephen |              J |     Mr |
|   Clinton |     Hilary |              B | (null) |
|     Obama |     Barack |         (null) |     Mr |

查询 3

WITH Split_Names AS (
  SELECT REGEXP_SUBSTR( Name, '^[^,]+' ) AS Last_Name,
         REGEXP_REPLACE( Name, '^.*?,\s*|\s*,.*?$' ) AS Given_Names,
         REGEXP_SUBSTR( Name, '[^\s,]+$' ) AS Title
  FROM   Names
)
SELECT Last_Name,
       REGEXP_REPLACE( Given_Names, '\s+\w$' ) AS First_Name,
       TRIM( REGEXP_SUBSTR( Given_Names, '\s+\w$' ) ) AS Middle_Initial,
       Title
FROM   Split_Names

Results

| LAST_NAME | FIRST_NAME | MIDDLE_INITIAL |  TITLE |
|-----------|------------|----------------|--------|
|     Covey |    Stephen |              J |     Mr |
|   Clinton |     Hilary |              B | (null) |
|     Obama |     Barack |         (null) |     Mr |

【讨论】:

  • REGEXP_SUBSTR 在 Oracle 11.1 (documentation here) 中扩展为采用第 6 个参数,该参数返回匹配的子表达式(捕获组)。这仅适用于 Oracle 11 或更高版本 - 但该问题未标记为特定版本。
  • 添加了两个应该在 Oracle 10 中工作的版本。
  • @SqlNerd:确保使用数据中的数据样本进行测试,并包括意外的内容,如空元素、带空格的名称、单引号、连字符等。
  • @Gary_W 所有这些事情都由我上面的所有解决方案处理SQLFIDDLE
  • 当名称更改为 Covey, Mr., Stephen J 时这将失败,对吗?
【解决方案2】:

这是 Alexander 的答案,使用改进的正则表达式修改,可处理 NULL 列表元素。哦,不要重复那个正则表达式,而是通过创建一个如下所述的函数来使其可重用:REGEX to select nth value from a list, allowing for nulls,然后调用它。这样一来,代码就可以被所有人封装和重用,如果您必须更改代码,只需在一个地方即可:

SQL> with tbl(input_row) as (
   select 'Covey, Stephen J, Mr' from dual
   union
   select 'Clinton,,Ms' from dual
   union
   select 'Obama, Barack, Mr' from dual
   )
   SELECT TRIM( REGEXP_SUBSTR(input_row, '([^,]*)(,|$)', 1, 1, NULL, 1)) AS Last_NAME,
   TRIM( REGEXP_SUBSTR( REGEXP_SUBSTR(input_row, '([^,]*)(,|$)', 1, 2, NULL, 1), '[^ ]+', 1, 1)) AS First_Name,
   TRIM( REGEXP_SUBSTR( REGEXP_SUBSTR(input_row, '([^,]*)(,|$)', 1, 2, NULL, 1), '[^ ]+', 1, 2)) AS Middle_Initial,
   TRIM( REGEXP_SUBSTR(input_row, '([^,]*)(,|$)', 1, 3, NULL, 1)) AS Title
   FROM tbl;

LAST_NAME            FIRST_NAME           MIDDLE_INITIAL       TITLE
-------------------- -------------------- -------------------- --------------------
Clinton                                                        Ms
Covey                Stephen              J                    Mr
Obama                Barack                                    Mr

SQL>

【讨论】:

  • MT0 是最好的答案。它处理 last_names、first_names 和 NULL 列表元素中的嵌入空格,并减少了 2 次对 regexp_substr 的调用。
【解决方案3】:

使用regexp_substr (DB >=10g):

SELECT TRIM( REGEXP_SUBSTR(input_row, '[^,]+', 1, 1)) AS Last_NAME,
TRIM( REGEXP_SUBSTR( REGEXP_SUBSTR(input_row, '[^,]+', 1, 2), '[^ ]+', 1, 1)) AS First_Name,
TRIM( REGEXP_SUBSTR( REGEXP_SUBSTR(input_row, '[^,]+', 1, 2), '[^ ]+', 1, 2)) AS Middle_Initial,
TRIM( REGEXP_SUBSTR(input_row, '[^,]+', 1, 3)) AS Title
FROM source_table;

【讨论】:

  • 警告!当列表中有 NULL 元素时,通常用于解析分隔字符串的格式 '[^,]+' 的正则表达式会失败。确保彻底测试。总是期待意外!有关更多详细信息和改进的正则表达式,请参见此处:stackoverflow.com/questions/31464275/…
  • 完美。!!谢谢。 :)
  • @Gary_W 你是想说,如果 input_row 为空,即如果输入字符串为空,正则表达式将失败?
  • 否,如果该列表中的某个元素为空,并且您在该值之后或在它之后(请参阅我提供的链接以获取更多信息)。即尝试将此作为输入数据:'Clinton,,Ms'。名字最终将是“女士”。它将返回比失败更糟糕的错误数据!
  • 这也将无法正确解析由两部分组成的名字,例如 Miss Mary Kate Anne De Laney,其中姓氏是 De Laney(带有嵌入的空格),Mary Kate 是名字(也是嵌入空格),Anne 是中间名。这可能会形成为 De Laney, Mary Kate A, Miss
猜你喜欢
  • 1970-01-01
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 2019-02-19
  • 1970-01-01
  • 2020-07-18
相关资源
最近更新 更多