【问题标题】:ORA-14551 when inserting into GTTORA-14551 插入 GTT 时
【发布时间】:2012-09-09 20:59:16
【问题描述】:

我有以下代码:

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。据我们所知,它可能会失败并显示类似的消息。)问题是,是否有合理的方法来解决这种情况?

【问题讨论】:

    标签: oracle plsql temp-tables


    【解决方案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;
    

    【讨论】:

      【解决方案2】:

      不是特别漂亮,但你可以使用匿名块:

      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 的每个值仍然不同。

      【讨论】:

      • 谢谢,这是一个有趣的方法;我喜欢。回答你的问题,不; rand_text('first') 将返回形容词(“Obstinate”),而 rand_text('last') 将返回名词(“Pepper”)。但我明白你为什么不这么认为。再次感谢。
      • 啊,是的,重读这个问题很有意义。一行rand_text()我假装测试这个没有*8-)
      【解决方案3】:

      您可以尝试使用 md5 哈希进行屏蔽。这样,表就包含了不能转换为原始(实际)名称的哈希值。我还假设您的查询通常会通过 emp_id 或类似键加入,而不是实际名称。

      因此,为所有名称更新一次您的开发表:

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

      请注意,姓氏区分大小写,但如果您愿意,可以使用大写(姓氏)。希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 2016-05-06
        • 1970-01-01
        • 2013-04-05
        • 2021-01-17
        • 2013-01-27
        • 1970-01-01
        • 2014-06-29
        • 2014-06-29
        • 1970-01-01
        相关资源
        最近更新 更多