使用变量限制游标中的记录

时间:2013-10-31 23:34:08

标签: oracle

我不确定如何最好地描述我的问题

我有一个表(NR_POSTAL_ABBR),它有邮政缩写和它们代表的含义,如ST和STREET,AVE和AVENUE。我希望能够用该表中的值替换地址字段。

如果我有一个地址123 Main ST我想要说123 Main Street。我有一个程序执行此操作(如下)。它很慢,现在我有一张3M记录表,它必须通过400个缩写对才会永远运行。

所以我正在考虑加快这个速度的方法。一种方法是只循环遍历地址字段中具有abbr的记录,所以执行类似下面的操作,但它不起作用,因为它位于错误的位置。

所以2部分问题

  1. 有没有更好的方法来实现我想要做的事情?
  2. 如果没有,那么我如何修复以下程序,以便能够仅限地址具有NR_POSTAL_ABBR表中的ReplaceWhat值的记录
  3. 谢谢

    ETA NewAddress字段的地址为。,:;用空格代替。这样我只能替换值,如果它们是整个单词(st,而不是west)

    我想用

    替换第二个CURSOR
         CURSOR readMainTable IS
           SELECT A.*
             FROM analyst.NR_TMP_105 A
    WHERE NeweAddress LIKE '%' || VariableThatHoldsTheReplaceWhatValue || '%';
    

    我目前拥有的程序,虽然有效但很慢

    DECLARE
         CURSOR getReplsStrng IS
           SELECT replacewhat
              ,replacewith
             FROM analyst.NR_POSTAL_ABBR
            WHERE ReplaceOrder = 1;
    
         CURSOR readMainTable IS
           SELECT A.*
             FROM analyst.NR_TMP_105 A;
    
         lvAddress VARCHAR2(5000);
         lvTmpAddress VARCHAR2(5000);
         lnPos NUMBER(10);
         lnPosPls NUMBER(10);
         lvPosPls VARCHAR2(500);
         lvPosMinus VARCHAR2(500);
         lnLoopCnt NUMBER := 0;
         lvCty VARCHAR2(200);
         lvBfUpd VARCHAR2(500);
         lvAfterUpd VARCHAR2(500);
    BEGIN
         lnLoopCnt := 0;
    
         FOR getRec IN readMainTable LOOP
           lnLoopCnt := lnLoopCnt + 1;
    
           lvAddress := NULL;
           lvTmpAddress := NULL;
    
           lvAddress := getRec.NewAddress;
           lvTmpAddress := getRec.NewAddress;
    
           FOR getInnerRec IN getReplsStrng LOOP
             lvPosPls := NULL;
             lvPosMinus := NULL;
             lnPos := 0;
             lnPos := INSTR(UPPER(lvAddress), UPPER(getInnerRec.replacewhat), 1, 1);
    
             IF lnPos > 0 THEN
                  NULL;
    
                  lvPosPls := SUBSTR(UPPER(lvAddress)
                           ,((  INSTR(UPPER(lvAddress), UPPER(getInnerRec.replacewhat), 1, 1)
                              + LENGTH(UPPER(getInnerRec.replacewhat))))
                           ,1);
                  lvPosMinus := SUBSTR(UPPER(lvAddress), (INSTR(UPPER(lvAddress), UPPER(getInnerRec.replacewhat), 1, 1) - 1), 1);
    
                  IF     (   lvPosPls IS NULL
                    OR lvPosPls = CHR(32))
                  AND (   lvPosMinus = CHR(32)
                    OR lvPosMinus = CHR(32)) THEN
                    lvAddress := REPLACE(UPPER(lvAddress), UPPER(getInnerRec.replacewhat), UPPER(getInnerRec.replacewith));
    
                    lvAddress := LOWER(lvAddress);
                  ELSIF lvPosPls IS NOT NULL THEN
                    NULL;
                  END IF;
                  BEGIN
                    UPDATE analyst.NR_TMP_105 b
                    SET b.NewAddress = lvAddress
                     WHERE   b.NewAddress = lvTmpAddress
                        AND b.UniqueID = getRec.UniqueID;
                    COMMIT;
                  EXCEPTION
                    WHEN OTHERS THEN
                      DBMS_OUTPUT.put_line('Error in updating the address : ' || lvTmpAddress);
                  END;
             ELSIF lnPos = 0 THEN
                  NULL;
             END IF;
    
             lvTmpAddress := lvAddress;
    
             IF MOD(lnLoopCnt, 200) = 0 THEN
                  COMMIT;
                  NULL;
             END IF;
           END LOOP;
         END LOOP;
    
         COMMIT;
    EXCEPTION
         WHEN OTHERS THEN
           DBMS_OUTPUT.put_line('Error in main process:' || SUBSTR(SQLERRM, 1, 200));
    END;
    

1 个答案:

答案 0 :(得分:1)

如果我得到你的第二部分,那么你可以按照

的方式做点什么
CURSOR readMainTable IS
   SELECT DISTINCT A.*
     FROM analyst.NR_TMP_105 A
     INNER JOIN NR_POSTAL_ABBR B
     ON (A.NewAddress like ' %'||B.replacewhat||'%'
    WHERE B.ReplaceOrder = 1

这应该只为您提供需要替换的地址(或者可能需要替换它们 - 您可能需要对其进行优化)。 有没有更好的办法?也许,但你如何决定是否需要付出额外的努力。