ORA-00936: пропущенное выражение - строка 62 - PullRequest
0 голосов
/ 13 октября 2019

Я несколько часов безуспешно пытался определить, что не так с оператором вставки в «Немедленное выполнение». Удостоверился, что я не пропускаю запятые или ввод неправильного символа.

Я просмотрел все ответы на SO и других сайтах, пытаясь выяснить, что я могу делать неправильно, но не повезло.

Запуск этой функции приводит к следующей ошибке (начинается строка ошибкис "->" Пожалуйста, не обращайте на это внимания, поскольку это просто для подсветки цели):

ORA-00936: missing expression
ORA-06512: at "BDW_AMPS.COUNT_RECORDS", line 62

и вот код PL / SQL для функции:

CREATE OR REPLACE FUNCTION count_records (
    p_test_case_id   IN NUMBER,
    p_table_name     IN VARCHAR2
) RETURN VARCHAR2 IS

    v_amt_recs            INT;
    v_test_result         VARCHAR2(10);
    v_threshold_val       VARCHAR2(10);
    v_test_suite_table    VARCHAR2(100);
    v_test_result_id      NUMBER;
    v_batch_id            NUMBER;
    v_report_id           NUMBER;
    v_test_seq_no         NUMBER;
    v_session_name        VARCHAR2(100);
    v_error_description   VARCHAR2(100);
    v_process_by          VARCHAR2(100);
BEGIN
    v_test_suite_table := 'bdw_amps.spares_bdw_test_suite';
    v_process_by := 'INFORMATICA';
    EXECUTE IMMEDIATE 'SELECT THRESHHOLD_VALUE FROM '
                      || v_test_suite_table
                      || ' WHERE TEST_CASE_ID = '
                      || p_test_case_id
    INTO v_threshold_val;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || p_table_name
    INTO v_amt_recs;

    EXECUTE IMMEDIATE 'SELECT BDW_AMPS.SPARES_TEST_SEQ_ID_SEQ.NEXTVAL FROM DUAL'
    INTO v_test_result_id;

    EXECUTE IMMEDIATE 'SELECT MAX(BATCH_ID) FROM BDW_AMPS.spares_bdw_session_audit 
     WHERE SESSION_NAME=(SELECT SESSION_NAME FROM '
                      || v_test_suite_table
                      || ' WHERE TEST_CASE_ID = '
                      || p_test_case_id
                      || ')'
    INTO v_batch_id;

    EXECUTE IMMEDIATE 'SELECT REPORT_ID FROM '
                      || v_test_suite_table
                      || ' WHERE TEST_CASE_ID = '
                      || p_test_case_id
    INTO v_report_id;

    EXECUTE IMMEDIATE 'SELECT TEST_SEQ FROM '
                      || v_test_suite_table
                      || ' WHERE TEST_CASE_ID = '
                      || p_test_case_id
    INTO v_test_seq_no;

    EXECUTE IMMEDIATE 'SELECT SESSION_NAME FROM '
                      || v_test_suite_table
                      || ' WHERE TEST_CASE_ID = '
                      || p_test_case_id
    INTO v_session_name;

    IF
        v_amt_recs > v_threshold_val
    THEN
        v_test_result := 'PASS';

    --> EXECUTE IMMEDIATE 'INSERT INTO BDW_AMPS.spares_bdw_test_results(
        TEST_RESULT_ID, 
        BATCH_ID, 
        REPORT_ID, 
        TEST_CASE_ID, 
        TEST_SEQ_NO, 
        TABLE_NAME, 
        SESSION_NAME, 
        TEST_RESULT, 
        PROCESS_DATE, 
        PROCESS_BY
        )
        VALUES 
        ('|| v_test_result_id || ',
        ' || v_batch_id || ',
        ' || v_report_id || ',
        ' || p_test_case_id || ',
        ' || v_test_seq_no || ',
        ' || p_table_name || ',
        ' || v_session_name || ',
        ' || v_test_result || ',
        SYSDATE,
        ' || v_process_by || '
        )';

    EXECUTE IMMEDIATE 'commit';

    ELSE
        v_test_result := 'FAIL';
        v_error_description := 'Count: ' || v_amt_recs || ' is greater than threshold value: ' || v_threshold_val;

    EXECUTE IMMEDIATE 'INSERT INTO BDW_AMPS.spares_bdw_test_results(
    TEST_RESULT_ID, 
    BATCH_ID, 
    REPORT_ID, 
    TEST_CASE_ID, 
    TEST_SEQ_NO, 
    TABLE_NAME, 
    SESSION_NAME, 
    TEST_RESULT,
    ERROR_DESCRIPTION,
    PROCESS_DATE, 
    PROCESS_BY
    )
    VALUES (
    '|| v_test_result_id || ',
    ' || v_batch_id || ',
    ' || v_report_id || ',
    ' || p_test_case_id || ',
    ' || v_test_seq_no || ',
    ' || p_table_name  || ',
    ' || v_session_name || ',
    ' || v_test_result || ',
    ' || v_error_description || ',
    SYSDATE,
    ' || v_process_by  || '
    )';
    EXECUTE IMMEDIATE 'commit';

    END IF;

    RETURN v_test_result;
