Как мне избежать повторения этого подзапроса в предложении?


У меня есть 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 2

4 ответа:

В стандартном SQL есть предложение WITH, однако я не знаю, поддерживается ли оно 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;

Вы можете поместить выбранную деталь в вид, чем вы можете отфильтровать результаты просмотра, используя псевдоним " sq "

Надеюсь, это поможет

В целом я ставлю под сомнение необходимость устранения дублирования. Компилятор SQL может видеть, что два подзапроса идентичны, и решил выполнить их только один раз, если это кажется оптимальным.

Кроме того, оставляя дубликаты в исходном коде, компилятор и оптимизатор SQL получают возможность обрабатывать их по-разному. Например, оптимизация выравнивания подзапроса SQLite может быть применена к одному из пары дубликатов или применена по-разному к каждому из них. См. раздел 9.0, подзапрос сплющивание https://www.sqlite.org/optoverview.html .