【问题标题】:Separate "Mr John Joe Smith" into "Mr" "John" "Joe" "Smith"将“约翰·乔·史密斯先生”分成“先生”“约翰”“乔”“史密斯”
【发布时间】:2021-02-10 16:58:13
【问题描述】:

客户提供的文件具有以下结构:

FullName
Mr John Joe Smith

他们希望将其转换为以下内容:

Salutation FirstName MiddleName LastName
Mr John Joe Smith

我对此进行了调查,并尝试了以下方法:

SELECT        substring(FullName,0,charindex(' ',Fullname)) As Salutation, substring(FullName,charindex(' ',Fullname)+1,len(fullname)) As FirstName
FROM            dbo.Individuals

这会产生:

Salutation FirstName
Mr John Joe Smith

我正在努力将它进一步分开,这是最好的方法还是有更好的方法?

任何帮助将不胜感激,谢谢。

【问题讨论】:

  • 简短的回答是“你不知道”。如果您在输入时没有将其分开,那么您不知道什么是真正的名字、中间名或姓氏。
  • 你不知道你试图打开的蠕虫罐头。
  • 你会为Mr John & Mrs Joanne Jones Smith Esq.做什么?
  • 您从未见过 John Esq。 @查理脸?虽然他们喜欢用他们的第一个中间名“&”,但他的一些朋友称他为“夫人”以惹恼他。

标签: sql sql-server tsql


【解决方案1】:

只要始终有相同的四个元素以相同的顺序...

select  parsename(replace('Mr John Joe Smith',' ','.'),4) [Salutation],
        parsename(replace('Mr John Joe Smith',' ','.'),3) [FirstName],
        parsename(replace('Mr John Joe Smith',' ','.'),2) [MiddleName],
        parsename(replace('Mr John Joe Smith',' ','.'),1) [LastName]

【讨论】:

  • 这适用于任何已经包含句点的字符串,例如'Dr. Ludwig Philipp Albert Schweitzer'。请注意,ParseName 在出现意外输入时往往会静默失败,例如select ParseName( 'Dr..Ludwig.Philipp.Albert.Schweitzer', 1 );.
  • 确实如此。
  • 当然,这确实适用于任何潜在的解决方案。如果您从不干净的数据开始,则永远无法保证结果,除非您构建了一系列数据清理。
  • 根据前三个空格将字符串分成四列并让LastName 列中的所有多余土地与通过拆分不同字符引入新问题之间存在差异可能已经存在也可能不存在,并为所有列返回null。 Falsehoods Programmers Believe About Names 解释了多种失败的附加选项。
  • 谢谢@WAMLeslie,这很好用。我可以在结果中看到它产生了预期的效果。我还可以看到当一个人的名字超过 3 个时,它会为该行返回 null。这可能是与客户讨论设计而不是逻辑问题。再次感谢您的帮助。
【解决方案2】:

这是 parsename 的替代方法:

SELECT *
FROM (
  SELECT FullName,Name
   ,CASE RN WHEN 1 THEN 'Salutation' WHEN 2 THEN 'FirstName' WHEN 3 THEN 'MiddleName' WHEN 4 THEN 'LastName' END AS ColName
  FROM (SELECT FullName,value AS Name,ROW_NUMBER() OVER(PARTITION BY FullName ORDER BY (SELECT NULL)) AS RN
    FROM dbo.Individuals
    CROSS APPLY STRING_SPLIT(FullName,' ') ) base ) mid
PIVOT (MAX(Name) FOR ColName IN ([Salutation],[FirstName],[MiddleName],[LastName]) ) p

您可以扩展 CASE 语句以使其对格式不敏感。例如:

CASE
 WHEN FullName LIKE '% % % %' THEN
  CASE RN WHEN 1 THEN 'Salutation' WHEN 2 THEN 'FirstName' WHEN 3 THEN 'MiddleName' WHEN 4 THEN 'LastName' END
 WHEN FullName LIKE '% % %' THEN
  CASE RN WHEN 1 THEN 'FirstName' WHEN 2 THEN 'MiddleName' WHEN 3 THEN 'LastName' END
 WHEN FullName LIKE '% %' THEN
  CASE RN WHEN 1 THEN 'FirstName' WHEN 2 THEN 'LastName' END
END AS ColName

但是,如果您混合使用“Mr John Smith”和“John Joe Smith”、包含超过 5 个组件的行等,这仍然会适得其反,并且需要额外的逻辑。

根据文档,STRING_SPLIT 也没有保证返回顺序,尽管我个人从未见过它与原始字符串的顺序不同。如果您需要保证订购,或者如果您使用的是 pre-compatibility-130 并且没有 STRING_SPLIT,您可以使用 define your own 函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    • 2013-08-14
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多