#oracle #dynamic #plsql
#Oracle #динамическое #plsql
Вопрос:
Мне нужно создать динамический выбор таким образом
fielda = 'Y';
fieldB = 'N';
fieldC = 'Y';
select * from tablea
where tablea.id = 9999
if (fielda = 'Y')
and tablea.a = 'XXX' --add this condition
End if
if (fieldb = 'Y')
and tablea.b = 'YYY' -- not add this condition
End if
if (fieldc = 'Y')
and tablea.c = 1234 --add this condition
End if
...
...
Результат выбора должен быть
select * from tablea
where tablea.id = 9999
and tablea.a = 'XXX'
and tablea.c = 1234
Теперь я должен создать это
sqlstm := 'select * from tablea';
sqlstm := sqlstm || ' where tablea.id = 9999 ';
if (fielda = 'Y')
sqlstm := sqlstm || ' and tablea.a = '''XXX''' '
End if
blah blah blah
execute immediate sqlstm
Но знаете ли вы способ сделать это без «sqlstm бла-бла-бла» и «выполнить немедленно»?
С уважением, Марко
Ответ №1:
Вы можете использовать OR
AND
подобные условия и, учитывая, что значения полей будут равны Y или N.
select * from tablea
where tablea.id = 9999
And ( (fielda = 'N' OR tablea.a = 'XXX')
AND (fieldb = 'N' OR tablea.b = 'YYY')
AND (fieldc = 'N' OR tablea.c = 1234)
)
Комментарии:
1. Извините, я должен объяснить лучше
2. Теперь смотрите обновленный ответ. Также вместо
fielda = 'N'
вы можете написатьfielda != 'Y'
в соответствии с вашим требованием.
Ответ №2:
Если у вас есть только несколько возможных условий, я бы также предложил не использовать динамический SQL. Однако, если у вас много полей и / или они могут отображаться в любой комбинации, динамическое решение может быть таким:
DECLARE
sqlstr VARCHAR2(30000);
curId NUMBER := DBMS_SQL.OPEN_CURSOR;
ret INTEGER;
refCur SYS_REFCURSOR;
BEGIN
sqlstr := 'select * from tablea where tablea.id = 9999 ';
IF (fielda = 'Y') THEN
sqlstr := sqlstr 'AND tablea.a = :p1 ';
END IF;
IF (fieldb = 'Y') THEN
sqlstr := sqlstr 'AND tablea.b = :p2 ';
END IF;
IF (fieldc = 'Y') THEN
sqlstr := sqlstr 'AND tablea.c = :p3 ';
END IF;
DBMS_SQL.PARSE(curid, sql_stmt, DBMS_SQL.NATIVE);
IF (fielda = 'Y') THEN
DBMS_SQL.BIND_VARIABLE(curid, ':p1', 'XXX');
END IF;
IF (fieldb = 'Y') THEN
DBMS_SQL.BIND_VARIABLE(curid, ':p2', 'YYY');
END IF;
IF (fieldc = 'Y') THEN
DBMS_SQL.BIND_VARIABLE(curid, ':p3', 123);
END IF;
ret := DBMS_SQL.EXECUTE(curId);
refCur := DBMS_SQL.TO_REFCURSOR(curId);
-- DBMS_SQL.RETURN_RESULT(refCur);
-- or
FETCH refCur BULK COLLECT INTO ...;
-- process the result
CLOSE refCur;
END;
Но это может быть излишним для вашей ситуации.
Ответ №3:
Не используйте динамический SQL; просто используйте один оператор SQL:
SELECT *
FROM tablea
WHERE id = 9999
AND ( ( fielda = 'Y' AND a = 'XXX' )
OR ( fieldb = 'Y' AND b = 'YYY' )
OR ( fieldc = 'Y' AND c = 1234 )
);
(Примечание: если вы выполняете запрос только из одной таблицы, то использование идентификатора таблицы в качестве префикса перед каждым столбцом является избыточным.)
(Примечание 2: если вы используете this is PL / SQL, тогда вам нужно будет использовать SELECT ... INTO ... FROM ...
[или BULK COLLECT INTO
] .)
Вы можете использовать приведенный выше запрос с переменными fielda
fieldb
и fieldc
с помощью курсора PL / SQL:
DECLARE
cur SYS_REFCURSOR;
fielda CHAR(1) := 'Y';
fieldb CHAR(1) := 'N';
fieldc CHAR(1) := 'Y';
data tablea%ROWTYPE;
BEGIN
OPEN cur FOR
SELECT *
FROM tablea
WHERE id = 9999
AND ( ( fielda = 'Y' AND a = 'XXX' )
OR ( fieldb = 'Y' AND b = 'YYY' )
OR ( fieldc = 'Y' AND c = 1234 )
);
LOOP
FETCH cur INTO data;
EXIT WHEN cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(
data.a || ' ' || data.b || ' ' || data.c || ' ' || data.x
);
END LOOP;
END;
/
или, BULK COLLECT INTO
коллекции:
DECLARE
fielda CHAR(1) := 'Y';
fieldb CHAR(1) := 'N';
fieldc CHAR(1) := 'Y';
a_table SYS.ODCIVARCHAR2LIST;
b_table SYS.ODCIVARCHAR2LIST;
c_table SYS.ODCIVARCHAR2LIST;
x_table SYS.ODCINUMBERLIST;
BEGIN
SELECT a, c, b, x
BULK COLLECT INTO a_table, b_table, c_table, x_table
FROM tablea
WHERE id = 9999
AND ( ( fielda = 'Y' AND a = 'XXX' )
OR ( fieldb = 'Y' AND b = 'YYY' )
OR ( fieldc = 'Y' AND c = 1234 )
);
FOR i IN 1 .. a_table.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(
a_table(i) || ' ' || b_table(i) || ' ' || c_table(i) || ' ' || x_table(i)
);
END LOOP;
END;
/
Что для образца данных:
CREATE TABLE tablea ( id, a, b, c, x ) AS
SELECT 9999, 'XXX', 'AAA', 1111, 1 FROM DUAL UNION ALL
SELECT 9999, 'BBB', 'YYY', 2222, 2 FROM DUAL UNION ALL
SELECT 9999, 'CCC', 'CCC', 1234, 3 FROM DUAL;
Оба вывода:
XXX AAA 1111 1 CCC CCC 1234 3
db<>скрипка здесь
Комментарии:
1. Извините, я должен объяснить лучше
2. @SirLancillotto Ваше обновление ничего не меняет, вам по-прежнему нужен тот же запрос.