2013-04-01 17 views
0

我们有一个技术支持代理弄乱了我们的“FullName”列中的第一个中间名和最后一个名字之间的空白。SQL通过分离大写修正名称列

所以不是

John Alan Smith 

的名字读

JohnAlanSmith 

我们没有在各列的名字,我们也没有名字的另一个来源。这是为第三方应用程序。

我们有超过1500个用户在数据库中,所以我们需要轻松地解决问题。我能想到的唯一方法是通过检测首都。当然,我们需要以某种方式排除像麦当劳这样的姓氏中间的大写字母。

我们可以发出SQL语句来做到这一点吗?即使我们只需要手动更正100个名称,它也会比1500+更好。

+1

哪个RDBMS您使用的? – sgeddes

+0

用JimBobMacDonald这样的名字测试每个答案。您可能需要查找名称只有两个大写字母的查询,然后手动执行其他操作。 –

+0

@sgeddes - 我正在使用Microsoft SQL Server 2005 Express Edition – Brady

回答

1

我忍不住想这样做。下面的代码是针对SQL Server的,它实际上可以工作(您可以在sqlfiddle上查看)。

这是一个多步骤的过程。这个想法是通过加入一堆数字并检查字符的值来确定它是否大写,以确定名称中每个大写字母的位置。每个大写字母都在自己的行上。

然后,为其提取名称部分,并将字符串连接在一起。假设第一个字母大写(如果不是这种情况,很容易修复),此方法可行。另外,请记住一些首都不是“边缘”:“麦加维”,“陈史密斯”等。

以上每个步骤都会因数据库而异。

with somenums as (
     select 1 as n union all select 2 union all select 3 union all select 4 union all select 5 
    ), 
    nums as (
     select ROW_NUMBER() over (order by (select NULL)) as n 
     from somenums s cross join somenums s2 
    ), 
    test as (
     select 'JohnAlanSmith' as name union all 
     select 'MaryElizabethChou' 
    ), 
    caps as (
     select name, n 
     from test join 
      nums 
      on ascii(SUBSTRING(test.name, nums.n, 1)) between ascii('A') and ascii('Z') 
    ), 
    nameparts as (
    select name, n, nextn, SUBSTRING(name, n, coalesce(nextn - n, 1000)) as namepart 
    from (select name, n, 
        (select min(n) from caps c2 where c2.name = c.name and c2.n > c.n 
       ) as nextn 
      from caps c 
     ) c 
    ) 
select name, 
     STUFF((select ' '+namepart 
       from nameparts np2 
       where np2.name = np.name 
       order by n 
       for xml path ('') 
      ), 1, 1, '' 
      ) as betterName 
from nameparts np 
group by name 
+0

这看起来不错,但我无法在sqlfiddle中使用它。你能提供一个示例表吗?谢谢! – Brady

+0

@Brady - 为我工作:http://sqlfiddle.com/#!3/d41d8/11841 – sgeddes

+0

@Brady。 。 。样本表是称为'test'的CTE。 –

0

对于MySQL:

当你不想浪费太多时间写一个复杂的功能,你可能有这样的一个尝试:

/*test data*/ 
create table foo(name varchar(50)); 
insert into foo values ('JohnAndySmith'); 

select 
name, 
trim(replace(replace(name, 'A', ' A'), 'S', ' S')) 
from 
foo 

观摩here

当然,你必须为整个字母表做。 TRIM()函数删除第一个字母前的空格。

有关我使用的功能的更多信息,请参阅manual

+0

这将如何与MacDonald这样的名字一起工作? –

+1

@DanBracuk。 。 。与所有其他解决方案相同。它会将它分成两个名字。 –

0

根据你的关系型数据库,这样的东西可以工作。这是专门为SQL塞雷尔语,并使用该接受一个字段,并在字符串中的位置,并返回字符串,直到下一个大写字母的功能:

select field, fname, mname, dbo.ReturnCapString(field,len(fname)+len(mname)+1) lname 
from 
    (
    select field, fname, dbo.ReturnCapString(field,len(fname)+1) mname 
    from 
     (
     select field, dbo.ReturnCapString(field,1) fname 
     from yourtable 
     ) t 
    ) t2 

和作用 - 对功能更主要的是看到ASCII检查如果字符是资本或不:

CREATE FUNCTION ReturnCapString (@String VARCHAR(100), @Pos int) 
RETURNS varchar(100) 
AS 
BEGIN 
    DECLARE @return varchar(100) 
    DECLARE @position INT 
    DECLARE @counter INT 

    SET @position = @Pos + 1 
    SET @counter = 1 
    SET @return = '' 

    WHILE @position <= DATALENGTH(@string) AND @return = '' 
    BEGIN 
     IF ASCII(SUBSTRING(@string, @position, 1)) BETWEEN 65 AND 90 
      SELECT @return = SUBSTRING(@string, @pos, @counter) 

     SET @position = @position + 1 
     SET @counter = @counter + 1 

    END 

    IF @return = '' 
    BEGIN 
    SET @return = SUBSTRING(@String, @Pos, LEN(@string)) 
    END 

    RETURN @return 
END 

当然并且,SQL Fiddle证明。

顺便说一句 - 感谢您的有趣问题!虽然这是不完美的(不要认为什么将是100%完美的),如果你需要的潜在标志任何明显的问题,使用此琴:http://sqlfiddle.com/#!3/77f446/10

FLAG FIELD   FNAME MNAME LNAME 
     JohnAlanSmith John  Alan  Smith 
     McDonalds  Mc    Donalds 
X  JimBobMacDonald Jim  Bob  Mac