Oracle 插入GTT时使用ORA-14551

Oracle 插入GTT时使用ORA-14551,oracle,plsql,temp-tables,Oracle,Plsql,Temp Tables,我有以下代码: 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

我有以下代码:

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;
此例程的目的是在准备从生产中创建开发数据库时屏蔽数据库中的名称

我们想屏蔽名称,但我们希望它们是可重复的,这样我们的结果就像:(左边的输入;右边的输出)

您可能会想到:姓氏更改为随机值,但在再次遇到时会重复。给定的名称只是随机的。在这里,姓氏是一个值得关注的问题

数组和其他非永久性解决方案对我们来说不会很好地工作,因为这实际上将作为一系列更新语句执行,所有更新语句都在同一个会话中执行。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的结果执行,这是不允许的(如果不能做到这一点,我们就不愿意尝试随后自然进行的更新。据我们所知,它可能会失败,并出现类似的消息)问题是,有没有一种合理的方法来解决这个问题?

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

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\u text(in\u val)
而不是
rand\u text(ftype)
?这将总是得到一个随机版本的
'last'
,虽然公平地说,对于
in\u val
中的
的每个值仍然是不同的,但不是特别漂亮,但是你可以使用一个匿名块:

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\u text(in\u val)
而不是
rand\u text(ftype)吗
?这将始终得到一个随机版本的
“last”
,但公平地说,每个
值在_val

中仍然是不同的。您可以尝试使用md5哈希进行掩蔽。这样,表中包含的哈希值就无法转换为原始值(实际值)我还假设您的查询通常会通过emp_id或类似的键连接,而不是实际的名称

因此,为所有名称更新一次dev表:

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

commit;

请注意,这对lastname是区分大小写的,但如果愿意,您可以使用大写(lastname)。希望有帮助。

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

因此,为所有名称更新一次dev表:

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

commit;

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

我最终使用了一个自治块。这些都不是一个好主意,但在这种情况下,我认为这只是一张罚单。下面是它的外观:

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;

我最终使用了一个自动闭塞。这很少是一个好主意,但在这种情况下,我认为这只是一张罚单。下面是它的外观:

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;

谢谢,这是一个有趣的方法;我喜欢它。要回答你的问题,不;rand_text('first')将返回形容词(“顽固不化”),rand_text('last')将返回名词(“胡椒”)。但我明白你为什么不这么想。再次感谢。啊,是的,重读这个问题是有意义的。这一行
rand_text()
我做了个模拟来测试这一点没有*8-)谢谢,这是一个有趣的方法;我喜欢它。回答你的问题,不;rand_text('first')将返回形容词(“顽固”),rand_text('last')将返回名词(“胡椒”).但我明白你为什么不这么想。再次感谢。啊,是的,重读这个问题是有意义的。我为测试这一点而做的一行
rand_text()
没有*8-)