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