SQL Server中的字符串替换使用另一个表的内容(例如update table1 set value = replace(table1.value,table2.val1,table2.val2))

时间:2009-12-24 06:13:11

标签: sql-server tsql

我有一个包含邮政地址的SQL Server表。在准备邮寄时,我需要做一些符合USPS偏好的字符串替换(例如,“Avenue”变成“Ave”)。

为了省去枚举所有替换的麻烦,我将标签/缩写对保存在两列表中。有没有一种优雅的方法可以将每个这些作为参数传递给更新语句中的Replace函数?

查找表如下所示:

CREATE TABLE addressLookup (label varchar(50),abbreviation varchar(20))
INSERT INTO addressLookup (label,abbreviation)
SELECT 'Avenue','Ave' UNION
SELECT 'Boulevard','Blvd' UNION
SELECT 'Drive','Dr' UNION
SELECT 'Lane','Ln' UNION
SELECT 'Street','St' UNION
SELECT 'First','1st' UNION
SELECT 'Second','2nd' UNION
SELECT 'Third','3rd' UNION
SELECT 'Fourth','4th' UNION
SELECT 'Fifth','5th' UNION
SELECT 'Sixth','6th' UNION
SELECT 'Seventh','7th' UNION
SELECT 'Eighth','8th' UNION
SELECT 'Ninth','9th' UNION
SELECT 'Tenth','10th' UNION
SELECT 'Eleventh','11th' UNION
SELECT 'Twelfth','12th' UNION
SELECT 'Apartment','Apt' UNION
SELECT 'Apartments','Apts' UNION
SELECT 'Floor','Fl' UNION
SELECT 'Room','Rm' UNION
SELECT 'Suite','Ste' UNION
SELECT 'Po Box','PO Box' UNION
SELECT 'P O Box','PO Box' UNION
SELECT 'P o Box','PO Box' UNION
SELECT 'Rural Route','RR' UNION
SELECT 'R Rte','RR' UNION
SELECT 'Rr','RR'

这将是一个操作数据的例子(我知道它很草率,但这只是一个例子):


CREATE TABLE addresses (userid int PRIMARY KEY, address1 varchar(50), address2 varchar(50), address3 varchar(50), city varchar(50), state varchar(50), zip varchar(50))
INSERT INTO addresses (userid,address1,address2,address3,city,state,zip)
SELECT 10,'Indiana University','123 University Lane','Campus Box 123','Bloomington','IN','47405'

更新的问题是来自addressLookup表的任意数量的记录可以匹配地址表的内容。我想我可以实现一个递归存储过程来完成这项工作,但我希望有人会有一个更好,更优雅的解决方案。

修改

为了澄清,地址表已经填充(有数百万条记录)。我只是试图预测任何可能抱怨需要真实数据来测试解决方案的人。

2 个答案:

答案 0 :(得分:7)

您可以使用 CURSOR 执行此操作。但是使用Sql Server 2005 CTE你可以试试这个。

以下是完整工作示例:

DECLARE @addressLookup TABLE (label varchar(50),abbreviation varchar(20))
INSERT INTO @addressLookup (label,abbreviation)
SELECT 'Avenue','Ave' UNION
SELECT 'Boulevard','Blvd' UNION
SELECT 'Drive','Dr' UNION
SELECT 'Lane','Ln' UNION
SELECT 'Street','St' UNION
SELECT 'First','1st' UNION
SELECT 'Second','2nd' UNION
SELECT 'Third','3rd' UNION
SELECT 'Fourth','4th' UNION
SELECT 'Fifth','5th' UNION
SELECT 'Sixth','6th' UNION
SELECT 'Seventh','7th' UNION
SELECT 'Eighth','8th' UNION
SELECT 'Ninth','9th' UNION
SELECT 'Tenth','10th' UNION
SELECT 'Eleventh','11th' UNION
SELECT 'Twelfth','12th' UNION
SELECT 'Apartment','Apt' UNION
SELECT 'Apartments','Apts' UNION
SELECT 'Floor','Fl' UNION
SELECT 'Room','Rm' UNION
SELECT 'Suite','Ste' UNION
SELECT 'Po Box','PO Box' UNION
SELECT 'P O Box','PO Box' UNION
SELECT 'P o Box','PO Box' UNION
SELECT 'Rural Route','RR' UNION
SELECT 'R Rte','RR' UNION
SELECT 'Rr','RR'


DECLARE @addresses TABLE (userid int PRIMARY KEY, address1 varchar(50), address2 varchar(50), address3 varchar(50), city varchar(50), state varchar(50), zip varchar(50))
INSERT INTO @addresses (userid,address1,address2,address3,city,state,zip)
SELECT 10,'Indiana University','123 University Lane Suite','Campus Box 123','Bloomington','IN','47405'

;WITH CTE AS(
        SELECT  *,
                ROW_NUMBER() OVER (ORDER BY label) RowID
        FROM    @addressLookup
),
CTERep AS(
        SELECT  CTE.*,
                userid,
                REPLACE(address1, CTE.label,CTE.abbreviation) address1,
                REPLACE(address2, CTE.label,CTE.abbreviation) address2,
                REPLACE(address3, CTE.label,CTE.abbreviation) address3,
                REPLACE(city, CTE.label,CTE.abbreviation) city,
                REPLACE(state, CTE.label,CTE.abbreviation) state,
                REPLACE(zip, CTE.label,CTE.abbreviation) zip,
                1 AS Depth
        FROM    CTE, @addresses a
        WHERE   RowID = 1
        UNION ALL
        SELECT  CTE.*,
                CTERep.userid,
                REPLACE(CTERep.address1, CTE.label,CTE.abbreviation) address1,
                REPLACE(CTERep.address2, CTE.label,CTE.abbreviation) address2,
                REPLACE(CTERep.address3, CTE.label,CTE.abbreviation) address3,
                REPLACE(CTERep.city, CTE.label,CTE.abbreviation) city,
                REPLACE(CTERep.state, CTE.label,CTE.abbreviation) state,
                REPLACE(CTERep.zip, CTE.label,CTE.abbreviation) zip,
                CTERep.Depth + 1
        FROM    CTE INNER JOIN
                CTERep ON CTE.RowID = CTERep.RowID + 1
)
SELECT  userid,
        address1,
        address2,
        address3,
        city,
        state,
        zip
FROM    CTERep
WHERE   Depth = (SELECT COUNT(*) FROM @addressLookup)

答案 1 :(得分:0)

我知道这篇文章已有近5年的历史,但如果它能帮到这里的人是最简单的解决方案而不使用游标......

--REPLACE LABEL WITH ABBREVIATION
SELECT  @Address1 = REPLACE(@SearchString,[Label],[Abbreviation]),
        @Address2 = REPLACE(@SearchString2,[Label],[Abbreviation]),
        @Address3 = REPLACE(@SearchString2,[Label],[Abbreviation])
FROM    [dbo].[addressLookup]


--DEMO OUTPUT
SELECT  @Address1,
        @Address2,
        @Address3