我只是想知道是否有人遇到SQLite(3.7.4)中的一个案例,其中查询将返回一组结果,当它成为子查询时,结果完全不同?我在一个更复杂的查询中发现了这个问题,但这里有一个更简单的例子来演示相同的行为:
数据库设置:
CREATE TABLE "test" ("letter" VARCHAR(1) PRIMARY KEY, "number" INTEGER NOT NULL);
INSERT INTO "test" ("letter", "number") VALUES('b', 1);
INSERT INTO "test" ("letter", "number") VALUES('a', 2);
INSERT INTO "test" ("letter", "number") VALUES('c', 2);
初始查询:
SELECT "letter", "number" FROM "test" ORDER BY "letter", "number" LIMIT 1;
这将返回a|2
,结果中的第二行正如您所期望的那样,因为我们正在对字母进行排序,然后是数字。但是,这是我没想到的:
初始查询作为子查询:
SELECT DISTINCT "number" FROM (SELECT "letter", "number" FROM "test" ORDER BY "letter", "number" LIMIT 1) AS "test";
这会返回1
,这完全不符合我的预期。我期望看到的是2
。我对子查询如何工作的理解是,它应该返回相同的结果,好像内部查询已实现,并且外部查询应用于这些结果(即使我意识到数据库达到了极长的程度)在必要之前不要实现结果。
我的假设不正确吗?我在PostgreSQL和MySQL中测试了相同的查询,它按预期工作(即返回2
)。对我来说,我看到的是SQLite崩溃子查询的错误,但我不确定。
重申一下,上面的例子简化了我实际做的事情。我不只是在返回单行的子查询上使用DISTINCT,而是返回许多行,其中一些行具有相同的值,因此我需要DISTINCT。以上示例是我能想到的最简单的方法来演示正在发生的事情。
编辑:我可以通过向内部查询添加OFFSET 0
来禁用不正确的子查询折叠,例如:
SELECT DISTINCT "number" FROM (SELECT "letter", "number" FROM "test" ORDER BY "letter", "number" LIMIT 1 OFFSET 0) AS "test";
我将通过SQLite邮件列表将此报告为错误,这是一种解决方法。
答案 0 :(得分:1)
我可以验证它是否也适用于Firefox的SQLite插件。
如果有任何安慰,这个表格有效:
SELECT DISTINCT "number" FROM (SELECT "letter", "number" FROM "test"
ORDER BY "letter", "number") AS "test" ORDER BY "letter" LIMIT 1;
我相信SQLite规范会忽略内部查询中的LIMIT子句并将其迁移到外部。没有限制:
SELECT DISTINCT "number" FROM (SELECT "letter", "number" FROM "test"
ORDER BY "letter", "number") AS "test";
返回
1
2
(2 rows)
有趣的是,这也会返回正确的结果
SELECT number FROM (SELECT letter, number FROM test
ORDER BY letter, number LIMIT 1) AS test;
可以使用EXPLAIN比较这两个计划 DESCRIBE正在添加大量操作,内嵌和优化内部查询(错误地)。