Мне просто интересно, сталкивался ли кто-нибудь с делом в 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 и обойти это.