Как преобразовать подзапрос 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)

Решение

Это, вероятно, не поможет, если таблица уже находится в производстве, но правильный способ смоделировать это - сделать версию = 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 (версию), чтобы вставить новую запись.

Может как то так?

SELECT
  t2.id,
  t2.title,
  t2.contenttext,
  t2.fk_idothertable,
  t2.version
FROM mytable t1, mytable t2
WHERE t1.fk_idothertable == t2.fk_idothertable
GROUP BY t2.fk_idothertable, t2.version
HAVING t2.version=MAX(t1.version)

Просто дикая догадка ...

Не знаю, насколько это будет эффективно, но:

ВЫБЕРИТЕ t1. *, T2.version
ИЗ mytable AS t1
    ПРИСОЕДИНИТЬСЯ (
        ВЫБЕРИТЕ mytable.fk_idothertable, MAX (mytable.version) версию AS
        ИЗ mytable
    ) t2 ВКЛ t1.fk_idothertable = t2.fk_idothertable
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