Eu tinha escrito esse código acidentalmente
SELECT COUNT(*) "Table0" WHERE "Column0" = ? LIMIT 1;
Quando eu quis escrever este código:
SELECT COUNT(*) FROM "Table0" WHERE "Column0" = ? LIMIT 1;
Fiquei realmente surpreso que a primeira linha compilou sem dar nenhum tipo de erro. Eu verifiquei a sintaxe nos documentos do SQLite, e não parece que isso deveria compilar, mas compila. O que está acontecendo aqui? Como isso está sendo interpretado pelo SQLite?
A linha incorreta sempre retorna 0, mesmo que haja uma correspondência na tabela.
Também é interessante que o LibSQL realmente falha, mas com uma mensagem sobre "Column0" não existir... talvez isso faça mais sentido quando entendermos como isso está sendo interpretado...
A
AS
palavra-chave é opcional ao especificar um alias, entãoSELECT COUNT(*) "Table0"
significa o mesmo queSELECT COUNT(*) AS "Table0"
.A tabela padrão quando você não especifica a
FROM
tem uma linha e nenhuma coluna. Uma maneira mais típica de usá-la é com expressões comoSELECT 1 + 1
orSELECT EXISTS (…)
.Como não é um nome resolvível,
"Column0"
é tratado como uma string devido a um recurso de compatibilidade do MySQL que está sendo gradualmente removido do SQLite; seu LibSQL foi aparentemente configurado com essa opção desabilitada, ou talvez tenha sido completamente removido do fork. (Você pode confirmar isso passando'Column0'
como valor de parâmetro e vendo o resultado ir de 0 a 1.)Acho que foi isso que aconteceu na sua primeira consulta:
SELECT COUNT(*) "Table0" WHERE "Column0" = ? LIMIT 1;
A mágica aconteceu aqui
SELECT COUNT(*) "Table0"
, quando você não escreveuFROM
, o SQL tomouTable0
como alias para aCount(*)
consulta e começou a operar em uma tabela vazia implícita sem linhas, então não importa quantos registros correspondentes você tenha na tabela, ele sempre retornará 0 linhas devido àFROM
frase ausente.Chegando à segunda parte da consulta
WHERE "Column0" = ?
, como não há menção àFROM
cláusula, elaColumn0
também é tratada como uma expressão (no backend o SQLite pensa que é um alias ou nome de coluna que você pode usar)Boa pergunta, gostei da curiosidade por trás dela! :)
O problema está em como o SQLite interpreta sua consulta quando você acidentalmente omite a cláusula FROM . No SQLite, a sintaxe é permissiva o suficiente para permitir construções que parecem inválidas, mas são tecnicamente aceitáveis na gramática SQL. O que está acontecendo é:
Nesta consulta:
COUNT(*) "Tabela0":
O SQLite interpreta "Table0" como um alias para o resultado de COUNT(*) . Isso significa que a consulta está selecionando a contagem de todas as linhas em um conjunto de resultados virtual e nomeando a coluna de resultado como "Table0". WHERE "Column0" = ?:
Como não há cláusula FROM , a consulta opera em uma tabela fictícia de linha única fornecida pelo SQLite. Essa tabela não contém colunas reais, mas o SQLite permite que você escreva expressões como "Column0" = ? mesmo que "Column0" não exista. O SQLite avalia essa condição como falsa (ou, mais precisamente, avalia como falsa para todas as linhas da tabela fictícia). LIMITE 1.
LibSQL , um derivado do SQLite, parece ser mais rigoroso em impor que nomes de colunas na cláusula WHERE devem existir nas tabelas consultadas. Como "Column0" não existe na tabela fictícia implícita (ou em qualquer tabela devido à falta de uma cláusula FROM), isso gera um erro.
Acho que isso ajudará você a entender o que realmente acontece.