【问题标题】:T-SQL Parse text in select statementT-SQL 解析选择语句中的文本
【发布时间】:2012-09-20 04:57:35
【问题描述】:

我目前正在开展一个项目,将数据从一个表导入到另一个表。我正在尝试将包含 FULLNAME 的字段解析为其 LAST、FIRST、MI 部分。这些名称都采用“LAST,FIRST MI”的格式我已经编写了一个存储过程,它可以正确解析并根据需要返回结果,但我不确定如何将存储过程合并到单个 select 语句中。例如,当前我有:

SELECT FULLNAME From UserInfo

而我想要的是这样的:

SELECT Last, First, MI from UserInfo

目前我的存储过程采用 ParseName(FULLNAME, Last as OUTPUT, First as OUTPUT, MI as OUTPUT) 的形式。如何调用此过程并将输出变量分成 3 个不同的列?

【问题讨论】:

  • 您应该normalize 数据库并拥有FirstNameLastNNameMiddleInitial 字段而不是FULLNAME 一个。
  • 我实际上是在执行 Select INTO 以将具有 FULLNAME 的旧表中的数据导入到具有 FIRST、LAST 和 MI 列的表中。我只是想弄清楚如何将这些部分组合在一起。

标签: tsql sql-server-2005 select stored-procedures


【解决方案1】:

将您的存储过程替换为table valued function。然后,您可以将此函数应用于所有行。

以下是一个示例 - 只需输入您解析名称的逻辑

create FUNCTION dbo.f_parseName(@inFullName varchar(255))
RETURNS 
    @tbl TABLE (lastName varchar(255), firstName varchar(255), middleName varchar(255))
as
BEGIN
-- put your logic here
insert into @tbl(lastName,firstName,middleName)
select substring(@inFullName,0,10),substring(@inFullName,11,10), substring(@inFullName,21,10)

return

end

应用函数

-- sample data
declare @fullNames table (fullName varchar(255))
insert into @fullNames (fullName) values
('111111111122222222223333333333')
,('AAAAAAAAAABBBBBBBBBBCCCCCCCCCC')


select 
    fn.fullName
    ,pn.lastName
    ,pn.firstName
    ,pn.middleName
from 
    @fullNames fn
    cross apply dbo.f_parseName(fn.fullName) pn

【讨论】:

  • 您的答案似乎效果很好,但由于某种原因,在第 85 行之后,所有派生列都显示为 NULL?有什么想法吗?
  • 我发现了我的问题。我的存储过程正在进行 OLE 自动化调用,但我没有正确销毁 COM 对象
【解决方案2】:

您可以将存储过程的结果放在(临时)表中,如下所示(我添加了 FULLNAME 列以提供连接条件,您必须调整存储过程才能做到这一点):

CREATE TABLE #temp (
  FULLNAME NVARCHAR(..)
  ,Last NVARCHAR(..)
  ,First NVARCHAR(..)
  ,MI NVARCHAR(..)
);

INSERT INTO #temp (Last, First, MI)
EXECUTE MySproc;

如果您希望能够在结构上执行SELECT Last, First, MI from UserInfo,您必须首先在 UserInfo 中添加三列作为您的名称信息,然后插入您从存储过程中获得的解析数据。

编辑

您提到您使用SELECT ... INTO ... 将数据放入新表中。我猜新表没有FULLNAME 列,那么最好使用表值函数(如this answer 建议的那样)。但是,如果您保留 FULLNAME 列,则可以使用它将临时表与新表连接以更新新表,如下所示:

UPDATE NUI
  SET NUI.Last = T.Last, NUI.First = T.First, NUI.MI = T.MI
  FROM NewUserInfo AS NUI
  INNER JOIN #temp AS T ON NUI.FULLNAME = T.FULLNAME;

如果您的新表中没有 FULLNAME 列,您也可以将此 UPDATE 方法与另一个连接条件一起使用,但请确保事先运行良好的测试以检查连接是否成立。

希望这会有所帮助,祝你好运!

【讨论】:

  • 感谢您的建议。我试图通过我提出问题的方式来消除复杂性。我实际上正在执行 SELECT into 以将数据从旧表移动到新表(我的 OP 通过提到我正在执行导入来引用它)。新表已经有第一中间和最后一列。因此,如果我按照您的建议创建临时表,我是否必须将临时表加入 UserInfo 表才能获取完整的数据列表?
  • 嘿@TimN_FL,我添加了一个 UPDATE 示例,但这取决于 FULLNAME 列的可用性。使用表值函数可能会更好!
【解决方案3】:

您可以像这样将计算列添加到表中:

alter table UserInfo
    add firstName as SUBSTRING(fullName, CHARINDEX(',',fullName,0)+2, LEN(fullName)-CHARINDEX(',',fullName,0)-CHARINDEX(' ', REVERSE(fullName),0)-1)
        ,lastName as SUBSTRING(fullName, 0, CHARINDEX(',',fullName,0))
        ,middleInitital as REVERSE(SUBSTRING(REVERSE(fullName),0,CHARINDEX(' ', REVERSE(fullName),0)))

但最好的解决方案是反其道而行之。使用 firstNamelastNamemiddleInitial 的实际列对数据进行规范化,并为 fullName 执行计算列。

上面代码中的表达式可能需要多做一些工作,因为我确信它们可以更有效地编写。我只是让他们工作来展示这个想法。

创建计算列后,您可以这样做:

select  firstName
        ,lastName
        ,middleInitital
from UserInfo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    相关资源
    最近更新 更多