Pergunta

Eu preciso usar execução de SQL dinâmica no Oracle onde eu não sei o número exato de variáveis ??de ligação utilizados no SQL antes da execução.

Existe uma maneira de usar um número variável de variáveis ??de ligação na chamada para EXECUTE IMMEDIATE de alguma forma?

Mais especificamente, eu preciso passar um parâmetro para o SQL desconhecida, mas eu não sei quantas vezes ele será usado ali.

Eu tentei algo como

EXECUTE IMMEDIATE 'SELECT SYSDATE FROM DUAL WHERE :var = :var' USING 1;

Mas jogou para trás com ORA-01008: not all variables bound.

Foi útil?

Solução

Você não pode fazer isso com EXECUTE IMMEDIATE. No entanto, você pode fazer isso usando pacote DBMS_SQL da Oracle. O Guia do banco de dados de aplicativos do desenvolvedor tem uma comparação entre a EXECUTE IMMEDIATE você está familiarizado com e métodos dbms_sql. Esta página documentos DBMS_SQL, mas tem alguns exemplos (relacionados acima), que deve começar (exemplo 1 é um caso simples de executar uma declaração de que poderia ter um número arbitrário de variáveis ??de ligação). DBMS_SQL é muito mais complicado do ponto de vista de codificação, mas vai permitir que você faça qualquer coisa que você pode conceber.

Várias instâncias da variável de ligação que ocorre na SQL são permitidos. No entanto, você terá que saber o nome a ser utilizado como variável de ligação (por exemplo: var no seu caso)., A fim de passá-lo para DBMS_SQL.BIND_VARIABLE

Outras dicas

Você também pode contornar esse problema usando uma declaração WITH. Geralmente usando DBMS_SQL é melhor, mas às vezes esta é uma forma mais simples:

BEGIN
    EXECUTE IMMEDIATE 'WITH var AS (SELECT :var FROM dual) SELECT SYSDATE FROM DUAL WHERE (SELECT * FROM var) = (SELECT * FROM var)' USING 1;
END;

Este Linha em AskTom cobre o assunto em detalhes

No seu caso, se você quer passar um parâmetro ou nenhum, você poderia construir duas consultas que têm um único parâmetro e em um destes consulta não é usada (ou seja, o predicado é sempre verdade) como este:

-- query1
SELECT * FROM DUAL WHERE dummy = :x;

-- query2
SELECT * FROM DUAL WHERE nvl(:x, 1) IS NOT NULL;

Você provavelmente pode refinar o predicado para que o otimizador vai entender que é sempre verdade.

Mais especificamente, eu preciso passar um parâmetro para o SQL desconhecida, mas eu não sei quantas vezes ele será usado ali.

Na verdade, eu corri para este exato mesmo problema um par de dias atrás, e um amigo compartilhou comigo uma maneira de fazer exatamente isso com EXECUTE IMMEDIATE.

Trata-se de gerar um bloco PLSQL, em oposição ao próprio bloco SQL. Ao usar EXECUTE IMMEDIATE com um bloco de código PLSQL, você pode vincular variáveis ??pelo nome ao invés de apenas por posição.

Confira o meu exemplo / código e no meu próprio segmento pergunta semelhante / resposta:

Pode-se usar dbms_sql como Steve Broberg explicado, mas o cursor resultante não pode ser consumido (leitura) em um monte de clientes. Oracle 11 adicionou uma função de conversão ( dbms_sql.to_refcursor ) que torna possível converter um cursor dbms_sql a um cursor ref mas por alguma uma razão não pode consumir este cursor ref convertido em um aplicativo .NET. Pode-se consumir um cursor ref normal em .net, mas não um cursor ref que costumava ser cursor dbms_sql.

Assim que tipo de cliente será consumir este cursor?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top