Sql server 格式化地址字符串

Sql server 格式化地址字符串,sql-server,tsql,Sql Server,Tsql,使用T-SQL,我需要知道将包含地址的字符串拆分为单独字段的最佳方法,以便重新格式化它们。它必须能够处理不同的输入格式 AddressIn: AddressOut: StreetNumber: StreetName: '25 Main Street' | '25' 'Main Street' '25 MainStreet' | '25' 'MainStreet' '

使用T-SQL,我需要知道将包含地址的字符串拆分为单独字段的最佳方法,以便重新格式化它们。它必须能够处理不同的输入格式

AddressIn:           AddressOut:
                     StreetNumber:     StreetName:
'25 Main Street'   | '25'              'Main Street'
'25 MainStreet'    | '25'              'MainStreet'
'Main Street 25'   | '25'              'Main Street'
'MainStreet 25'    | '25'              'MainStreet'
'25B Main Street'  | '25B'             'Main Street'
'25B MainStreet'   | '25B'             'MainStreet'
'Main Street 25B'  | '25B'             'Main Street'
'MainStreet 25B'   | '25B'             'MainStreet'

任何帮助都将不胜感激。

这将满足您的要求,但我同意上面的评论,使用SQL进行此类解析并不理想

select
CASE 
    WHEN patindex('%[0-9]%',theAddress)=1 
    THEN substring(theaddress,1,charindex(' ',theaddress) ) 
    ELSE rtrim(substring(theAddress,patindex('%[0-9]%',theAddress),99) )
END as StreetNumber,
CASE 
    WHEN patindex('%[0-9]%',theAddress)=1 
    THEN substring(theaddress,charindex(' ',theAddress)+1,99) 
    ELSE substring(theAddress,1,patindex('%[0-9]%',theAddress)-1)
END as StreetName
FROM <yourtable>
选择
案例
当patindex('%[0-9]]'时,地址=1
然后是子字符串(地址,1,charindex(“”,地址))
ELSE rtrim(子字符串(地址,patindex('%[0-9]]',地址),99))
以街号结束,
案例
当patindex('%[0-9]]'时,地址=1
然后是子字符串(地址,charindex('',地址)+1,99)
ELSE子字符串(地址,1,patindex('%[0-9]',地址)-1)
以StreetName结尾
从…起
注意事项,您可以从评论中看到

  • 性能将不是很好,尤其是如果您的桌子是 大的
  • 除示例之外的其他地址格式可能会中断 代码
遵循以下步骤:

步骤1:(拆分字符串并仅提取包含街道编号的部分)

输出:
'25B'主街'

步骤2:(步骤1是主要思想,也是最重要的,下面的函数只是为了使选择更容易-函数可能不同,可以用不同的方式编写)

然后

最后是这个查询:
select*from dbo.splitAddress_2()

结果:

注意:数字部分是否位于地址字符串的开头、中间或结尾并不重要,例如对于
“Main 25B Street”
此解决方案将运行良好


对@Sparky的答案进行了鲁棒性修改

DECLARE @Addresses TABLE (Address  NVARCHAR(200))
INSERT INTO @Addresses VALUES
    ('25 Main Street'),
    ('25 MainStreet'),
    ('Main Street 25'),
    ('MainStreet 25'),
    ('25B Main Street'),
    ('25B MainStreet'),
    ('Main Street 25B'),
    ('MainStreet 25B')
select
CASE 
    WHEN patindex('%[0-9]%',Address)=1 
    THEN substring(Address,1,charindex(' ',Address) ) 
    ELSE rtrim(substring(Address,patindex('%[0-9]%',Address),99) )
END as StreetNumber,
CASE 
    WHEN patindex('%[0-9]%',Address)=1 
    THEN REPLACE(Address,substring(Address,1,charindex(' ',Address) ),'')
    ELSE REPLACE(Address,rtrim(substring(Address,patindex('%[0-9]%',Address),99) ),'')
END as StreetName
FROM @Addresses
据推测,这段代码应该能够更好地处理更多类型的地址

此版本是一个额外的例外:

DECLARE @Addresses TABLE (Address  NVARCHAR(200))
INSERT INTO @Addresses VALUES
    ('25 Main Street'),
    ('25 MainStreet'),
    ('Main Street 25'),
    ('MainStreet 25'),
    ('25B Main Street'),
    ('25B MainStreet'),
    ('Main Street 25B'),
    ('MainStreet 25B'),
    ('Main 25B Street')
select
CASE
    WHEN CHARINDEX(' ',Address,patindex('%[0-9]%',Address))-patindex('%[0-9]%',Address) > 0
    THEN substring(Address, patindex('%[0-9]%',Address), CHARINDEX(' ',Address,patindex('%[0-9]%',Address))-patindex('%[0-9]%',Address))
    WHEN patindex('%[0-9]%',Address)=1 
    THEN substring(Address,1,charindex(' ',Address) ) 
    ELSE rtrim(substring(Address,patindex('%[0-9]%',Address),99) )
END as StreetNumber,
CASE
    WHEN CHARINDEX(' ',Address,patindex('%[0-9]%',Address))-patindex('%[0-9]%',Address) > 0
    THEN REPLACE(Address,substring(Address, patindex('%[0-9]%',Address), CHARINDEX(' ',Address,patindex('%[0-9]%',Address))-patindex('%[0-9]%',Address)),'')
    WHEN patindex('%[0-9]%',Address)=1 
    THEN REPLACE(Address,substring(Address,1,charindex(' ',Address) ),'')
    ELSE REPLACE(Address,rtrim(substring(Address,patindex('%[0-9]%',Address),99) ),'')
END as StreetName
FROM @Addresses

完全避免使用SQL,看看是否可以从应用程序代码中执行此操作!我认为您会发现,定义可靠地标识任意地址字符串的特定组件所需的规则非常困难。如果不能用通俗易懂的英语定义规则,那么就很难用SQL编写代码:)恐怕不行。我从一个附在供应商应用程序上的数据库中提取数据&它只存储为字符串。我以前有过这种情况,数据来自呼叫中心,来自自由文本表单。我建议您选择地址,并将一致的数据存储在本地数据库中。由于有数百万行采用邮政编码格式,您将无法逃脱为每行执行的拆分字符串函数调用。旁注:我看不出有任何理由尝试这样的操作。地址有很多种味道,所以尝试以任何方式格式化它们几乎是无用的。请参阅使用此方法的第一部分(获取街道编号),这一部分更加清晰,只需用空字符串替换当前记录中已精简的街道编号,即可以更可靠的方式获得街道名称。对获取街道编号的方法进行更广泛的测试并加以完善,将无需使用第二种方法获取街道名称。我同意,但是您需要提取街道编号,将其存储在某个位置,并在随后的街道名称部分使用替换。这是可行的,但会使查询更加复杂。以上是一个与他已知的地址格式相匹配的简单解决方案。不完美,但使用非常简单抱歉,只需检查它的
Main 25B Street
输出不正确
Main 25B Street不在ops示例地址格式中。。。ops声明,原始请求中的变化是唯一预期的输入格式,这是另一种方法。谢谢。很抱歉,只是检查一下主25B街的输出是否正确。首先,我从未声称我修改的代码处理了所有异常,说“错”,我说它更健壮。请阅读代码之外的英语句子。第二,这种格式是极端的,我不相信普通人会写它,但它肯定是“可修复的”,只需要一点额外的代码。是的,我非常同意,起初,我还试图用这种格式编写函数,但在发布之前对其进行了更改,因为它需要更多的检查和检查。我编写了一个版本来处理这个额外的异常,以便查看它的外观:)如果可能,请始终尝试避免while循环和游标,对于这种解决方案,您的方法甚至效率更低。@SubqueryCrunch我确信在这种情况下,一个小循环比在
case
中使用大量的
内置函数
和多个
语句
时更好,无论如何,谢谢您的评论,祝您好运。
CREATE TABLE address_table (AddressIn  NVARCHAR(200))
INSERT INTO address_table VALUES
    ('25 Main Street'),
    ('25 MainStreet'),
    ('Main Street 25'),
    ('MainStreet 25'),
    ('25B Main Street'),
    ('25B MainStreet'),
    ('Main Street 25B'),
    ('MainStreet 25B'),
    ('Main 25B Street')
