我正在使用两个表 - 一个用于地址,另一个用于MasterAddressCodes。
我需要使用MasterAddressCodes表中的地址的位置代码更新Address表。
这已经使用游标编写脚本,但效率非常低,需要2个多小时才能完成(大约225000条记录),我知道必须有一个更优雅,更高效的解决方案。
以下是表格详情:
地址:
CREATE TABLE [dbo].[Address](
[addressID] [int] IDENTITY(1,1) NOT NULL,
[number] [varchar](12) NULL,
[street] [varchar](30) NULL,
[tag] [varchar](20) NULL,
[prefix] [varchar](10) NULL,
[apt] [varchar](17) NULL,
[city] [varchar](24) NULL,
[state] [varchar](2) NULL,
[zip] [varchar](10) NULL,
[location_code] [varchar](40) NULL,
[postOfficeBox] [bit] NOT NULL,
)
MasterAddressCode:
CREATE TABLE [dbo].[MasterAddressCode](
[Street Name] [varchar](50) NULL,
[From] [varchar](50) NULL,
[To] [varchar](50) NULL,
[Code] [varchar](50) NULL,
[LocationCode] [varchar](50) NULL,
[Tag] [varchar](10) NULL,
[Prefix] [varchar](10) NULL
)
这是我到目前为止所拥有的:
select locationcode from MasterAddressCode tmp
join address a on a.street = tmp.[street name], a.prefix = tmp.prefix, a.tag = tmp.tag
where a.number between tmp.[from] and tmp.[to]
这就是我被困的地方。地址[number]列的值与您预期的值相同 - 123,4567,8899988 - 但也有例外,如123 1 / 2,345 / 3,678 1/4。
此外,与MasterAddressCode的匹配还取决于数字是偶数还是奇数 - 但不是所有地址,只有那些在MasterAddressCode中具有'E'表示偶数或'O'表示Odd的地址。[代码]专栏。
光标脚本正在执行以下操作:
-- Iterate through all records in address
-- if location code does not match what is in MasterAddressCode, update the location code
DECLARE @addID INT
DECLARE @street varchar (30)
DECLARE @tag VARCHAR(20)
DECLARE @prefix VARCHAR(10)
DECLARE @number VARCHAR(12)
DECLARE @num INT
DECLARE @recCt INT
DECLARE @newLocCode VARCHAR(40)
DECLARE add_cursor CURSOR FOR
select addressid from address
OPEN add_cursor
FETCH NEXT from add_cursor into @addID
WHILE @@FETCH_STATUS = 0
BEGIN
Print @addID;
set @street = (select street from address where addressid = @addID)
set @tag = (select tag from address where addressid = @addID)
set @number = (select number from address where addressid = @addID)
set @prefix = (select prefix from address where addressid = @addID)
--cast number as int and remove 1/2 if there
IF @number like ('%1/2') or @number like ('%1/3')or @number like ('%1/4')
BEGIN
set @number = LEFT(@number, LEN(@number) - 3)
END
set @recCt = (select count(*) from MasterAddressCode where [Street Name] = @street
and tag = @tag
and prefix = @prefix
and (@num between [From] and [To] ))
--check for the street to be 'odd'
IF @recCt > 1 and (@num%2)<>0 and (@street is not NULL or @street != '') and (@number is not NULL)
BEGIN
set @newLocCode = (SELECT LocationCode FROM MasterAddressCode
WHERE (@num between [From] and [To])
AND [Street Name] = @street
AND tag = @tag
AND Code = 'O' )
PRINT 'Odd ' + @number + ' ' + @newLocCode
END
--check for the street to be 'even'
IF @recCt > 1 and (@num%2)=0 and (@street is not NULL or @street != '') and (@number is not NULL)
BEGIN
set @newLocCode = (SELECT LocationCode FROM MasterAddressCode
WHERE (@num between [From] and [To])
AND [Street Name] = @street
AND tag = @tag
AND Code = 'E' )
PRINT 'Even ' + @number + ' ' + @newLocCode
END
--default update
IF @recCt = 1 and (@street is not NULL or @street != '') and (@number is not NULL)
BEGIN
set @newLocCode = (SELECT LocationCode FROM MasterAddressCode
WHERE (@num between [From] and [To])
AND [Street Name] = @street
AND tag = @tag
AND Code = '' or Code is NULL)
PRINT 'Default ' + @number + ' ' + @newLocCode
END --else
IF @street is NULL or @number is NULL
BEGIN
set @newLocCode = NULL
PRINT 'NULL in number or street'
END
update address set location_code = @newLocCode where addressid = @addID
FETCH NEXT FROM add_cursor INTO @addID
END --while
CLOSE add_cursor
DEALLOCATE add_cursor
所以......任何建议都会受到赞赏!
答案 0 :(得分:0)
嗯,我把它放在一起,我希望(手指交叉)它应该工作
;WITH A AS
(
SELECT *,
CASE
WHEN number like '%1/2' or number like '%1/3' or number like '%1/4'
THEN LEFT(number, LEN(number) - 3)
ELSE number
END AS New_Number
FROM [address]
)
update A
set A.location_code = CASE
WHEN MA2.recCt > 1 and (A.New_Number%2)<>0 and (A.street is not NULL or A.street != '')
and (A.New_Number is not NULL) AND MA.Code = 'O'
THEN MA.LocationCode
WHEN MA2.recCt > 1 and (A.New_Number%2)=0 and (A.street is not NULL or A.street != '')
and (A.New_Number is not NULL) AND MA.Code = 'E'
THEN MA.LocationCode
WHEN MA2.recCt = 1 and (A.street is not NULL or A.street != '') and (A.New_Number is not NULL)
AND (MA.Code = '' or MA.Code is NULL)
THEN MA.LocationCode
WHEN A.New_Number IS NULL OR A.street IS NULL
THEN NULL
END
FROM A
INNER JOIN MasterAddressCode MA ON A.tag = MA.tag
AND A.prefix = MA.prefix
AND A.street = MA.[Street Name]
AND A.New_Number
BETWEEN MA.[from] AND MA.[to]
INNER JOIN
( SELECT [Street Name] , tag, prefix, COUNT(*) AS recCt
FROM MasterAddressCode MA
INNER JOIN [address] A ON A.tag = MA.tag
AND A.prefix = MA.prefix
AND A.street = MA.[Street Name]
AND A.New_Number
BETWEEN MA.[from] AND MA.[to]
GROUP BY [Street Name] , tag, prefix
) MA2 ON A.tag = MA2.tag
AND A.prefix = MA2.prefix
AND A.street = MA2.[Street Name]
AND A.New_Number
BETWEEN MA2.[from] AND MA2.[to]
答案 1 :(得分:0)
没有要测试的数据,我不知道我是否正确或性能如何,但我相当确定我包含了迭代器中的每一段逻辑。您可以查看here或查看以下内容:
;WITH allMasterAddresses AS (
SELECT [Street Name] AS StreetName, Tag, Prefix, [From], [To], [Code], [LocationCode]
FROM dbo.MasterAddressCode
)
, addressWithStrippedNumber AS (
SELECT addressID
, CASE
WHEN RIGHT(address.number, 3) IN ('1/2', '1/3', '1/4') THEN LEFT(address.number, LEN(address.number) - 3)
ELSE address.number
END AS number
FROM dbo.Address address
)
/* Run this SELECT instead of the UPDATE to evaluate results before updating */
/*
SELECT address.addressID
, address.street
, address.tag
, address.prefix
, addressStripped.number
, address.location_code AS CurrentLocationCode
, CASE
WHEN address.street IS NULL OR addressStripped.number IS NULL THEN NULL
ELSE masterAddress.LocationCode
END AS NewLocationCode
*/
UPDATE address
SET address.location_code = CASE
WHEN address.street IS NULL OR addressStripped.number IS NULL THEN NULL
ELSE masterAddress.LocationCode
END
FROM dbo.Address address
INNER JOIN addressWithStrippedNumber addressStripped ON address.addressID = addressStripped.addressID
INNER JOIN (
SELECT StreetName, Tag, Prefix, [From], [To], COUNT(0) AS Total
FROM allMasterAddresses
GROUP BY StreetName, Tag, Prefix, [From], [To]
) AS masterAddresses ON address.street = masterAddresses.StreetName
AND address.tag = masterAddresses.Tag
AND address.prefix = masterAddresses.Prefix
AND addressStripped.number BETWEEN masterAddresses.[From] and masterAddresses.[To]
AND masterAddresses.Total > 0
INNER JOIN allMasterAddresses AS masterAddress ON address.street = masterAddress.StreetName
AND address.tag = masterAddress.Tag
--AND address.prefix = masterAddress.Prefix /* this isn't in your original logic, but don't you need it? */
AND addressStripped.number BETWEEN masterAddress.[From] and masterAddress.[To]
AND isNull(masterAddress.Code, '') = CASE
WHEN masterAddresses.Total = 1 THEN ''
ELSE CASE
WHEN addressStripped.number % 2 != 0 THEN 'O'
ELSE 'E'
END
END
WHERE isNull(address.street, '') != ''
AND addressStripped.number IS NOT NULL;