Как преобразовать подзапрос SQL в соединение
У меня есть две таблицы с отношением 1: n: «content» и «versioned-content-data» (например, сущность статьи и все версии, созданные для этой статьи). Я хотел бы создать представление, которое отображает верхнюю версию каждого «контента».
В настоящее время я использую этот запрос (с простым подзапросом):
ВЫБРАТЬ t1.id, t1.title, t1.contenttext, t1.fk_idothertable t1.version ИЗ mytable как t1 ГДЕ (версия = (ВЫБРАТЬ МАКС. (Версия) как версия) ИЗ mytable ГДЕ (fk_idothertable = t1.fk_idothertable)))
Подзапрос на самом деле является запросом к той же таблице, которая извлекает самую высокую версию определенного элемента. Обратите внимание, что элементы с версией будут иметь одну и ту же таблицу fk_idothertable.
В SQL Server я попытался создать индексированное представление этого запроса, но, похоже, я не смог, поскольку подзапросы не разрешены в индексированных представлениях . Итак ... вот мой вопрос ... Можете ли вы придумать способ преобразовать этот запрос в какой-то запрос с помощью JOIN?
Похоже, что индексированные представления не могут содержать:
- подзапросы
- общие табличные выражения
- производные таблицы
- HAVING пункты
Я в отчаянии. Любые другие идеи приветствуются :-)
Большое спасибо!
Ответов (7)7
Это, вероятно, не поможет, если таблица уже находится в производстве, но правильный способ смоделировать это - сделать версию = 0 постоянной версией и всегда увеличивать версию материала OLDER. Поэтому, когда вы вставляете новую версию, вы говорите:
UPDATE thetable SET version = version + 1 WHERE id = :id
INSERT INTO thetable (id, version, title, ...) VALUES (:id, 0, :title, ...)
Тогда этот запрос будет просто
SELECT id, title, ... FROM thetable WHERE version = 0
Никаких подзапросов, никакой агрегации MAX. Вы всегда знаете, какая сейчас версия. Вам никогда не нужно выбирать max (версию), чтобы вставить новую запись.
If SQL Server accepts LIMIT clause, I think the following should work:
SELECT
t1.id,
t1.title,
t1.contenttext,
t1.fk_idothertable
t1.version
FROM mytable as t1 ordery by t1.version DESC LIMIT 1;
(DESC - For descending sort; LIMIT 1 chooses only the first row and
DBMS usually does good optimization on seeing LIMIT).
Вот так ... Я предполагаю, что mytable в подзапросе была другой реальной таблицей ... поэтому я назвал ее mytable2. Если бы это была та же таблица, это все равно будет работать, но тогда я полагаю, что fk_idothertable будет просто id.
SELECT
t1.id,
t1.title,
t1.contenttext,
t1.fk_idothertable
t1.version
FROM mytable as t1
INNER JOIN (SELECT MAX(Version) AS topversion,fk_idothertable FROM mytable2 GROUP BY fk_idothertable) t2
ON t1.id = t2.fk_idothertable AND t1.version = t2.topversion
Надеюсь это поможет
Возможно, вы сможете сделать MAX псевдонимом таблицы, который группируется.
Это может выглядеть примерно так:
SELECT
t1.id,
t1.title,
t1.contenttext,
t1.fk_idothertable
t1.version
FROM mytable as t1 JOIN
(SELECT fk_idothertable, MAX(version) AS topversion
FROM mytable
GROUP BY fk_idothertable) as t2
ON t1.version = t2.topversion
Я думаю, что FerranB был близок, но не совсем правильно сгруппировал:
with
latest_versions as (
select
max(version) as latest_version,
fk_idothertable
from
mytable
group by
fk_idothertable
)
select
t1.id,
t1.title,
t1.contenttext,
t1.fk_idothertable,
t1.version
from
mytable as t1
join latest_versions on (t1.version = latest_versions.latest_version
and t1.fk_idothertable = latest_versions.fk_idothertable);
M