Mais

Fechar explicitamente um objeto de resultado OGR de uma chamada para ExecuteSQL

Fechar explicitamente um objeto de resultado OGR de uma chamada para ExecuteSQL


Como posso fechar / liberar explicitamente o resultado de uma instrução ExecuteSQL ao consultar um banco de dados Spatialite com OGR via Python? Eu tenho uma consulta simples para retornar o SRID de um conjunto de dados. Isso funciona conforme o esperado. No entanto, as chamadas subsequentes parads.ExecuteSQLfalha com o erro 'Erro lógico SQL ou banco de dados ausente', a menos que eu repita as linhas de resultado.

Por exemplo:

ogr.UseExceptions () # Esta consulta retorna uma única linha sql = 'selecionar srid distinto (geometria) de foo' result = ds.ExecuteSQL (sql) row = result.next () epsg = row.GetField (0) # Esta chamada falha ds.ExecuteSQL ('drop table bar')

Concluir a iteração evita o erro:

_ = [r para r no resultado]

Isso é bom para casos simples, mas não muito explícito. Eu tentei ligarresult.Dereference (),linha = nenhum; resultado = Nenhummas isso não ajuda. O que é que estou perdendo aqui?

ATUALIZAR A exceção só é gerada quando eu habilito ogr.UseExceptions (). Caso contrário, o erro passa silenciosamente e a instrução drop table não tem efeito.


Como @fluidmotion sugeriu, o objeto da camada de resultado retornado porresultado = ds.ExecuteSQL (sql), com uma instrução select que retorna linhas, deve ser liberado chamandods.ReleaseResultSet (resultado)para destruir adequadamente o objeto. Eu esqueci isso na documentação, API e OGR_SQL.

ogr.UseExceptions () # Esta consulta retorna uma única linha sql = 'selecionar srid distinto (geometria) de foo' result = ds.ExecuteSQL (sql) row = result.next () epsg = row.GetField (0) # Destrua o conjunto de resultados ds.ReleaseResultSet (result) # Esta chamada agora deve ser bem-sucedida ds.ExecuteSQL ('drop table bar')

Experimente isso em seu procedimento armazenado:

Se, por qualquer motivo, o procedimento armazenado não retornar um conjunto de resultados, vazio ou não, o objeto do conjunto de registros não será aberto, portanto:

Você precisa criar uma conexão ativa primeiro e passá-la para o objeto do conjunto de registros, assim:

Os avisos podem confundir o resultado. SET ANSI_WARNINGS OFF evita perder o resultado do SELECT ou os valores dos parâmetros de saída.

Tenho certeza de que isso não afetará muitas pessoas, mas acabei de me deparar com esse problema. Isso funcionava na produção e não no ambiente de desenvolvimento. O que descobri foi que nosso procedimento armazenado tinha uma instrução de impressão no ambiente de desenvolvimento. Acho que a declaração de impressão estava atrapalhando as obras e o ADODB achou que era o recorde.

Eu sei que isso é muito antigo. Mas no meu caso, era a ordem dos parâmetros. Funcionou depois de definir os parâmetros conforme aparecem no procedimento armazenado. Eu sei que não há uma explicação lógica para isso, pois os parâmetros são nomeados e a ordem não deve importar muito.

Isso pode ser causado por uma instrução de impressão em seu procedimento armazenado. Eu acidentalmente deixei alguns dentro após alguma depuração de desempenho. espero que isso ajude alguém que ainda está trabalhando no ADO legado.


Supondo que as tabelas temporárias que você está referenciando existam, seu problema é o escopo da sessão. As tabelas temporárias marcadas com um único # são visíveis para a sessão em que foram criadas e também são conhecidas como tabelas temporárias locais.

O problema que você tem é que, quando você executa um fragmento de sql dinâmico, ele é executado em uma nova sessão - portanto, essa sessão não pode ver as tabelas temporárias que você criou.

