将数据解析为单独的单独列

时间:2018-12-04 02:10:19

标签: sql-server tsql sql-server-2008

我有一个名为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

提前谢谢!

2 个答案:

答案 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;

enter image description here

这个想法很简单-用逗号替换所有空字符串。然后拆分新创建的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;