将一列中的记录分成多列

时间:2019-05-15 07:21:47

标签: sql-server

我不确定这在sql server中是否可以实现。我有一个表ADDRESS,其元数据如下。 SQ_ID是我的唯一关键字列

SQ_ID INT
ADDRESS_LINE_1 varchar(255)
ADDRESS_LINE_2 varchar(255)
ADDRESS_LINE_3 varchar(255)
ADDRESS_LINE_4 varchar(255)
REGION varchar(255)
POSTOCODE varchar(255)
COUNTRY_CODE varchar(255)

现在,我已经在该表中加载了大约200万条记录,问题是所有地址详细信息都已加载到该表的“地址行1”列中。现在,我正在尝试找到一种拆分方法。下面给出了一些地址示例集。

enter image description here

所以我想以以下方式拆分地址行1中的数据

  给定记录中addressLine1中的

值应填充为   给定地址行2中相同表值中的地址行1   记录应填充到表中相同表值中的addressline2   给定记录中的addressLine3应该填充到addressline3   给定记录中primaryTown中同一表中的值应为   在provinceOrState中的同一表值中填充到addressline4   给定记录中的数据应填充到同一表中的区域   给定记录中isoAlpha2Code中的值应填充为   给定zipOrPostalCode中相同表值中的COUNTRY_CODE   记录应填充到同一表中的POSTOCODE

下面给出了我的预期输出

enter image description here

我还要附加一组样本地址值进行测试

{'addressLine1': '67 xxxx Road', 'primaryTown': 'HOxxxCHxxCH',
 'zipOrPostalCode': 'RM11 1EX', 'addressCountry': {'isoAlpha2Code':
 'GB'}}

{'primaryTown': 'MünXXer', 'addressCountry': {'isoAlpha2Code': 'DE'}}

{'addressLine1': '28 THE EXCAC', 'primaryTown': 'PERTH',
'provinceOrState': 'WA', 'addressCountry': {'isoAlpha2Code': 'AU'}}

{'addressLine1': '28 THE ESPLANADE', 'primaryTown': 'PERTH',
'provinceOrState': 'WA', 'addressCountry': {'isoAlpha2Code': 'AU'}}

{'addressLine1': '76 XXX STREET', 'primaryTown': 'MAXDFOT',
'provinceOrState': 'NSW', 'addressCountry': {'isoAlpha2Code': 'AU'}}

{'addressLine1': 'UNIT 56', 'addressLine2': '22 XDFR STREET',
'primaryTown': 'MANLY VALE', 'provinceOrState': 'NSW',
'addressCountry': {'isoAlpha2Code': 'AU'}}

{'addressLine1': 'BjoXCDSaret 15', 'addressLine2': 'Jppsdeheim',
'addressLine3': '', 'primaryTown': 'AKERdwfUS', 'addressCountry':
{'isoAlpha2Code': 'NO'}}

1 个答案:

答案 0 :(得分:2)

您无法通过拆分来解析JSON。尽管SQL Server 2016和更高版本支持JSON,所以您可以使用JSON_VALUE之类的函数来提取所需的数据。

除非您要索引和过滤这些值,否则您不必执行此操作。如果您打算使用国家/地区或邮政编码对结果进行过滤或分组,则可以提取国家或邮政编码。另一方面,无法查询地址行,并且地址行也可能保留在JSON字符串中。您始终可以在必要时使用JSON_VALUE提取它们。

primaryTown中的Puttin AddressLine4看起来像是一个错误。该 是可用于查询的重要属性。它应该去自己的领域,或者根本不提取。

SQL Server 2016及更高版本

在任何情况下,您都可以使用JSON_VALUE解析JSON值,例如:

declare @myTable table(json varchar(max))

insert into @myTable
values
('{"addressLine1": "BjoXCDSaret 15", "addressLine2": "Jppsdeheim","addressLine3": "", "primaryTown": "AKERdwfUS", "addressCountry":
{"isoAlpha2Code": "NO"}}'),
('{"addressLine1": "67 xxxx Road", "primaryTown": "HOxxxCHxxCH",
 "zipOrPostalCode": "RM11 1EX", "addressCountry": {"isoAlpha2Code":
 "GB"}}'),