END;

Ответы [ 2 ]

2 голосов
/ 13 октября 2019

Предполагая, что это упрощенный пример чего-то, что действительно должно быть динамичным, одна проблема заключается в том, что строковые значения не заключаются в кавычки. (Если бы у вас были значения даты, они также нуждались бы в специальной обработке.)

Например:

create table demo (numcol number, stringcol varchar2(20));

declare
    l_num number := 123;
    l_string varchar2(20) := 'Kittens';
    l_sql long := 'insert into demo(numcol, stringcol) values ('||l_num||', '||l_string||')';
begin
    dbms_output.put_line(l_sql);
    execute immediate l_sql;
end;
/

Сгенерированный код:

insert into demo(numcol, stringcol) values (123, Kittens)

Сбой с:

ORA-00984: column not allowed here

Ошибка будет зависеть от содержимого строки. Например, если он содержит пробелы:

declare
    l_num number := 123;
    l_string varchar2(20) := 'Kittens are cute';
    l_sql long := 'insert into demo(numcol, stringcol) values ('||l_num||', '||l_string||')';
begin
    dbms_output.put_line(l_sql);
    execute immediate l_sql;
end;
/

Сгенерированный код:

insert into demo(numcol, stringcol) values (123, Kittens are cute)

ORA-00917: missing comma

или запятые:

declare
    l_num number := 123;
    l_string varchar2(20) := 'Kittens, Puppies';
    l_sql long := 'insert into demo(numcol, stringcol) values ('||l_num||', '||l_string||')';
begin
    dbms_output.put_line(l_sql);
    execute immediate l_sql;
end;
/

insert into demo(numcol, stringcol) values (123, Kittens, Puppies)

ORA-00913: too many values

Вам необходимо заключить в кавычки:

