如何以递归方式解析SQL语句中的数据

时间:2011-01-07 19:10:50

标签: sql sql-server sql-server-2005 tsql recursion

我正在尝试清理数据库中“名称”字段中的数据,并将该数据拆分为FirstName,MiddleName和&姓。目前,我正在使用Case语句在文本中查找各种触发器,以帮助我以某种方式格式化输出。

但是,我开始注意到我在其他测试中嵌套测试,需要弄清楚如何递归处理数据。请参阅此示例,了解我如何提取FirstName。

Case 
  When CharIndex(' ',LTrim(RTrim(Name))) in (0,1) Then '' --'empty or LName'
  When Left(Name,3) IN ('MR ','MS ', 'DR ','MRS') Then    --'Prefix Titles'
    Case --'If we found a prefix, run the same "tests" with the prefix removed'
      When CharIndex(' ',LTrim(RTrim(Right(Name,Len(Name)-CharIndex(' ',Name)))))
        in (0,1) Then '' 
      When SubString(LTrim(RTrim(Right(Name,Len(Name)-CharIndex(' ',Name)))),3,1) 
        = '&' Then SubString(LTrim(RTrim(Right(Name,Len(Name)-CharIndex(' ',
        Name)))),1,5)
      Else Left(LTrim(RTrim(Right(Name,Len(Name)-CharIndex(' ',Name)))),
        CHarIndex(' ',LTrim(RTrim(Right(Name,Len(Name)-CharIndex(' ',Name)))))-1) 
    End
  When SubString(LTrim(RTrim(Name)),3,1) = '&' Then 
    SubString(LTrim(RTrim(Name)),1,5) --'Look for initials e.g. J & A Smith'
  Else Left(LTrim(RTrim(Name)),CHarIndex(' ',LTrim(RTrim(Name)))-1) 
  End

因此,为了让它在更复杂的情况下工作(例如MR JOHN A SMITH JR),我需要递归测试。在命令式编程中,如果我有一个名为GetFirstName的函数:

,我会做这样的事情
GetFirstName('MR JOHN A SMITH JR')
//GetFirstName identfies 'MR' and within the function it calls:
||
\\
   ==> GetFirstName('JOHN A SMITH JR')
       //GetFirstName identifies 'JR' and within the function it calls:
       ||
       \\
          ==> GetFirstName('JOHN A SMITH')
              //Finally, it returns 'JOHN'

理想情况下,在直接SQL中执行此操作会很棒,但我不确定是否可行。如果我不使用直接SQL,我会有哪些替代方案? (我正在使用SQL Server 2005)

2 个答案:

答案 0 :(得分:1)

我不认为直接SQL可以轻松/干净地完成任务。您可以使用正则表达式,但是您必须编写自己的CLR函数来提供正则表达式功能。

答案 1 :(得分:0)

这听起来像是一次性活动。您确定在使用临时表的几个语句中不能这样做吗?如果它是一次性活动,那么对代码调试的准确性和简单性的要求可能高于性能。

考虑这样的事情:

CREATE TABLE #MyNames (
  PersonID INT PRIMARY KEY,
  OriginalName VARCHAR(50),
  WorkingName VARCHAR(50),
  CandidateTitle VARCHAR(10),
  CandidateLastName VARCHAR(50),
  CandidateFirstName VARCHAR(50),
  CandidateMiddleName VARCHAR(50)
  --Your other candidate fields.....
)

INSERT INTO #MyNames (PersonID, OriginalName)
 SELECT TOP 100 ID, LTRIM(RTRIM(Name)) from SourcePersonTable

--Possibly add some indexes here for original name

UPDATE #MyNames
 SET CandidateTitle = LEFT(OriginalName,3),
     WorkingName = SUBSTRING(OriginalName,4,9999)
Where LEFT(OriginalName,3) IN
    ('MR ','MRS','MS ','DR ')

-- etc...

继续添加步骤并编辑[WorkingName]字段。当你完成一次传球时,就这样做......

UPDATE #MyNames SET WorkingName = OriginalName

......你已经准备好再做一次扫描。