Wie eine SQL-Unterabfrage in einen konvertieren beitreten
-
03-07-2019 - |
Frage
Ich habe zwei Tabellen mit einem 1: n-Beziehung: „Inhalt“ und „versioniert-Inhaltsdaten“ (zum Beispiel einer Artikel Einheit und alle Versionen dieses Artikels erstellt wird). Ich möchte eine Ansicht erstellen, die die Top-Version jedes „Inhalt“ angezeigt wird.
Zur Zeit verwende ich diese Abfrage (mit einer einfachen Unterabfrage):
SELECT t1.id, t1.title, t1.contenttext, t1.fk_idothertable t1.version FROM mytable as t1 WHERE (version = (SELECT MAX(version) AS topversion FROM mytable WHERE (fk_idothertable = t1.fk_idothertable)))
Die Unterabfrage ist eigentlich eine Abfrage an die gleiche Tabelle, die die höchste Version eines bestimmten Elements extrahiert. Beachten Sie, dass der versioniert Artikel die gleichen fk_idothertable hat.
In SQL Server Ich habe versucht, eine indizierte Sicht dieser Abfrage zu erstellen, aber es scheint, dass ich nicht in der Lage bin, da Unterabfragen sind in indizierte Sichten nicht erlaubt . So ... hier ist meine Frage ... Können Sie einen Weg finden, diese Abfrage eine Art von Abfrage zu konvertieren mit JOIN?
Es scheint, wie indizierte Sichten können nicht enthalten:
- Unterabfragen
- allgemeine Tabellenausdrücke
- abgeleitete Tabellen
- HAVING-Klauseln
Ich bin verzweifelt. Jede andere Ideen sind willkommen: -)
Vielen Dank!
Lösung
Dies wird wahrscheinlich nicht helfen, wenn die Tabelle bereits in der Produktion ist, aber der richtige Weg, dies zu modellieren ist auf Version = 0 die permanente Version zu machen und immer die Version von älterem Material zu erhöhen. Also, wenn Sie eine neue Version einsetzen würden Sie sagen:
UPDATE thetable SET version = version + 1 WHERE id = :id
INSERT INTO thetable (id, version, title, ...) VALUES (:id, 0, :title, ...)
Dann würde diese Abfrage nur sein
SELECT id, title, ... FROM thetable WHERE version = 0
Keine Unterabfragen, keine MAX-Aggregation. Sie wissen immer, was die aktuelle Version ist. Sie müssen sich nie wählen max (Version), um den neuen Datensatz einzufügen.
Andere Tipps
Vielleicht so etwas wie das?
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)
Nur eine wilde Vermutung ...
Sie könnten in der Lage sein, die MAX eine Tabelle alias zu machen, die Gruppe hat durch.
Es könnte wie folgt aussehen:
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
Ich denke, FerranB Nähe war, aber hatte nicht ganz die Gruppierung rechts:
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
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).
Ich weiß nicht, wie effizient dies sei, aber:
SELECT t1.*, t2.version FROM mytable AS t1 JOIN ( SElECT mytable.fk_idothertable, MAX(mytable.version) AS version FROM mytable ) t2 ON t1.fk_idothertable = t2.fk_idothertable
So ... Ich gehe davon aus, dass das ‚mytable‘ in der Unterabfrage war eine andere aktuelle Tabelle ... so rief ich es mytable2. Wenn es der gleiche Tisch ist, dann wird dies immer noch funktionieren, aber dann denke ich, dass fk_idothertable wird nur ‚id‘ sein.
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
Hope, das hilft