CREATE FUNCTION [dbo].[splitAddress_2]()
RETURNS @output TABLE(street_number NVARCHAR(50),street_name NVARCHAR(100))
BEGIN 
 DECLARE @adr varchar(200)
 DECLARE cr CURSOR
    FOR SELECT AddressIn FROM address_table
OPEN cr
FETCH NEXT FROM cr into @adr;
while(@@fetch_status=0)
begin
insert into @output(street_number,street_name)
select * from dbo.splitAddress_1(@adr)
FETCH NEXT FROM cr into @adr;
end
close cr
deallocate cr
 RETURN 
END
DECLARE @Addresses TABLE (Address  NVARCHAR(200))
INSERT INTO @Addresses VALUES
    ('25 Main Street'),
    ('25 MainStreet'),
    ('Main Street 25'),
    ('MainStreet 25'),
    ('25B Main Street'),
    ('25B MainStreet'),
    ('Main Street 25B'),
    ('MainStreet 25B')
select
CASE 
    WHEN patindex('%[0-9]%',Address)=1 
    THEN substring(Address,1,charindex(' ',Address) ) 
    ELSE rtrim(substring(Address,patindex('%[0-9]%',Address),99) )
END as StreetNumber,
CASE 
    WHEN patindex('%[0-9]%',Address)=1 
    THEN REPLACE(Address,substring(Address,1,charindex(' ',Address) ),'')
    ELSE REPLACE(Address,rtrim(substring(Address,patindex('%[0-9]%',Address),99) ),'')
END as StreetName
FROM @Addresses
DECLARE @Addresses TABLE (Address  NVARCHAR(200))
INSERT INTO @Addresses VALUES
    ('25 Main Street'),
    ('25 MainStreet'),
    ('Main Street 25'),
    ('MainStreet 25'),
    ('25B Main Street'),
    ('25B MainStreet'),
    ('Main Street 25B'),
    ('MainStreet 25B'),
    ('Main 25B Street')
select
CASE
    WHEN CHARINDEX(' ',Address,patindex('%[0-9]%',Address))-patindex('%[0-9]%',Address) > 0
    THEN substring(Address, patindex('%[0-9]%',Address), CHARINDEX(' ',Address,patindex('%[0-9]%',Address))-patindex('%[0-9]%',Address))
    WHEN patindex('%[0-9]%',Address)=1 
    THEN substring(Address,1,charindex(' ',Address) ) 
    ELSE rtrim(substring(Address,patindex('%[0-9]%',Address),99) )
END as StreetNumber,
CASE
    WHEN CHARINDEX(' ',Address,patindex('%[0-9]%',Address))-patindex('%[0-9]%',Address) > 0
    THEN REPLACE(Address,substring(Address, patindex('%[0-9]%',Address), CHARINDEX(' ',Address,patindex('%[0-9]%',Address))-patindex('%[0-9]%',Address)),'')
    WHEN patindex('%[0-9]%',Address)=1 
    THEN REPLACE(Address,substring(Address,1,charindex(' ',Address) ),'')
    ELSE REPLACE(Address,rtrim(substring(Address,patindex('%[0-9]%',Address),99) ),'')
END as StreetName
FROM @Addresses