数组循环中的Oracle查询 - 奇怪的结果

时间:2016-04-06 13:30:52

标签: oracle plsql oracle11g database-scripts

我循环遍历数组并执行插入/更新。在循环中,我检查记录是否存在。如果没有,请执行插入。如果是,则执行更新。 STRING_SPLIT_FNC是一个包,它接受一个字符串并将其拆分为分隔符(〜)并将拆分的字符串存储在一个数组中。

DECLARE

service_name VARCHAR(50) := 'Service1';
service_version VARCHAR(10) := '2016';
i INTEGER;
record_count NUMBER;
TYPE T_ARRAY_OF_VARCHAR IS TABLE OF VARCHAR(2000) INDEX BY BINARY_INTEGER;
main_array T_ARRAY_OF_VARCHAR;
split_array STRING_SPLIT_FNC.T_ARRAY;

BEGIN
    main_array(1) := '2014|2015|2016|~service.info~25500~NULL~1';
    main_array(2) := '2014|2015|2016|2017~service.path~/mypath/myfolder/myfile.zip~0';
    main_array(3) := '2014|2015|2016|2017|2018~service.date~Yes~NULL~1';

    SELECT COUNT(SERVICE_ID) INTO record_count FROM TEST_SERVICE WHERE SERVICE_DESC = service_name AND SERVICE_VERSION = service_version;
    IF record_count = 0 THEN
       INSERT INTO TEST_SERVICE(SERVICE_ID, SERVICE_DESC, SERVICE_VERSION) VALUES (SERVICE_SEQ.nextval, service_name, service_version);
    END IF;

SELECT SERVICE_ID INTO service_id FROM TEST_SERVICE WHERE SERVICE_DESC = service_name AND SERVICE_VERSION = service_version;


    i := main_array.FIRST;
    LOOP
        record_count := 0;
        split_array := STRING_SPLIT_FNC.SPLIT(main_array(i),'~');
        IF (INSTR(split_array(1), service_version) > 0) THEN
            DBMS_OUTPUT.PUT_LINE('Record count prior: ' || record_count || ' Service Id: ' || service_id || ' Config: ' || split_array(2));
            SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = split_array(2);      
            DBMS_OUTPUT.PUT_LINE('Record count after: ' || record_count || ' Service Id: ' || service_id || ' Config: ' || split_array(2));
            IF record_count = 0 THEN          
               INSERT INTO TEST_REF_SERVICE_CONFIG (REF_CONFIG_ID, SERVICE_ID, CONFIG_NAME, DEFAULT_VALUE, ALLOW_OVERRIDE) VALUES (REF_SERVICE_CONFIG_SEQ.nextval, service_id, split_array(2), split_array(3), TO_NUMBER(split_array(5)));
               DBMS_OUTPUT.PUT_LINE('Inserted Service: ' || service_name || '[' || service_version || '], Config: ' || split_array(2) || ' [' || split_array(3) || '], Override: ' || split_array(5));
            ELSE
               record_count := 0;
               SELECT COUNT(REF_CONFIG_ID) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = split_array(2) AND DEFAULT_VALUE = split_array(3);
               IF record_count = 0 THEN   
                   DBMS_OUTPUT.PUT_LINE('Record count after [in update part]: ' || record_count);
                   UPDATE TEST_REF_SERVICE_CONFIG SET DEFAULT_VALUE = split_array(3), ALLOW_OVERRIDE = split_array(5) WHERE SERVICE_ID = service_id AND CONFIG_NAME = split_array(2) AND DEFAULT_VALUE = split_array(3);
                   DBMS_OUTPUT.PUT_LINE('Updated Service: ' || service_name || '[' || service_version || '], Config: ' || split_array(2) || ' [' || split_array(3) || '], Override: ' || split_array(5));
               ELSE
                   record_count := 0;
                   DBMS_OUTPUT.PUT_LINE('No insert or update performed.  Service: ' || service_name || '[' || service_version || '], Config: ' || split_array(2) || ' [' || split_array(3) || '], Override: ' || split_array(5));
               END IF;
            END IF;
        ELSE 
            DBMS_OUTPUT.PUT_LINE('Specified service/version not found ' || service_name || '[' || service_version || ']');
        END IF;
        i := main_array.NEXT(i);

        EXIT WHEN i IS NULL;
    END LOOP;
    END;

假设TEST_REF_SERVICE_CONFIG表中没有记录。 现在,让我们说我为service_name = Service1和service_version = 2015运行它.service_id是500.来自main_array的所有3个元素都被插入。

现在,我运行service_name = Service1和service_version = 2017.服务ID是502.它应该只插入main_array中的最后2条记录。

当下面的查询应为0时,返回record_count = 1:

SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = split_array(2);      

当我单独运行查询时,我将计为0。

SELECT COUNT(*) FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = 502 AND CONFIG_NAME = 'service.path';

为什么循环中的查询在为0时返回计数为1?我也尝试过:

DECLARE
config_name VARCHAR(250);
...
LOOP
            record_count := 0;
            split_array := STRING_SPLIT_FNC.SPLIT(main_array(i),'~');
            IF (INSTR(split_array(1), service_version) > 0) THEN
               config_name := split_array(3);
               SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = config_name;  

现在我将record_count设为121 !!! 在此先感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

我认为这里发生的事情是由于您为变量选择了与表中列相同的名称。

当您在查询中引用变量时,应使用:符号作为前缀。 所以,而不是这样做:

           SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = config_name; 

你应该这样做:

           SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = :service_id AND CONFIG_NAME = :config_name; 

或者更好的是,为变量和列名使用不同的命名约定,以使代码更具可读性。

省略:前缀的结果是Oracle将其解释为"给我所有记录,其中SERVICE_ID列的值等于SERVICE_ID列的值......",这将适用于所有记录。

答案 1 :(得分:1)

我认为你可能会遇到别名问题。

 WHERE **SERVICE_ID = service_id** AND CONFIG_NAME = split_array(2);      

解决此问题的方法是将变量名称更改为与列名称不同。如果这是一个PL / SQL过程或函数,您可以在变量名前加上过程或函数的名称,但不能在匿名块中执行此操作。