declare
    l_num number := 123;
    l_string varchar2(20) := 'Kittens, Puppies';
    l_sql long := 'insert into demo(numcol, stringcol) values ('||l_num||', '''||l_string||''')';
begin
    dbms_output.put_line(l_sql);
    execute immediate l_sql;
end;
/

так что вы генерируете

insert into demo(numcol, stringcol) values (123, 'Kittens, Puppies')

(Если строка может содержать символы кавычек, это потребует дополнительной работы.)

Стоит всегда строить динамический SQL какпеременной и распечатывает или регистрирует ее при сбое, поскольку обычно достаточно ясно, в чем проблема, когда вы видите код.

Другой момент заключается в том, что объединение таких значений требует больших ресурсов, поскольку Oracle пытается кешироватьОператоры SQL для повторного использования, поэтому они будут анализироваться и оптимизироваться индивидуально и занимать место в кеше, но никогда не будут использоваться повторно. Если это будет часто выполняться с разными значениями, вам следует рассмотреть возможность использования переменных связывания через предложение using в execute immediate.

1 голос
/ 13 октября 2019

Ваши операторы DML (INSERT) не нуждаются в операторах EXECUTE IMMEDIATE. Поэтому удалите их после строки 61:

CREATE OR REPLACE FUNCTION count_records (
    p_test_case_id   IN NUMBER,
    p_table_name     IN VARCHAR2
) RETURN VARCHAR2 IS

    v_amt_recs            INT;
    v_test_result         VARCHAR2(10);
    v_threshold_val       VARCHAR2(10);
    v_test_suite_table    VARCHAR2(100);
    v_test_result_id      NUMBER;
    v_batch_id            NUMBER;
    v_report_id           NUMBER;
    v_test_seq_no         NUMBER;
    v_session_name        VARCHAR2(100);
    v_error_description   VARCHAR2(100);
    v_process_by          VARCHAR2(100);
BEGIN
    v_test_suite_table := 'bdw_amps.spares_bdw_test_suite';
    v_process_by := 'INFORMATICA';

    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || p_table_name
    INTO v_amt_recs;

    v_test_result_id := BDW_AMPS.SPARES_TEST_SEQ_ID_SEQ.NEXTVAL;

    EXECUTE IMMEDIATE 'SELECT MAX(BATCH_ID) FROM BDW_AMPS.spares_bdw_session_audit 
     WHERE SESSION_NAME=(SELECT SESSION_NAME FROM '
                  || v_test_suite_table
                      || ' WHERE TEST_CASE_ID = '
                      || p_test_case_id
                      || ')'
    INTO v_batch_id;

    EXECUTE IMMEDIATE 'SELECT THRESHHOLD_VALUE, REPORT_ID, TEST_SEQ,SESSION_NAME FROM '
                      || v_test_suite_table
                      || ' WHERE TEST_CASE_ID = :caseId'
    INTO v_threshold_val,v_report_id,v_test_seq_no,v_session_name
    USING p_test_case_id;

    IF
        v_amt_recs > v_threshold_val
    THEN
        v_test_result := 'PASS';

    INSERT INTO BDW_AMPS.spares_bdw_test_results(
        TEST_RESULT_ID, 
        BATCH_ID, 
        REPORT_ID, 
        TEST_CASE_ID, 
        TEST_SEQ_NO, 
        TABLE_NAME, 
        SESSION_NAME, 
        TEST_RESULT, 
        PROCESS_DATE, 
        PROCESS_BY
        )
        VALUES 
        ( v_test_result_id ,
          v_batch_id ,
          v_report_id ,
          p_test_case_id ,
          v_test_seq_no ,
          p_table_name ,
          v_session_name ,
          v_test_result ,
          SYSDATE,
         v_process_by 
        );

    commit;

    ELSE
        v_test_result := 'FAIL';
        v_error_description := 'Count: ' || v_amt_recs || ' is greater than threshold value: ' || v_threshold_val;

    INSERT INTO BDW_AMPS.spares_bdw_test_results(
    TEST_RESULT_ID, 
    BATCH_ID, 
    REPORT_ID, 
    TEST_CASE_ID, 
    TEST_SEQ_NO, 
    TABLE_NAME, 
    SESSION_NAME, 
    TEST_RESULT,
    ERROR_DESCRIPTION,
    PROCESS_DATE, 
    PROCESS_BY
    )
    VALUES (
    v_test_result_id ,
     v_batch_id ,
     v_report_id ,
     p_test_case_id ,
     v_test_seq_no ,
     p_table_name  ,
     v_session_name ,
     v_test_result ,
     v_error_description ,
    SYSDATE,
     v_process_by  
    );
    commit;

    END IF;

    RETURN v_test_result;
END;

, в то время как их использование подходит для операторов SELECT из-за динамических имен таблиц.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...