SQL:交叉应用于将名称拆分为名字,姓氏和MI

时间:2019-04-05 16:41:32

标签: sql sql-server tsql

我有一个表,它的用户名是这样的。

Name
-----
Smith-Bay, Michael R.
Abbott, David Jr.
Actor, Cody
Agular, Stephen V.

我需要这个名字看起来像:

Last         First    MI
-------------------------
Smith-Bay    Michael  R
Abbott       David    Jr
Actor        Cody
Agular       Stephen  V 

我有以下SQL将名称拆分为第一个和最后一个:

select vl.lastname, vf.firstname
from users as t cross apply
(values (left(t.name, charindex(', ', t.name)), stuff(t.name, 1, 
charindex(', ', t.name) + 1, ''))) vl(lastname, rest) 
cross apply 
(values (left(vl.rest, charindex(' ', vl.rest + ' ')))) vf(firstname)
order by  vl.lastname

我如何应用另一个十字架申请来提取名字后的数字减去末尾的句点?

1 个答案:

答案 0 :(得分:1)

在定期处理ETL时,我不得不在很多情况下执行此操作,或者由于数据存储不良而需要从字符串中提取项目,或者只是必须从报表中提取数据。数据并不总是很好地打包在单独的列中,我发现自己出于各种原因而解析数据。希望您正在解析的数据是一致的。不一致的数据会使这变得更加困难或不可能。如果您可以依靠自己的名字来正确地使用格式,那么您建议我的下面的方法可以完美地工作。我已经在很多场合使用过。

下面的方法我已经使用了许多不同的语言。我已经在MS ACCESS,Microsoft SSMS和C#中完成了此操作。我的示例来自Oracle。

基本思想是:

  

Find the character positions,用于分隔您的名字,姓氏和中间名初始字符串。

     

Extract Strings into New Columns使用获得的字符位置。

enter image description here

代码如下:

WITH character_pos AS
(
/* First we need the character positions for spaces, commas and the period for the middle initial */
SELECT name
  /* Find 1st Space in the name so we can extract the first name from the string */
  , instr(name, ', ') AS comma_1st_space_pos
  /* Find 2nd Space in the name so we can extract the last name from the string */
  , instr(name, ' ', 1, 2) AS comma_2nd_space_pos
  /* Get the Length of the last name so we know how many characters the substr function should extract */
  , instr(name, ' ', 1, 2) - (instr(name, ', ') + 2) AS last_name_length
  /* Find period in the name so we can extract the Middle Initial should it exist */
  , instr(name, '.')  AS period_pos
  , (instr(name, '.') - 1) - instr(name, ' ', 1, 2) AS middle_initial_length

FROM parse_name
) /* END character_pos CTE */

SELECT name  
  , substr(name, 0, comma_1st_space_pos -1) AS last_name

  , CASE WHEN  period_pos = 0 THEN substr(name, comma_1st_space_pos + 2)
    ELSE substr(name, comma_1st_space_pos + 2, last_name_length) 
    END AS first_name

  , substr(name, comma_2nd_space_pos + 1, middle_initial_length) AS middle_initial

  , comma_1st_space_pos, comma_2nd_space_pos, last_name_length
  , period_pos, middle_initial_length
FROM character_pos
;

我使用CTE只是在实际提取之外组织字符位置,但是所有这些都可以在一个SQL语句中完成。

基本上,这证明您只需要一些简单的字符串解析函数就不需要任何其他东西。您需要的只是Instring和Substring,它们通常可用任何语言提供。不需要存储过程,不需要临时表,也不需要额外的外部代码。除非原始问题的范围之外还有其他因素,否则有必要使用除SQL以外的其他任何东西。