我有一个名为Physical-address
的列,我需要将其解析为自己的列,以便将其导入到单独的地址字段中。列中的数据是这样的:
以下是一些示例:
1)6453 W教堂博士,加利福尼亚州萨米特维尔,邮政编码46741,布朗
2)北卡罗来纳州格林斯伯勒市北大街2456号,邮政编码27403
3)5847 East Wood Dr,VA
4)530阿罕布拉博士公寓。 A1安德森(IN 46012)
5)1511 W 9th St,Anderson,IN,46016
6)2900 W 22nd St,Anderson,IN,46013,Madison
7)社区医院,印第安纳州安德森市麦迪逊大街1515号,邮政编码46011
结果:
1)46741
2)27403
3)NULL
4)46012
5)46016
6)46013
7)46011
提前谢谢!
答案 0 :(得分:4)
您可以尝试使用此方法(示例数据,请加倍!)
DECLARE @DataSource TABLE
(
ID INT IDENTITY,
[value] NVARCHAR(MAX)
);
INSERT INTO @DataSource ([value])
VALUES ('6453 W Church Dr, Summitville, CA, 46741, Brown')
,('2456 North Street, Greensboro, NC 27403')
,('5847 East Wood Dr, VA')
,('530 Alhambra Dr. Apt. A1 Anderson IN 46012')
,('1511 W 9th St, Anderson, IN, 46016')
,('2900 W 22nd St, Anderson, IN, 46013, Madison')
,('Community Hospital, 1515 N Madison Ave, Anderson, IN, 46011');
-查询将在字符串中找到所有整数,并在所需的时间间隔中返回这些整数
SELECT ID,[value]
,fragment.value('text()[1]','int')
FROM @DataSource ds
CROSS APPLY(SELECT CAST('<x>' + REPLACE(REPLACE((SELECT [value] AS [*] FOR XML PATH('')),',',' '),' ','</x><x>') + '</x>' AS XML)) A(Casted)
CROSS APPLY A.Casted.nodes('/x[not(empty(. cast as xs:int?))]') B(fragment)
WHERE fragment.value('text()[1]','int') BETWEEN 10000 AND 99999;
第一个CROSS APPLY
将所有逗号替换为空格,然后将字符串拆分为所有空格(通过将a b c
转换为<x>a</x><x>b</x><x>c</x>
)。
魔术发生在第二个CROSS APPLY
中:
.nodes('/x[not(empty(. cast as xs:int?))]')
将返回片段,其中对xs:int?
的强制转换不会返回空。换句话说:所有数值都是数字。
由于我们只返回数字,因此我们可以在int
方法中节省使用.value()
,因此可以简单地使用BETWEEN
检查间隔。
向HABO致谢,您可以对此进行一些更改:
SELECT ID,[value]
,fragment.value('text()[1]','nvarchar(max)')
FROM @DataSource ds
CROSS APPLY(SELECT CAST('<x>' + REPLACE(REPLACE((SELECT [value] AS [*] FOR XML PATH('')),',',' '),' ','</x><x>') + '</x>' AS XML)) A(Casted)
CROSS APPLY A.Casted.nodes('/x[not(empty(. cast as xs:int?))]') B(fragment)
WHERE LEN(fragment.value('text()[1]','nvarchar(max)'))=5;
想法仍然相同:找到纯数字。但是结果以字符串形式处理(不省略前导零),并且过滤器正在检查长度为5的内容。
答案 1 :(得分:1)
假定您至少使用SQL Server 2012,以下是完整的工作示例。如果您使用的是早期版本,请用其他方法将IIF
替换为CASE WHEN
,并将TRY_CONVERT
替换为其他技术,以检查字符串是否为数字(您可以使用pathindex来检查是否存在任何非数字例如数字字符。)
DECLARE @DataSource TABLE
(
[value] NVARCHAR(MAX)
);
INSERT INTO @DataSource ([value])
VALUES ('6453 W Church Dr, Summitville, CA, 46741, Brown')
,('2456 North Street, Greensboro, NC 27403')
,('5847 East Wood Dr, VA')
,('530 Alhambra Dr. Apt. A1 Anderson IN 46012')
,('1511 W 9th St, Anderson, IN, 46016')
,('2900 W 22nd St, Anderson, IN, 46013, Madison')
,('Community Hospital, 1515 N Madison Ave, Anderson, IN, 46011');
WITH DataSource ([value], [valueXML]) AS
(
SELECT [value]
,CAST(('<X>'+REPLACE(REPLACE([value], ' ', ','),',' ,'</X><X>')+'</X>') AS XML)
FROM @DataSource
),
DataSourceFinal ([value], [number], [rank], [numbers_count]) AS
(
SELECT [value]
,T.c.value('.', 'nvarchar(128)')
,ROW_NUMBER() OVER (PARTITION BY DS.[value] ORDER BY T.c DESC)
,COUNT(T.c.value('.', 'nvarchar(128)')) OVER (PARTITION BY [value])
FROM DataSource DS
CROSS APPLY DS.[valueXML].nodes('X') T(c)
WHERE TRY_CONVERT(BIGINT, T.c.value('.', 'nvarchar(128)')) IS NOT NULL
AND T.c.value('.', 'nvarchar(128)') <> ''
)
SELECT [value]
,IIF([numbers_count] > 1, [number], NULL)
FROM DataSourceFinal
WHERE [rank] = 1;
这个想法很简单-用逗号替换所有空字符串。然后拆分新创建的CSV,并寻找最后一个数字。
如果您的T-SQL中有regex support,这可以很容易地解决。例如:
WITH DataSource ([value], [number], [rank], [numbers_count]) AS
(
SELECT DS.[value]
,REVERSE(RM.[CaptureValue])
,RM.[MatchID]
,COUNT(RM.[MatchID]) OVER (PARTITION BY DS.[value])
FROM @DataSource DS
CROSS APPLY [dbo].[fn_Utils_RegexMatches] (REVERSE([value]), '\d+') RM
)
SELECT [value]
,IIF([numbers_count] > 1, [number], NULL)
FROM DataSource
WHERE [rank] = 0;