Para resolver o problema, você pode fazer uma das três coisas:

  • Crie a tabela temporária dentro do seu sql dinâmico
  • Use uma tabela temporária global usando ##, pois são visíveis em todas as sessões
  • Reprojete seu código para inserir em uma variável de tabela e retornar isso como um parâmetro de saída para sp_executesql

O SQL dinâmico é executado na mesma sessão que o código de chamada. A questão não é a sessão, mas o escopo. Seu SQL dinâmico cria as tabelas temporárias dentro da chamada sp_executesql e, portanto, a tabela #temp criada só é visível em que chamada sp_executesql, conforme documentado no MSDN:

  • Uma tabela temporária local criada em um procedimento armazenado é descartada automaticamente quando o procedimento armazenado é concluído. A tabela pode ser referenciada por qualquer procedimento armazenado aninhado executado pelo procedimento armazenado que criou a tabela. A tabela não pode ser referenciada pelo processo que chamou o procedimento armazenado que criou a tabela.

  • Todas as outras tabelas temporárias locais são eliminadas automaticamente no final da sessão atual.

  • As tabelas temporárias globais são eliminadas automaticamente quando a sessão que criou a tabela termina e todas as outras tarefas param de fazer referência a elas. A associação entre uma tarefa e uma tabela é mantida apenas durante a vida de uma única instrução Transact-SQL. Isso significa que uma tabela temporária global é descartada na conclusão da última instrução Transact-SQL que fazia referência ativa à tabela quando a sessão de criação terminou.

Portanto, você precisa reter a tabela #temp em um escopo que cobre tanto a criação quanto o uso, por exemplo (também corrigiu os problemas de injeção de SQL que você teve e passou @WAGECODE como um parâmetro):

Desnecessário dizer que este é um uso bastante desnecessário de tabelas #temp, você pode simplesmente selecionar o resultado que deseja e chamá-lo um dia, não há necessidade de tabelas #temp:


Classe do cursor¶

Esta classe representa um Cursor (em termos de especificações Python DB-API) que é usado para fazer consultas no banco de dados e obter resultados. Você cria ocorrências de Cursor chamando o método cursor () em um objeto de conexão Connection aberto.

Propriedades do objeto Cusor¶

Retorna o número de linhas afetadas pela última operação. No caso de instruções SELECT, ele retorna informações significativas somente depois que todas as linhas foram buscadas.

Esta é a extensão da especificação DB-API. Retorna uma referência ao objeto de conexão no qual o cursor foi criado.

Esta é a extensão da especificação DB-API. Retorna o valor de identidade da última linha inserida. Se a operação anterior não envolver a inserção de uma linha em uma tabela com coluna de identidade, Nenhum será retornado.

Esta é a extensão da especificação DB-API. Retorna o índice atual baseado em 0 do cursor no conjunto de resultados.

Métodos de objeto Cusor¶

Feche o cursor. O cursor está inutilizável a partir deste ponto.

Cursor. execute ( Operação ) ¶ Cursor. execute ( Operação, params )

Operação é uma corda e params, se especificado, é um valor simples, uma tupla, um dicionário ou Nenhum.

Executa a operação no banco de dados, possivelmente substituindo marcadores de posição de parâmetro por valores fornecidos. Este deve ser o método preferido de criação de comandos SQL, em vez de concatenar strings manualmente, o que cria um potencial de ataques de injeção SQL. Este método aceita formatação semelhante ao operador de interpolação de string embutido do Python & # 8217s. No entanto, como a formatação e a conversão de tipo são tratadas internamente, apenas os marcadores% s e% d são suportados. Ambos os marcadores de posição são funcionalmente equivalentes.

Espaços reservados com chave são suportados se você fornecer um dict para params.

Se você chamar execute () com um argumento, o sinal% perde seu significado especial, então você pode usá-lo normalmente em sua string de consulta, por exemplo, no operador LIKE. Veja o exemplos.

Você deve chamar Connection.commit () após execute () ou seus dados não serão persistidos no banco de dados. Você também pode definir connection.autocommit se quiser que seja feito automaticamente. Este comportamento é exigido pelo DB-API, se você não gostar, apenas use o módulo _mssql.

