Как избежать повторения этого подзапроса для предложения 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".

Я надеюсь, что это полезно

Другие вопросы по тегам