2015-04-07 24 views
1

我正在处理两个表 - 一个用于地址,另一个用于MasterAddressCodes。基于另一个表上的值更新表的SQL集操作

我需要使用地址的位置代码更新地址表,因为它在MasterAddressCodes表中。

这已经是使用游标编写的脚本,但效率非常低,需要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] 

这里是哪里我是st科军。地址[号码]列的值与您所期望的一样 - 123,4567,8899988 - 但也有例外,如123 1/2,345 1/3,678 1/4。

此外,与MasterAddressCode的匹配还取决于数字是偶数还是奇数 - 但不是所有地址,只有那些在MasterAddressCode中具有偶数或'O'奇数的'E'的数字。 [code]栏。

光标脚本执行以下操作:

-- 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

其中'@ num'正在填充脚本中? –

回答

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] 
+0

所以......当我运行这个时,在最后的联接中有A.new_number的错误。如果我删除数字作为加入的一个因素,显然它不会抓住正确的位置代码...我会看看我是否可以推荐它...并且谢谢你! 如果你不介意我的问题 - 你的思想过程是什么把它们拉在一起?我卡住只看到更新迭代,似乎无法围绕创建一套语法... – 90mph

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; 
+0

这跑了不起 - 但错了:-( 它看起来像它抓住位置代码从第一次匹配它在MasterAddressCode表中找到... – 90mph

+0

你能说清楚它应该如何定位它的locationCode,而不是我怎么做的?我真的不明白规范,所以基本上是试图逆向工程你的代码。可以调整它,一旦我可以清楚地了解它做错了什么。 –

相关问题