如果有人键入最后/第一/中间,如何将名称拆分为第一/中间/最后?已知订单
Posted
技术标签:
【中文标题】如果有人键入最后/第一/中间,如何将名称拆分为第一/中间/最后?已知订单【英文标题】:How to split names into first/middle/last if there are people who typed last/first/middle? Order known 【发布时间】:2019-06-15 21:00:46 【问题描述】:我正在尝试根据指定的顺序将名称拆分为名字、中间名和姓氏。我不知道如何做到这一点,任何帮助将不胜感激。我正在使用 sql server 2008 工作。
我附上了一个示例数据集和我想创建的理想数据集。
ID ORDER NAME
1 first, middle, last Bruce, Batman, Wayne
2 middle, last, first Superman, Kent, Clark
3 last, first, middle Prince, Diana, Wonderwoman
进入:
ID ORDER NAME
1 first Bruce
1 middle Batman
1 last Wayne
2 middle Superman
2 last Kent
2 first Clark
3 last Prince
3 first Diana
3 middle Wonderwoman
【问题讨论】:
你有哪个版本? 为什么不努力规范化您的数据,而不是进行另一种形式的非规范化? @larnu 一厢情愿地想,也许这个问题是因为正在进行标准化;) 考虑到你可以一次性标准化数据,我坐在“不太可能”的一边@CaiusJard :( 【参考方案1】:SQL Server 没有很好的字符串处理功能。不过,您可以使用递归 CTE 来做到这一点:
with cte as (
select id,
convert(varchar(max), left(ord, charindex(',', ord) - 1)) as ord,
convert(varchar(max), left(name, charindex(',', name) - 1)) as name,
convert(varchar(max), stuff(ord, 1, charindex(',', ord) + 1, '')) as ord_rest,
convert(varchar(max), stuff(name, 1, charindex(',', name) + 1, '')) as name_rest,
1 as lev
from t
union all
select id,
convert(varchar(max), left(ord_rest, charindex(',', ord_rest + ',') - 1)) as ord,
convert(varchar(max), left(name_rest, charindex(',', name_rest + ',') - 1)) as name,
convert(varchar(max), stuff(ord_rest, 1, charindex(',', ord_rest + ',') + 1, '')) as ord_rest,
convert(varchar(max), stuff(name_rest, 1, charindex(',', name_rest + ',') + 1, '')) as name_rest,
lev + 1
from cte
where ord_rest <> '' and lev < 10
)
select id, ord, name
from cte
order by id, lev
Here 是一个 dbfiddle。
【讨论】:
【参考方案2】:在返回序列的解析/拆分函数的帮助下,使用 CROSS APPLY 就变成了一件小事
示例
Select A.ID
,B.*
From YourTable A
Cross Apply (
Select [Order] = B1.RetVal
,[Name] = B2.RetVal
From [dbo].[tvf-Str-Parse]([ORDER],',') B1
Join [dbo].[tvf-Str-Parse]([NAME] ,',') B2 on B1.RetSeq=B2.RetSeq
) B
退货
ID Order Name
1 first Bruce
1 middle Batman
1 last Wayne
2 middle Superman
2 last Kent
2 first Clark
3 last Prince
3 first Diana
3 middle Wonderwoman
感兴趣的功能
CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From ( values (cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.'))) as A(x)
Cross Apply x.nodes('x') AS B(i)
);
【讨论】:
谢谢!它解决了我的大部分问题,并帮助我弄清楚下一步需要做什么。 @TinaChan 很高兴为您提供帮助。【参考方案3】:我发现其他答案有点难以理解 - 它们肯定是巧妙的技巧,但我认为任何来维护它们的人可能会像“whaaaat?”。在这里,我计算出第一个 cte 中逗号的索引(第一个逗号字符串索引进入 o1/n1,第二个逗号进入 o2/n2),将字符串切开(1 和第一个逗号之间的子字符串,第一个之间的子字符串和第二个逗号,第三个逗号后的子字符串)在第二个 cte 中,然后使用几个联合将结果从 7 列转换为 3
WITH idxs AS
(
SELECT
id,
order,
name,
CHARINDEX(',', [order]) as o1,
CHARINDEX(',', [order], CHARINDEX(',', [order]) + 1) as o2,
CHARINDEX(',', name) as n1,
CHARINDEX(',', name, CHARINDEX(',', name) + 1) as n2
FROM
t
),
cuts as (
SELECT
id,
SUBSTRING([order], 1, o1-1) as ord1,
SUBSTRING([order], o1+1, o2-o1-1) as ord2,
SUBSTRING([order], o2+1, 4000) as ord3,
SUBSTRING(name, 1, n1-1) as nam1,
SUBSTRING(name, n1+1, n2-n1-1) as nam2,
SUBSTRING(name, n2+1, 4000) as nam3
FROM
idxs
)
SELECT id, ord1 as [order], nam1 as name FROM cuts
UNION ALL
SELECT id, ord2, nam2 FROM cuts
UNION ALL
SELECT id, ord3, nam3 FROM cuts
请注意,如果您的数据有时有空格,有时没有,您将受益于在输出中使用 LTRIM/RTRIM
如果逗号后始终存在空格,您还可以调整子字符串索引以删除空格(任何起始索引为 x+1 将是 x+2,因此长度必须为 -2)
【讨论】:
以上是关于如果有人键入最后/第一/中间,如何将名称拆分为第一/中间/最后?已知订单的主要内容,如果未能解决你的问题,请参考以下文章