Herdei uma consulta com mais de 1.000 linhas que funciona no Oracle SQL Developer.
Quando tento executar a consulta em um script Python, recebo um erro (Ocorreu um erro: ORA-00900: instrução SQL inválida) na linha: EXEC DBMS_STATS.gather_table_stats('SSS', 'YYY') .
Tenho pouca experiência com bancos de dados e uma busca no Google sobre o erro não gerou uma solução possível.
Script Python:
with open('myquery.sql', 'r') as sql_file:
query = str(sql_file.read().replace("\n\n",""))
sql_commands = query.split(';')
for command in sql_commands:
try:
if command.strip() != '':
print(command)
cur.execute(command)
connection.commit()
except Exception as e:
print(f"An error occurred: {e}")
connection.commit()
As últimas linhas da consulta (myquery.sql):
DELETE
FROM CD_SS.MM_DSD_MIG_MASTER;
commit;
INSERT INTO CD_SS.MM_DSD_MIG_MASTER
SELECT DISTINCT
PATTERN,
b_ITEM_NUM,
'N',
NULL, NULL, NULL
FROM CD_SS.MM_DSD_MIG_PATTERNS;
commit;
update MM_DSD_MIG_MASTER
set MIGRATION_STATUS_FLAG = 'Z'
where MIGRATION_STATUS_FLAG = 'N';
commit;
grant all privileges on MM_DSD_MIG_MASTER to public;
grant all privileges on MM_DSD_MIG_PATTERNS to public;
DBMS_STATS.gather_table_stats('CD_SS', 'MM_DSD_MIG_PATTERNS');
DBMS_STATS.gather_table_stats('CD_SS', 'MM_DSD_MIG_MASTER');
Tudo funciona se as linhas DMS_STATS forem omitidas, mas fui informado que isso deve permanecer.
Você está confundindo instruções SQL (que o banco de dados pode executar individualmente) com um script SQL que pode conter várias instruções SQL, PL/SQL ou SQL*Plus. Normalmente, uma ferramenta como SQL*Plus, SQL Developer ou SQLcl lê um script e executa instruções sequencialmente, uma de cada vez. A maioria das instruções será enviada ao banco de dados no estado em que se encontram, mas outras podem afetar apenas a ferramenta, como configurações para alterar o comprimento da linha de exibição, e não serão enviadas ao banco de dados. Outras instruções podem precisar de pré-processamento extra antes de serem enviadas, como,
EXEC DBMS_STATS.xxx()
por exemplo, serão enviadas como uma instrução PL/SQLBEGIN DBMS_STATS.xxx(); END;
.Todos os drivers de linguagem Oracle executam instruções individuais. Se seus scripts SQL contiverem apenas instruções SQL ou PL/SQL (e não comandos SQL*Plus como EXEC, SET ou COLUMN), você pode fazer algo mais elaborado, como https://github.com/oracle/python-oracledb/blob/v3.1.0/samples/sample_env.py#L261-L298 , que lerá e processará um script SQL semelhante a https://github.com/oracle/python-oracledb/blob/v3.1.0/samples/sql/create_schema.sql . Observe que cada instrução termina com uma barra.
Como alternativa, para uso rápido, costumo escrever código Python mais ou menos assim:
Você pode ver que cada instrução é passada individualmente para
execute()
. Observe que não há ponto e vírgula ou barra no final das instruções SQL (qualquer instrução PL/SQL comoBEGIN
/END
precisará de um ponto e vírgula no final). Você precisaria alterar quaisquerEXEC
chamadas paraBEGIN
/,END
como mostrado anteriormente. Não se esqueça de chamar,commit
se necessário.A documentação do Python-oracledb está aqui .
Um recurso recente do python-oracledb, Pipelining, é divertido de usar se você tiver o Oracle Database 23ai. Veja meu blog Usando Pipelining para Criação Eficiente de Esquemas .
O script pode ser convertido em um único bloco anônimo PL/SQL. A vantagem dessa conversão é que ela permite que o mesmo bloco seja executado em todos os ambientes. (Embora a barra no final provavelmente deva ser excluída ao executar em Python.) A desvantagem dessa conversão é que todas as instruções DDL precisam ser convertidas em instruções EXECUTE IMMEDIATE.