SQL 服务器:使用一个现有列的拆分内容更新两列

SQL Server : update two columns with the split content of one existing column

我有一个 SQL 服务器 table 具有这些列:

ID, Name, FirstName, LastName

所有名称现在都存储在 Name 列中,我想 运行 更新以填充 FirstNameLastName 列。

当前 table 的样本如下所示:

1 | John Doe | NULL | NULL

更新后我希望这样:

1 | John Doe | John | Doe

为简单起见,可以做出以下假设:

我已经尝试了以下(首先作为 SELECT,这样我可以在 运行 更新之前看到输出):

SELECT
    (SELECT TOP 2 value FROM STRING_SPLIT([NAME], ' ')) AS FirstName,   
    (SELECT TOP 1 value FROM STRING_SPLIT([NAME], ' ')) AS LastName 
FROM
    UserTable 
WHERE 
    LastName IS NULL
    AND [NAME] IS NOT NULL

但是这不起作用,因为第一列将 return 前两个顶部条目。但我想获得第二个条目,而不是前两个。第二列(前 1 列)就可以了。

我看到 STRING_SPLIT 提供了第三个参数 -> 序数。这将允许我向子查询添加 WHERE 子句。然而,这仅在 Azure 中可用,但我目前正在 运行ning SQL Server 2016 (v13)(没有 Azure)。

在 SQL Server 2016 中实现我的 UPDATE 的最佳方法是什么?

鉴于您指定的具体限制条件:

您可以使用 SUBSTRINGCHARINDEX

的组合
  • 注意使用 CROSS APPLY (VALUES 以允许重用 CHARINDEX 计算
  • 注意使用NULLIF以防止在没有space
  • 的情况下出错
SELECT
  SUBSTRING(t.NAME, 1, v.space - 1) AS FirstName,
  SUBSTRING(t.NAME, v.space + 1, LEN(t.NAME)) AS LastName
FROM UserTable t
CROSS APPLY (VALUES(
    NULLIF(CHARINDEX(' ', t.NAME), 0)
)) v(space)
WHERE t.LastName IS NULL
  AND t.[NAME] IS NOT NULL;

请注意,这绝不是拆分名称的通用解决方案。

名字可以多种多样,可能在名字之前有姓氏,可能没有姓氏,可能有多个名字或姓氏等。不要做假设。

这是另一种通过内置 PARSENAME() 函数使用标记化的方法。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, Name VARCHAR(100), FirstName VARCHAR(50), LastName VARCHAR(50));
INSERT INTO @tbl (Name, FirstName, LastName)
VALUES
('John Doe', NULL, NULL),
('Anna Mac', NULL, NULL);
-- DDL and sample data population, end

SELECT ID
    , FirstName = PARSENAME(tokens, 2)
    , LastName = PARSENAME(tokens, 1)
FROM @tbl
    CROSS APPLY (SELECT REPLACE(Name, SPACE(1),'.')) AS t(tokens);

输出

+----+-----------+----------+
| ID | FirstName | LastName |
+----+-----------+----------+
|  1 | John      | Doe      |
|  2 | Anna      | Mac      |
+----+-----------+----------+