2012-09-17 25 views
1

時,我有以下代碼:ORA-14551插入GTT

CREATE OR REPLACE FUNCTION repeatable_rand_text(ftype IN VARCHAR2 
               , in_val IN VARCHAR2) 
    RETURN VARCHAR2 IS 
    workval   VARCHAR2(64); 
    insert_needed BOOLEAN := FALSE; 
BEGIN 
    BEGIN 
     SELECT new_name 
     INTO workval 
     FROM ps_dt_mixnames_preserve 
     WHERE name_type = ftype AND old_name = in_val; 

    EXCEPTION 
     WHEN NO_DATA_FOUND THEN 
      workval := rand_text(ftype); 
      insert_needed := TRUE; 
    END; 

    IF insert_needed THEN 
     INSERT INTO ps_dt_mixnames_preserve(name_type, old_name, new_name) 
     VALUES  (ftype, in_val, workval); 
    END IF; 

    RETURN workval; 
END repeatable_rand_text; 

這個程序的目的,是在一個數據庫中,以掩蓋名稱作爲準備創建一個生產發展數據庫的一部分。

我們要掩蓋的名字,但我們希望他們是可重複的,這樣我們的結果是這樣的:(左側輸入;右邊輸出)

JOHN JONES -> STEEL POTATO 
SAM JONES -> LARGE POTATO 
MARY JONES -> WHITE POTATO 
SUE SMITH -> LARGE CARROT 
FRED JONES -> RED POTATO 
JOHN SMITH -> GREEN CARROT 

你可能得到的想法:姓氏被更改爲隨機值,但在再次遇到時重複。鑑於名字只是隨機的。在這裏,這是一個令人擔憂的姓氏。

對於我們來說,數組和其他非永久性解決方案不會很好,因爲這實際上將作爲在同一會話中執行的大量UPDATE語句來執行。 GTT似乎非常適合這種類型的事情。

最終,我們會想執行類似的更新:

UPDATE MY_TABLE 
SET ORIG_NAME = repeatable_rand_text('last', ORIG_NAME) 

但爲了「證明這個程序的結果,我們執行下列SQL:

SELECT ORIG_NAME, repeatable_rand_text('last',ORIG_NAME) 
FROM MY_TABLE 

現在,很明顯,該函數中的INSERT將作爲SELECT的結果執行,這是一個不允許的(並且,如果不能這樣做,我們就不願意嘗試自然而然地發生的UPDATE。儘管我們知道,它可能會失敗並帶有類似的信息。)問題是,圍繞這種情況有沒有合理的方法?

回答

1

我終於使用了一個自治區塊。這些都不是一個好主意,但在這種情況下,我認爲這只是票。這是它的外觀:

function repeatable_rand_text(ftype IN VARCHAR2, in_val IN VARCHAR2) 
    -- The idea is to assign random values to an entity (such as family name), 
    -- and to repeat that value each time that entity is seen again. In this 
    -- manner, we can assign random values without losing associations such as 
    -- (again) family NAMES. 
    --  JONES -> POTATO 
    --  SMITH -> CARROT 
    --  DOE -> ONION 
    --  JONES -> POTATO 
    -- 
    -- Parameters: 
    -- field-type ('ADJ' 'NOUN' 'BOTH') 
    -- field-value 
    -- 
    RETURN VARCHAR2 
    DETERMINISTIC IS 
    PRAGMA AUTONOMOUS_TRANSACTION; 
    workval   VARCHAR2(64); 
    insert_needed BOOLEAN := FALSE; 
BEGIN 
    BEGIN 
     SELECT new_name 
     INTO workval 
     FROM ps_dt_mixnames_preserve 
     WHERE name_type = UPPER(ftype) AND old_name = UPPER(in_val); 
    EXCEPTION 
     WHEN NO_DATA_FOUND THEN 
      workval := rand_text(ftype); 
      insert_needed := TRUE; 
    END; 

    IF insert_needed THEN 
     INSERT 
     INTO ps_dt_mixnames_preserve(name_type, old_name, new_name) 
     VALUES (UPPER(ftype), UPPER(in_val), UPPER(workval)); 

     COMMIT; 
    END IF; 

    RETURN workval; 
END repeatable_rand_text; 
0

不是特別漂亮,但你可以使用匿名塊:

set serveroutput on 
declare 
    cursor c is 
     SELECT ORIG_NAME 
     FROM MY_TABLE; 
begin 
    for r in c loop 
     dbms_output.put_line(r.orig_name || ' -> ' || 
      repeatable_rand_text('last', r.orig_name)); 
    end loop; 
end; 
/

根據不同的數據量,這可能是不實際的。而且你可以填充這些值以使它們對齊。

您是不是應該撥打rand_text(in_val)而不是rand_text(ftype)?這將始終得到'last'的隨機版本,但要公平,它仍然會因in_val的每個值而不同。

+0

謝謝,這是一個有趣的方法;我喜歡。要回答你的問題,不要; rand_text('first')將返回形容詞(「Obstinate」),而rand_text('last')將返回名詞(「Pepper」)。但我可以看到你爲什麼想不到。再次感謝。 – Dennis

+0

啊,是的,重新理解這個問題是有道理的。一行'rand_text()'我測試了這個沒有* 8-) –

0

你可能會嘗試一個md5哈希掩碼。通過這種方式,該表包含不可轉換爲原始(實際)名稱的散列值。我還假設您的查詢通常會通過emp_id或類似的鍵加入,而不是實際的名稱。

所以更新您的開發表一勞永逸名稱:

update my_table 
set lastname = rawtohex(dbms_crypto.hash(utl_i18n.string_to_raw(lastname,'AL32UTF8'),2)); 

commit; 

注意,這是在姓大小寫敏感的,但你可以做一個上(姓氏)如果你想。希望有所幫助。