Cursor. executemany ( Operação, params_seq ) ¶

Operação é uma corda e params_seq é uma sequência de tuplas (por exemplo, uma lista). Execute uma operação de banco de dados repetidamente para cada elemento na sequência de parâmetros.

Busca a próxima linha de um resultado de consulta, retornando uma tupla ou um dicionário se as_dict foi passado para pymssql.connect (), ou None se não houver mais dados disponíveis. Raises OperationalError ( PEP 249 # erro operacional) se a chamada anterior para executar * () não produziu nenhum conjunto de resultados ou nenhuma chamada foi emitida ainda.

Cursor. fetchmany ( tamanho = nenhum ) ¶

Busca o próximo lote de linhas de um resultado de consulta, retornando uma lista de tuplas ou uma lista de dicionários se as_dict foi passado para pymssql.connect (), ou uma lista vazia se não houver mais dados disponíveis. Você pode ajustar o tamanho do lote usando o Tamanho parâmetro, que é preservado em muitas chamadas para este método. Raises OperationalError ( PEP 249 # erro operacional) se a chamada anterior para executar * () não produziu nenhum conjunto de resultados ou nenhuma chamada foi emitida ainda.

Busca todas as linhas restantes de um resultado de consulta, retornando uma lista de tuplas ou uma lista de dicionários se as_dict foi passado para pymssql.connect (), ou uma lista vazia se não houver mais dados disponíveis. Raises OperationalError ( PEP 249 # erro operacional) se a chamada anterior para executar * () não produziu nenhum conjunto de resultados ou nenhuma chamada foi emitida ainda.

Este método faz o cursor pular para o próximo conjunto de resultados disponível, descartando todas as linhas restantes do conjunto atual. Retorna o valor True se o próximo resultado estiver disponível, Nenhum se não estiver.

Cursor. __iter__ () ¶ Cursor. Próximo ( ) ¶

Esses métodos facilitam o protocolo iterador Python. Provavelmente, você não os chamará diretamente, mas indiretamente usando iteradores.

Uma extensão pymssql para o DB-API 2.0.

Cursor. setinputsizes () ¶ Cursor. setoutputsize () ¶

Esses métodos não fazem nada, conforme permitido pelas especificações do DB-API.


Parâmetro não fornecido ao procedimento armazenado quando uso Dapper DynamicParameter do dicionário C #

Estou usando o Dapper DynamicParameters para enviar um dicionário de parâmetros do meu aplicativo .NET Core para o SQL Server, mas recebo um erro:

O parâmetro @ cityName1 não é fornecido

Mas quando rastreio a consulta, posso ver que ela está presente.

O rastreamento do criador de perfil:

La procédure or fonction 'hp_GetLinksByCities' atende ao parâmetro '@ cityName1', qui n'a pas été fourni.

O procedimento armazenado ou função 'hp_GetLinksByCities' espera um parâmetro '@ cityName1' que não foi fornecido

Quando executei este código no SSMS, recebi o mesmo erro, mas com esta sintaxe, está funcionando bem:

Normalmente, o Dapper envia o pedido dessa forma e está funcionando muito bem. Por que ele age de forma diferente desta vez?

Eu não tenho ideia do que está errado. preciso usar o DynamicParameter de maneira diferente?


Exceções¶

Raiz da hierarquia de exceção.

exceção pymssql. Aviso ¶

Gerado para avisos importantes, como truncamentos de dados durante a inserção, etc. Uma subclasse de StandardError.

Classe base de todas as outras exceções de erro. Você pode usar isso para capturar todos os erros com uma única instrução exceto. Uma subclasse de StandardError.

exceção pymssql. InterfaceError ¶

Gerado por erros relacionados à interface do banco de dados, e não ao próprio banco de dados. Uma subclasse de Error.

exceção pymssql. DatabaseError ¶

Gerado para erros relacionados ao banco de dados. Uma subclasse de Error.

exceção pymssql. Erro de dados ¶

Gerado para erros que são devidos a problemas com os dados processados, como divisão por zero, valor numérico fora do intervalo, etc. Uma subclasse de DatabaseError.

exceção pymssql. OperationalError ¶

Gerado por erros que estão relacionados à operação do banco de dados e não necessariamente sob o controle do programador, por exemplo, ocorre uma desconexão inesperada, o nome da fonte de dados não foi encontrado, uma transação não pôde ser processada, ocorreu um erro de alocação de memória durante o processamento, etc. Uma subclasse de DatabaseError.

exceção pymssql. IntegrityError ¶

Gerado quando a integridade relacional do banco de dados é afetada, por exemplo, uma verificação de chave estrangeira falha. Uma subclasse de DatabaseError.

exceção pymssql. Erro interno ¶

Gerado quando o banco de dados encontra um erro interno, por exemplo, o cursor não é mais válido, a transação está fora de sincronia, etc. Uma subclasse de DatabaseError.

exceção pymssql. ProgrammingError ¶

Gerado para erros de programação, por exemplo tabela não encontrada ou já existe, erro de sintaxe na instrução SQL, número incorreto de parâmetros especificados, etc. Uma subclasse de DatabaseError.

exceção pymssql. NotSupportedError ¶

Gerado no caso de um método ou API de banco de dados usado que não é compatível com o banco de dados, por exemplo, solicitar um rollback () em uma conexão que não oferece suporte a transações ou que as transações estão desativadas. Uma subclasse de DatabaseError.

exceção pymssql. ColumnsWithoutNamesError ¶

Gerado por Cursor.execute () quando as_dict = True foi especificado para abrir a conexão e a consulta enviada ao servidor não envolve nomes de colunas em seus resultados. Uma subclasse de InterfaceError.

ColumnsWithoutNamesError não é uma exceção obrigatória PEP-249, mas sim uma extensão pymssql.


2 respostas 2

O motivo pelo qual as instruções SQL estão sendo agrupadas com sp_executesql é a configuração da propriedade SqlCommand.Commandtype e passando quaisquer Parâmetros para o comando.

O código acima termina com este T-SQL:

Este código termina com a execução do seguinte T-SQL:

Adição 23.12.15: Usando um comando CommandType.Text, os resultados são semelhantes: Assim que um parâmetro é adicionado ao objeto de comando, o .NET agrupa toda a consulta em sp_executesql e passa os parâmetros para ela.

Adição: Depois de mergulhar mais fundo em sp_executesql, a detecção de parâmetros e o armazenamento de planos em cache, este comportamento das classes .NET faz todo o sentido para evitar a compilação de consultas frequentes e o número de planos. Portanto, ele é basicamente projetado para garantir um melhor desempenho do SQL Server em geral, enquanto ao mesmo tempo pode levar a um desempenho ruim de algumas consultas (problema de detecção de parâmetro) que são usadas com valores de parâmetro diferentes do plano de consulta criado inicialmente.

O exemplo acima foi criado usando o .NET Framework 4.5 e o SQL Server 2008 Developer Edition.

Se este for um aplicativo .NET, é muito provável que seja resultado da chamada de SqlCommand.ExecuteReader (). De acordo com a página de classe SqlCommand principal, na grade de descrições de método na seção "Comentários", em ExecuteReader diz:

Executa comandos que retornam linhas. Para aumentar o desempenho, ExecuteReader invoca comandos usando o Transact-SQL sp_executesql procedimento armazenado do sistema. Portanto, ExecuteReader pode não ter o efeito que você deseja se usado para executar comandos como instruções SET Transact-SQL.

Não tenho tempo agora para testar isso para confirmar sua descrição, mas deve ser fácil o suficiente para criar um aplicativo de console simples que faz uma chamada muito simples, passando algum texto de consulta e incluindo um parâmetro que é fornecido com um SqlParameter. Meu palpite é que ExecuteNonQuery e ExecuteScalar também usam sp_executesql, pois também permitem a passagem de parâmetros, então por que haveria um caminho diferente para como eles são executados?


2 respostas 2

Esta é a maneira padrão de fazer transações. Você pode combinar várias consultas.

O ef core pode usar a mesma conexão ou diferente ou com base no pool de conexão. O núcleo Ef conectou e desconectou o modo de transação. Eu acho que isso pode servir para você. avar dados no cenário desconectado é um pouco diferente do que no cenário conectado. No cenário desconectado, o DbContext não está ciente das entidades desconectadas porque as entidades foram adicionadas ou modificadas fora do escopo da instância DbContext atual. Portanto, você precisa anexar as entidades desconectadas a um contexto com EntityState apropriado para executar operações CUD (Criar, Atualizar, Excluir) no banco de dados.

A figura a seguir ilustra as operações CUD em cenário desconectado:

Conforme a figura acima, entidades desconectadas (entidades que não estão sendo rastreadas pelo DbContext) precisam ser anexadas ao DbContext com um EntityState apropriado. Por exemplo, estado adicionado para novas entidades, estado modificado para as entidades editadas e estado excluído para as entidades excluídas, o que resultará em um comando INSERT, UPDATE ou DELETE no banco de dados quando o método SaveChanges () for chamado.

As seguintes etapas devem ser realizadas para inserir, atualizar ou excluir registros na tabela de banco de dados usando o Entity Framework Core em cenário desconectado:

Anexe uma entidade a DbContext com um EntityState apropriado, por exemplo, Método SaveChanges () de chamada adicionada, modificada ou excluída O exemplo a seguir demonstra a inserção de um novo registro no banco de dados usando as etapas acima:

No exemplo acima, std é uma instância desconectada da entidade Aluno. O método context.Add () anexa uma entidade Aluno a um contexto com um estado Adicionado. O método SaveChanges () cria e executa a seguinte instrução INSERT:

Comportamento no EF6 e versões futuras Para EF6 e versões futuras, adotamos a abordagem de que se o código de chamada escolher abrir a conexão chamando context.Database.Connection.Open (), então ele tem um bom motivo para fazê-lo e a estrutura irá suponha que ele deseja controlar a abertura e o fechamento da conexão e não irá mais fechar a conexão automaticamente.

Isso pode levar a conexões que ficam abertas por um longo tempo, portanto, use com cuidado.


Comprometendo uma transação

Todas as instruções SQL DML são executadas no contexto de uma transação. Um aplicativo faz com que as alterações feitas por essas instruções se tornem permanentes, confirmando a transação ou desfazendo-as, executando uma reversão. Embora as instruções SQL COMMIT e ROLLBACK possam ser executadas com o método executeUpdate (), você também pode chamar os métodos Connection :: commit () e Connection :: rollback ().

Se você deseja que as alterações DML que foram feitas sejam confirmadas imediatamente, você pode ativar o modo de confirmação automática da classe Statement emitindo a seguinte instrução:

Assim que a confirmação automática estiver em vigor, cada alteração se torna automaticamente permanente. Isso é semelhante a emitir um commit logo após cada execução.

Para retornar ao modo padrão, auto commit off, emita a seguinte declaração:


A partir de pymssql 2.0.0, os procedimentos armazenados podem ser chamados usando a interface rpc do db-lib.

Você pode usar a função pymssql.set_wait_callback () para instalar uma função de retorno de chamada que você mesmo deve escrever.

Este retorno de chamada pode resultar em outro greenlet, co-rotina, etc. Por exemplo, para gevent, você pode usar sua função gevent.socket.wait_read ():

O acima é útil se você estiver executando um servidor Gunicorn com o trabalhador gevent. Com esse retorno de chamada em vigor, quando você envia uma consulta ao servidor SQL e está aguardando uma resposta, pode ceder a outros greenlets e processar outras solicitações. Isso é muito útil quando você tem alta simultaneidade e / ou consultas de banco de dados lentas e permite usar menos processos de trabalho do Gunicorn e ainda lidar com alta simultaneidade.