('{"primaryTown": "MünXXer", "addressCountry": {"isoAlpha2Code": "DE"}}'),
('{"addressLine1": "28 THE EXCAC", "primaryTown": "PERTH",
"provinceOrState": "WA", "addressCountry": {"isoAlpha2Code": "AU"}}'),
('{"addressLine1": "28 THE ESPLANADE", "primaryTown": "PERTH",
"provinceOrState": "WA", "addressCountry": {"isoAlpha2Code": "AU"}}'),
('{"addressLine1": "76 XXX STREET", "primaryTown": "MAXDFOT",
"provinceOrState": "NSW", "addressCountry": {"isoAlpha2Code": "AU"}}'),
('{"addressLine1": "UNIT 56", "addressLine2": "22 XDFR STREET",
"primaryTown": "MANLY VALE", "provinceOrState": "NSW",
"addressCountry": {"isoAlpha2Code": "AU"}}')

select 
    JSON_VALUE(json,'$.zipOrPostalCode') as ZipCode,
    JSON_VALUE(json,'$.primaryTown') as primaryTown,
    JSON_VALUE(json,'$.addressCountry.isoAlpha2Code') as CountryCode
from @mytable

您可以使用相同的表达式在表上创建持久化的计算列并为其建立索引,从而加快需要按国家或邮政编码过滤的查询。

旧版本

在旧版本中,也许最简单的解决方案是创建一个使用JSON.NET解析数据并返回值的SQLCLR函数。

另一个选择是使用字符串替换将JSON字符串转换为XML,然后使用XPATH检索值。尽管替换操作取决于预期的数据,并且对空白敏感,并且在处理嵌套对象时很容易中断,但这可能会非常棘手。

例如,这个平面JSON对象:

declare @json varchar(max)='{"addressLine1": "BjoXCDSaret 15", "addressLine2": "Jppsdeheim", "addressLine3": "", "primaryTown": "AKERdwfUS"}'

可以通过一些替换将其转换为XML。请注意,我修复了空格差异,以确保标记之间始终存在空格。否则,我必须同时替换","", "

select 
    cast(
        replace(
            replace(
                replace(
                    replace(@json,'{"','<it '),
                '": "',' ="'),
            '", "','" '),
        '}',' />')
    as xml)

结果是:

<it addressLine1="BjoXCDSaret 15" addressLine2="Jppsdeheim" addressLine3="" primaryTown="AKERdwfUS" />

现在可以使用.value来查询:

select 
    cast(replace(replace(replace(replace(@json,'{"','<it '),'": "',' ="'),'", "','" '),'}',' />') as xml)       
     .value('(/it/@primaryTown)[1]','varchar(20)')

这将返回:

AKERdwfUS

这与嵌套的addressCountry对象不同。如果您知道 JSON文本包含的内容,则可以欺骗并替换特定的属性,而不仅仅是分隔符,例如:

declare @json varchar(max)='{"addressLine1": "UNIT 56", "addressLine2": "22 XDFR STREET", "primaryTown": "MANLY VALE", "provinceOrState": "NSW", "addressCountry": {"isoAlpha2Code": "AU"}}'
select      
cast(
    replace(
        replace(
            replace(
                replace(
                    replace(
                        replace(@json,'", "addressCountry": {"','"><addressCountry '),
                        '}}','/></it>'),
                    '{"','<it '),
                '": "',' ="'),
            '", "','" ')
        ,'}',' />') 
    as xml).value('(/it/addressCountry/@isoAlpha2Code)[1]','varchar(20)')

这将返回AU

虽然只能通过反复试验才能奏效,但这是一种严重的作弊行为。在这种情况下,addressCountry属性和以下分隔符将转换为元素。 }}应该只出现在字符串的末尾,因此将得到特殊处理。

使用客户端脚本

使用小型.NET程序使用JSON.NET读取数据并提取所需的值可能会更容易。 200万行不是很多,因此偶尔解析数据不会有什么大问题