Pregunta

Tengo dos tablas con una relación 1: n: " contenido " y " datos de contenido versionados " (por ejemplo, una entidad de artículo y todas las versiones creadas de ese artículo). Me gustaría crear una vista que muestre la versión superior de cada " contenido " ;.

Actualmente utilizo esta consulta (con una subconsulta 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 subconsulta es en realidad una consulta a la misma tabla que extrae la versión más alta de un elemento específico. Tenga en cuenta que los elementos versionados tendrán el mismo fk_idothertable.

En SQL Server traté de crear una vista indizada de esta consulta, pero parece que no puedo, ya que las subconsultas no están permitidas en vistas indizadas . Entonces ... aquí está mi pregunta ... ¿Puedes pensar en una forma de convertir esta consulta en algún tipo de consulta con JOINs?

Parece que las vistas indizadas no pueden contener:

  • subconsultas
  • expresiones de tabla comunes
  • tablas derivadas
  • CLAVES QUE TIENEN

Estoy desesperado. Cualquier otra idea es bienvenida :-)

¡Muchas gracias!

¿Fue útil?

Solución

Esto probablemente no ayudará si la tabla ya está en producción, pero la forma correcta de modelar esto es hacer que la versión = 0 sea la versión permanente y siempre incrementar la versión del material OLDER. Entonces, cuando insertas una nueva versión, dirías:

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

Entonces esta consulta simplemente sería

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

No hay subconsultas, no hay agregación MAX. Siempre sabes cuál es la versión actual. Nunca tiene que seleccionar max (versión) para insertar el nuevo registro.

Otros consejos

¿Quizás algo como esto?

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)

Sólo una suposición salvaje ...

Es posible que puedas hacer de MAX un alias de tabla que se agrupe por.

Podría verse algo como esto:

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

Creo que FerranB estaba cerca pero no tenía el derecho de agrupación:

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

No sé cuán eficiente sería esto, pero:

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

De esta manera ... Supongo que el 'mytable' en la subconsulta era una tabla real diferente ... así que lo llamé mytable2. Si fuera la misma tabla, esto seguirá funcionando, pero luego imagino que fk_idothertable simplemente será '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

Espero que esto ayude

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top