[英]SQL set operation to update table based on values on another table
i am working with two tables - one for Addresses and another for MasterAddressCodes. 我正在使用两个表-一个用于地址,另一个用于MasterAddressCodes。
I need to update the Address table with the locationcode for the address as it is in the MasterAddressCodes table. 我需要使用MasterAddressCodes表中的地址的位置代码更新Address表。
This is already scripted using a cursor, but it is hugely inefficient and takes over 2 hours to complete (225000 records approx), and I know that there has to be a more elegant and performant solution. 这已经使用游标编写了脚本,但是它效率极低,并且需要2个小时才能完成(大约225000条记录),而且我知道必须有一个更优雅,更高效的解决方案。
Here are the table details: 以下是表格的详细信息:
Address: 地址:
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: 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
)
Here's what I have so far: 这是我到目前为止的内容:
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]
And here is where I am stuck. 这就是我被困住的地方。 The address [number] column has values like you would expect - 123, 4567, 8899988 -- but there are also exceptions like 123 1/2, 345 1/3, 678 1/4. address [number]列具有您期望的值-123、4567、8899988-但也有例外,例如123 1 / 2、345 1 / 3、678 1/4。
In addition, the match to the MasterAddressCode will also depend on if the number is even or odd - but not for all addresses, only those that have an 'E' for Even or 'O' for Odd in the MasterAddressCode.[code] column. 另外,与MasterAddressCode的匹配还取决于数字是偶数还是奇数-但不是所有地址,仅取决于MasterAddressCode。[code]列中具有偶数“ E”或奇数“ O”的地址。 。
The cursor script is doing the following: 游标脚本正在执行以下操作:
-- 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
So...any suggestions would be appreciated! 所以...任何建议将不胜感激!
Well I put this together and I hope (fingers crossed) it should work 好吧,我把它们放在一起,希望(手指交叉)它应该工作
;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]
Without data to test against, I have no idea whether I got this right or what the performance will be like, but I am fairly certain I included every piece of logic from your iterator. 没有可以测试的数据,我不知道自己是否正确,或者性能如何,但是我可以肯定地说,我包括了迭代器中的所有逻辑。 You can check it out here or see below: 您可以在此处查看或查看以下内容:
;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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.