Aqui está meu comando para o banco de dados GRASS GIS (driver SQL Lite usado):
db.execute sql="UPDATE streams_order SET factor=next_stream WHERE number IS NOT NULL AND next_stream IN (SELECT number FROM streams_order)"
Mas eu quero
db.execute sql="UPDATE streams_order SET factor=next_stream WHERE number IS NOT NULL AND next_stream NOT IN (SELECT number FROM streams_order)"
E o resultado deve ser:
+---------+--------------+--------+---------+
| stream | next_stream factor | number |
+-------------------------------------------+
370 -1
372 370 370 372
374 440
376 372 376
380 374 374 380
.............................................
não funciona sem nenhum erro: a coluna "fator" fica vazia após executar o comando. Se eu colocar IN, funciona bem. Os tipos de coluna são todos INT.
Sandbox com dados reais está aqui https://dbfiddle.uk/zg8_xJUz
Se algo não for suportado, você enfrentará algum erro, como na pergunta anterior DBMI-SQLite driver error: Error in sqlite3_prepare(): near ".": sintaxe error in db.execute command .
Para depurar o problema antes de executar a instrução update, execute um select.
Se eu executar a mesma consulta de atualização transformada na instrução select, você verá que nenhum registro será retornado.
Agora o problema está na consulta.
Eu sugeriria usar
not exists
em vez denot in
, consulte SQL "selecionar onde não está na subconsulta" não retorna resultados para as diferenças entre existe e entra.Altere sua consulta selecionada para,
Resultado,
Consulta de atualização,
Veja exemplo aqui
Seu problema está relacionado à presença de valores NULL na
number
coluna.NOT IN sempre falha quando a lista tem valores NULL porque as comparações NULL não podem ser verdadeiras ou falsas.
Mais precisamente, na lógica SQL NULL não significa "vazio", significa "indeterminado". Uma comparação
val = NULL
sempre resultará em NULL, mesmo que val também seja NULL. É por isso que, para verificar se algo é NULL, precisamos usar o operador especialIS NULL
.A expressão
val IN ('A', NULL)
será traduzida comoval='A' OR val=NULL
.Se val for igual a 'A', isso se tornará
TRUE OR NULL
, que é avaliado comoTRUE
. (e NOT IN é avaliado comoFALSE
). Mas se val for igual a 'B' essa expressão se tornaFALSE OR NULL
, que é avaliada comoNULL
(e NOT IN ainda éNULL
).Portanto, em uma lista com elementos nulos,
val IN (...)
será avaliado como TRUE se um dos elementos não nulos for igual a val, e NULL caso contrário, enquantoval NOT IN (...)
será avaliado como FALSE se um dos elementos não nulos for igual a val e NULL caso contrário, mas será nunca é avaliado como TRUE, portanto sua atualização nunca será acionada.Veja também esta questão .
Gambiarra: