2008-11-13 20 views
6

Estoy buscando una manera de seleccionar hasta que se llegue a una suma.SQL: Seleccione "hasta"

Mi tabla de "documentos" tiene campos "tag_id" y "size".

Quiero seleccionar todos los documentos con tag_id = 26 pero sé que solo puedo manejar 600 unidades de tamaño. Por lo tanto, no tiene sentido seleccionar 100 documentos y descartar 90 de ellos cuando podría haber sabido que los primeros 10 ya sumaron hasta> 600 unidades.

Por lo tanto, el objetivo es: no traer de vuelta una tonelada de datos para analizar cuando voy a descartar la mayor parte.

... pero también me gustaría evitar introducir el uso de cursores en esta aplicación.

Estoy usando mysql.

+0

¿MySQL tiene funciones analíticas? –

+0

Dado que habría muchas combinaciones de documentos que se suman a> 600, ¿cómo sabe qué documentos desea usar? ¿O no importa? – Kev

+0

Se da preferencia a los documentos añadidos más recientemente (hay un campo date_created que pediremos desc en) – jhalb

Respuesta

7

Necesita ordenar de alguna manera los registros que tienen prioridad sobre los demás al sumar sus unidades máximas. De lo contrario, ¿cómo sabe qué conjunto de registros contiene un total de hasta 600?

SELECT d.id, d.size, d.date_created 
FROM documents d 
INNER JOIN documents d2 ON d2.tag_id=d.tag_id AND d2.date_created >= d.date_created 
WHERE d.tag_id=26 
GROUP BY d.id, d.size, d.date_created 
HAVING sum(d2.size) <= 600 
ORDER BY d.date_created DESC 

Esto es sólo una consulta básica para empezar, y hay una serie de problemas todavía para resolver:

  • Se detiene en < = 600, por lo que en la mayoría de los casos no será llene su límite de tamaño exactamente. Esto significa que es posible que desee modificarlo para permitir un registro más. Por ejemplo, si el primer registro es> 600, la consulta no devolverá nada, y eso podría ser un problema.
  • No hará nada para comprobar si hay registros más pequeños adicionales más adelante que aún podrían caber debajo del límite.
  • Los registros con valores date_created idénticos podrían ser "contados doblemente" aquí y allá.

edición
actualizado desde agregó la información que ha de clasificación por fecha.

+0

Estaba empezando a publicar algo muy similar, aunque usando una vista auxiliar. La suya es mejor. –

+0

Eso es más inteligente que mi respuesta también. :) – Kev

0

Esto es mucho menos eficiente, pero sí evitar un cursor (asumiendo que su mesa de documentos también tiene una columna de ID de serie):

select a.id, (select sum(b.size) from documents b where b.id <= a.id and b.tag_id = 26) 
from documents a 
where a.tag_id = 26 
order by a.id 

Además, esto se hizo en pgsql, así que no estoy seguro si esta sintaxis exacta funcionaría en mysql.

Luego puede ajustar esto en otra consulta que busque aquellos que tienen una suma> 600 (tendrá que nombrar la columna de suma) y tomar la primera identificación. Luego procesa todos los ID a continuación e incluye ese.

+0

Er, si no hay una identificación, entonces use la marca de tiempo creada. – Kev

0

Primero debe almacenar los documentos en una variable de tabla, ordenarlos en el orden en que desea recuperarlos, luego actualizar cada fila con un valor acumulativo para que pueda seleccionar en ella.

declare @documents_temp table (
    tag_id int, 
    size int, 
    cumulative_size int null) 

insert into @documents_temp 
select tag_id, size, size from documents order by tag_id 

update @documents_temp d set d.cumulative_size = d.size + 
    (select top 1 cumulative_size from @documents_temp 
    where tag_id < d.tag_id order by tag_id desc) 

select tag_id, size from @documents_temp where cumulative_size <= 600 

No sé si vale la pena.

Cuestiones relacionadas