2008-12-29 11 views
8

Es muy posible que una pregunta como esta se haya hecho antes, pero no puedo pensar en los términos para buscar.SQL Seleccionando "Ventana" alrededor de la Fila Particular

Estoy trabajando en una aplicación de galería de fotos y quiero mostrar 9 miniaturas que muestran el contexto de la foto actual (en una cuadrícula de 3x3 con la foto actual en el centro, a menos que la foto actual esté en la primera Se muestran 4 fotos, en cuyo caso si, por ejemplo, si la foto actual es la 2ª, quiero seleccionar las fotos 1 a 9). Por ejemplo, dado un álbum que contiene la lista de fotos con ids:

1, 5, 9, 12, 13, 18, 19, 20, 21, 22, 23, 25, 26

Si la corriente foto es 19, quiero ver también:

9, 12, 13, 18, 19, 20, 21, 22, 23

Si la fotografía actual es 5, I desea ver también:

1, 5, 9, 12, 13, 18, 19, 20, 21

He estado pensando en algo en la línea de:

SELECT * 
FROM photos 
WHERE ABS(id - currentphoto) < 5 
ORDER BY id ASC 
LIMIT 25 

pero esto no funciona en el caso en que los identificadores son no secuencial (como en el ejemplo anterior), o para el caso en que hay son fotos insuficientes antes de la foto actual.

¿Alguna idea?

Gracias,

Dom

P. S. Por favor, deje un comentario si algo no está claro, y aclararé la pregunta. Si alguien puede pensar en un título más útil para ayudar a otras personas a encontrar esta pregunta en el futuro, por favor coménteselo también.

Respuesta

5

Probablemente sólo podría utilizar un UNION y, a continuación, recorte los resultados adicionales en el código de procedimiento que muestra los resultados (como esto devolverá 20 filas en los casos que no son de última generación):

(SELECT 
    * 
FROM photos 
    WHERE ID < #current_id# 
    ORDER BY ID DESC LIMIT 10) 
UNION 
    (SELECT * 
    FROM photos 
    WHERE ID >= #current_id# 
    ORDER BY ID ASC LIMIT 10) 
ORDER BY ID ASC 

EDIT: Aumento de límite a 10 en ambos lados de la unión, como se sugiere por le dorfier.

EDIT 2: Modificado para reflejar mejor la implementación final, como lo sugiere Dominic.

+1

Esta es una técnica buena y útil. Lo he usado con MySQL en el pasado. Para manejar los extremos de la lista, donde no tendría suficientes filas: use el LÍMITE 10 y resuelva la selección en el código de procedimiento. – dkretz

+0

Gracias le dorfier, que resuelve el problema con los límites, lo editaré según lo sugerido. – Turnkey

+0

Terminé haciendo algo muy similar a esto. Agregué un "ORDER BY id ASC" en el resultado de la UNIÓN, por lo que las filas volvieron como estaba previsto. Deberá cambiar la primera ORDEN por ID DESC, de lo contrario, las primeras filas siempre volverán. –

0

Este es un problema estándar de "orden de filas" ... Si su base de datos tiene capacidad rowId, puede usarla; de lo contrario, necesita una subconsulta que cuente el numnber de filas con Id. Menor que la id de la fila actual ... de esta manera:

- asssuming @Id es valor de id en el "medio"

Select * From Photos P 
Where (Select Count(*) From Photos 
     Where id <= P.Id) 
    Between (Select Count(*) From Photos 
       Where id < @Id) - 4 
     And (Select Count(*) From Photos 
       Where id < @Id) + 4 

como comentario planteó la cuestión álbum que desee agregar álbum predicado a cada subconsulta

Select * From Photos P 
    Where (Select Count(*) From Photos 
      Where album = @album 
      And id <= P.Id) 
    Between (Select Case When Count(*) < 4 
         Then 4 Else Count(*) End 
       From Photos 
       Where album = @album 
       And id < @Id) - 4 
     And (Select Case When Count(*) < 4 
         Then 4 Else Count(*) End 
       From Photos 
       Where album = @album 
        And id < @Id) + 4 
+0

Debe haber filtro adicional por álbum, de lo contrario no resuelve el problema, es decir, solo funcionará en la identificación secuencial. –

1

Si está utilizando SQL Server, puede utilizar la función row_number() para darle el índice de orden de las filas y hacer algo como esto:

declare @selected_photo integer; 
set @selected_photo = 5; 

declare @buffer_size integer; 
set @buffer_size = 2; 

select 
    ph.rownum, 
    ph.id 
from 
    (select row_number() over (order by Id) as rownum, * from Photos) as ph 
where 
    ph.rownum between case 
         when @selected_photo - @buffer_size < 1 then 1 
         else @selected_photo - @buffer_size 
         end 
         and @selected_photo + @buffer_size 

Editar: Aquí es un artículo sobre la simulación de la row_number() Función en MySQL, combinando eso con , esto podría darte lo que necesitas; lo probaría pero no tengo un MySQL disponible para jugar en el trabajo.:-)

http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/

+0

Gracias Ron, pero estoy usando MySQL, así que no creo que pueda usar esto, ¿o sí? –

+0

No veo nada similar en los documentos de MySQL ... pero seguiré hurgando. :-) –

+0

@RonSavage: no te molestes. MySQL es uno de los pocos DBMS que quedan que no admiten funciones de ventana. –

Cuestiones relacionadas