【问题标题】:Split name into multiple parts in SELECT statement在 SELECT 语句中将名称拆分为多个部分
【发布时间】:2019-01-28 01:24:27
【问题描述】:

我似乎找不到关于将字符串拆分为我需要的部分的现有帖子。我在 SQL Server 中有一个数据库字段,其中包含“LastName FirstName MI”(没有逗号,只是分隔人名每个部分的空格)。我有以下 SQL 来获取名字和姓氏,但不知道如何获取中间名或中间名。

例如。能源部约翰B

SELECT
    RTRIM(LEFT([PATIENT_NAME], CHARINDEX(' ', [PATIENT_NAME]))) AS LastName,
    SUBSTRING([PATIENT_NAME], CHARINDEX(' ', [PATIENT_NAME]) + 1, LEN([PATIENT_NAME])) AS FirstName
FROM
    Clients

结果:

  • 名字 = 约翰 B
  • 姓氏 = Doe

如何在此SELECT 语句中仅返回不带中间名首字母的名字并从该字符串中获取“B”作为中间名?

【问题讨论】:

  • 这篇文章在处理名字时总是让我咯咯笑:Falsehoods Programmers Believe About Names
  • 你的 sql server 版本是多少?
  • 捎带@Larnu 的评论:您有什么保证某人的名字将采用您提供的格式?如果某人的姓名在这种格式中不是,您期望会发生什么?有两个姓氏(在西班牙国家很常见)或没有姓氏的人呢?我预见到你未来的问题......

标签: sql sql-server tsql


【解决方案1】:

您可以取右 1 个字符,也可以反转字符串取第一个字符。

SELECT RIGHT(LTRIM(RTRIM([Patient_Name])), 1) AS Middle_Initial

SELECT LEFT(REVERSE(LTRIM(RTRIM([Patient_Name]))), 1) AS Middle_Initial

至于从你的名字字符串中删除 MI,我会找到字符串的长度并取左边的 N-2 个字符,或者我会对空格进行 charindex,然后取那么多字符。综上所述:

DECLARE @name VARCHAR(100) = 'Smith David M      ' 

--Clean the string of leading/trailing whitespace
SELECT LTRIM(RTRIM(@name)) AS name_cleaned

--Find the first space to parse out the last name
SELECT CHARINDEX(' ', @name) AS first_space

--Select all chars before the first space
SELECT LEFT(LTRIM(RTRIM(@name)), CHARINDEX(' ', @name)-1) AS last_name

--Find the next space, use the starting location as the previous space and add 1
SELECT CHARINDEX(' ', @name, 7) AS second_space

--Select all chars between the spaces
SELECT SUBSTRING(@name, CHARINDEX(' ', @name)+1, CHARINDEX(' ', @name, 7) - CHARINDEX(' ', @name)) AS first_name

--Select the right most char for middle initial
SELECT RIGHT(LTRIM(RTRIM(@name)), 1) AS middle

【讨论】:

  • 谢谢,但是 RIGHT([Patient_Name]) 出于某种原因没有带回任何东西。我本来期望 B(也许有空格),我得检查一下。还有如何从 FirstName 中删除 MI?
  • @DataCrypt 如果您要返回空白,请对 Patient_Name 进行一些修剪。我将添加一些关于如何从名字中删除 MI 的内容。
  • 再次感谢。 SELECT RIGHT(LTRIM(RTRIM(@name)), 1) AS 中间有效,但它采用名字的第一个字符并在没有 MI 时将其用作中间首字母。
  • @DataCrypt 伙计,我们无法为您编写防白痴的解决方案。名字很难,然后会变得非常复杂。你有一个起点,所以从这里开始做一些腿部工作。
【解决方案2】:

您可以用句点字符 (.) 替换空格字符并使用 PARSENAME()。

请注意,这适用于名称的所有 3 个部分,而不仅仅是中间的首字母。

