Question

J'ai deux tables avec une relation 1: n: "contenu". et "versioned-content-data". (par exemple, une entité d'article et toutes les versions créées de cet article). Je souhaite créer une vue qui affiche la version la plus récente de chaque "contenu".

Actuellement, j'utilise cette requête (avec une sous-requête simple):

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)))

La sous-requête est en fait une requête sur la même table qui extrait la version la plus récente d'un élément spécifique. Notez que les éléments versionnés auront le même fk_idothertable.

Dans SQL Server, j'ai essayé de créer une vue indexée de cette requête, mais il semble que je ne puisse pas, car les sous-requêtes ne sont pas autorisées dans les vues indexées . Alors ... voici ma question ... Pouvez-vous trouver un moyen de convertir cette requête en une sorte de requête avec JOINs?

Il semble que les vues indexées ne puissent pas contenir:

  • sous-requêtes
  • expressions de table communes
  • tables dérivées
  • clauses HAVING

Je suis désespéré. Toutes les autres idées sont les bienvenues: -)

Merci beaucoup!

Était-ce utile?

La solution

Cela n’aidera probablement pas si la table est déjà en production, mais la bonne façon de la modéliser est de faire de version = 0 la version permanente et d’incrémenter toujours la version du matériel OLDER. Ainsi, lorsque vous insérez une nouvelle version, vous dites:

UPDATE thetable SET version = version + 1 WHERE id = :id
INSERT INTO thetable (id, version, title, ...) VALUES (:id, 0, :title, ...)

Ensuite, cette requête serait simplement

SELECT id, title, ... FROM thetable WHERE version = 0

Pas de sous-requêtes, pas d'agrégation MAX. Vous savez toujours quelle est la version actuelle. Vous ne devez jamais sélectionner max (version) pour insérer le nouvel enregistrement.

Autres conseils

Peut-être quelque chose comme ça?

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)

Juste une supposition sauvage ...

Vous pourriez peut-être faire de MAX un alias de table qui se regroupe par.

Cela pourrait ressembler à quelque chose comme ceci:

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

Je pense que FerranB était proche mais n'avait pas tout à fait le bon groupement:

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).

Je ne sais pas à quel point ce serait efficace, mais:

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

Comme ceci ... Je suppose que la "table" de la sous-requête était une table réelle différente ... alors je l'ai appelée mytable2. Si c'était la même table, alors cela fonctionnerait toujours, mais j'imagine que fk_idothertable sera simplement '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

J'espère que cela vous aidera

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top