Как избежать повторения этого подзапроса для предложения IN?
У меня есть сценарий SQL (в настоящее время работает на SQLite, но, вероятно, он должен работать на любом механизме БД), который использует один и тот же подзапрос дважды, и, поскольку он может извлекать много записей (таблица содержит пару миллионов строк), я ' Я хотел бы позвонить только один раз.
Сокращенная псевдо-версия запроса выглядит так:
SELECT * FROM
([the subquery, returns a column of ids]) AS sq
[a couple of joins, that fetches things from other tables based on the ids]
WHERE thisorthat NOT IN ([the subquery again])
Я пытался просто использовать имя (sq
) различными способами (с / без круглых скобок, с / без именования столбца sq и т. д.), но безрезультатно.
Я действительно должен повторить этот подзапрос?
Пояснение: я делаю это на python и sqlite в качестве небольшой демонстрации того, что можно сделать, но я бы хотел, чтобы мое решение масштабировалось как можно лучше с минимальными изменениями, насколько это возможно. В реальной ситуации в базе данных будет несколько миллионов строк, но в моем примере всего 10 строк с фиктивными данными. Таким образом, код, который будет хорошо оптимизирован, например, для MySQL, достаточно хорош - его не нужно оптимизировать специально для SQLite. Но, как я уже сказал, чем меньше нужно модификаций, тем лучше.
4 ответа
E сть WITH
предложение в стандартном SQL, однако, я не знаю, поддерживается ли он SQLlite - хотя, конечно, стоит попробовать:
WITH mySubQuery AS
(
[the subquery code]
)
SELECT * FROM
mySubQuery AS sq
[a couple of joins, that fetches things from other tables based on the ids]
WHERE thisorthat NOT IN (mySubQuery)
Тем не менее, то, что вы здесь делаете, скорее всего, будет ужасно медленным для любого набора данных, который содержит более нескольких тысяч строк, поэтому я постараюсь изменить его, если это возможно - NOT IN
в целом следует избегать, особенно если у вас есть пара соединений.
Вам нужен подзапрос? Вы могли бы, вероятно, переписать с помощью OUTER JOIN
например что-то вроде:
SELECT *
FROM [the subquery's FROM clause] AS sq
RIGHT OUTER JOIN [a couple of tables based on the ids]
ON thisorthat = sq.[a column of ids]
WHERE sq.[a column of ids] IS NULL;
В общем, я подвергаю сомнению необходимость устранения дублирования. Компилятор SQL видит, что два подзапроса идентичны, и решил сделать их только один раз, если это кажется оптимальным.
Кроме того, оставляя дубликаты в источнике, компилятору и оптимизатору SQL предоставляется возможность обрабатывать их по-разному. Например, оптимизация выравнивания подзапроса SQLite может применяться к одному из пары дубликатов или применяться по-разному к каждому. Смотрите раздел 9.0, Сглаживание подзапроса https://www.sqlite.org/optoverview.html.
Вы можете поместить часть SELECT в View, а затем отфильтровать результаты View, используя псевдоним "sq".
Я надеюсь, что это полезно