【讨论】:

  • 如何在 SELECT 语句中执行此操作?我需要最终在 UPDATE 语句中使用该查询。谢谢。
  • 将 REPLACE 函数嵌套在 SELECT 的 PARSENAME 函数中。
  • @DataCrypt 如果这是真实数据并且您要更新PATIENT_NAME 的值,我会非常小心。虽然我对这个问题的评论以及文章的链接有点开玩笑,但它实际上是非常真实的。在“现实世界”中,不可能对数据集中的每个名称做出“安全”假设。
【解决方案3】:

在姓氏上使用 CHARINDEX 时,您将使用它作为子字符串的长度。然后,在 FirstName 上,再次将其用作子字符串的起始位置。现在,中间的技巧,在 CHARINDEX 上,您必须包括起始位置,即 LEN 减去 LastName CHARINDEX。这将为您提供第二个空格,这是您要开始使用中间名的位置。

请看下面的例子:

DECLARE @tb TABLE (PATIENT_NAME varchar(250));
INSERT INTO @tb VALUES 
('Doe John B')

DECLARE 
    @LastName       INT
,   @Middle         INT 

SELECT 
    @LastName       =  CHARINDEX(' ', PATIENT_NAME)
,   @Middle         =  CHARINDEX(' ', PATIENT_NAME,  LEN(PATIENT_NAME) - CHARINDEX(' ', PATIENT_NAME))
FROM @tb


SELECT 
    SUBSTRING(PATIENT_NAME, 1, @LastName) LastName
,   SUBSTRING(PATIENT_NAME, @LastName, LEN(PATIENT_NAME) - @LastName) FirstName 
,   SUBSTRING(PATIENT_NAME, @Middle, LEN(PATIENT_NAME) - @Middle + 1 ) Middle  
FROM @tb   

我已经声明了一些变量来提高可读性,但是没有它们你也可以做到。

当然,LEFTRIGHT 是获取姓氏和中间名的更简单方法。除了使用一些辅助函数,如REVERSETRIM,但我更喜欢PARSENAME 作为一种更简单、更简洁的方法。
这是一个例子:

SELECT 
    PARSENAME(REPLACE(PATIENT_NAME,' ','.'),3) LastName
,   PARSENAME(REPLACE(PATIENT_NAME,' ','.'),2) FirstName
,   PARSENAME(REPLACE(PATIENT_NAME,' ','.'),1) Middle

【讨论】:

  • 此 PARSENAME 语句将所有字段恢复为 NULL。
  • @DataCrypt 这意味着您有空格或双空格,要检查,请在该字段上使用 LEN() 并检查您的空格字符数,然后将它们与 LEN 进行比较,请参阅差异。这将使您了解哪种方法可以处理您的数据
【解决方案4】:

由于您必须从字符串中提取的元素数量是固定的(3),您可以使用基于 XML 的拆分:

DECLARE @clients TABLE (PATIENT_NAME nvarchar(max));
INSERT INTO @clients VALUES 
 ('  Doe    John  B     ')
,('    Doe    Jane  C  ')
,(' Doe    Jill     ')

;WITH Splitted
AS (
    SELECT PATIENT_NAME as ORIGINAL_PATIENT_NAME
         ,REPLACE(REPLACE(REPLACE(ltrim(rtrim(PATIENT_NAME)),' ','<>'),'><',''),'<>',' ') as PATIENT_NAME
        ,CAST('<x>' + REPLACE(REPLACE(REPLACE(REPLACE(ltrim(rtrim(PATIENT_NAME)),' ','<>'),'><',''),'<>',' '), ' ', '</x><x>') + '</x>' AS XML) AS Parts
    FROM @clients
    )
SELECT
     ORIGINAL_PATIENT_NAME 
    ,PATIENT_NAME
    ,Parts.value(N'/x[1]', 'nvarchar(max)') AS LAST_NAME
    ,Parts.value(N'/x[2]', 'nvarchar(max)') AS FIRST_NAME
    ,Parts.value(N'/x[3]', 'nvarchar(max)') AS MIDDLE_NAME
FROM Splitted

结果:

正如您所见,它甚至可以使用随机间隔的名称。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-31
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    相关资源
    最近更新 更多