La risposta più vicina che posso fornire è questa
set @cnt = 0;
set @cursum = 0;
set @cntchanged = 0;
set @uqid = 1;
set @maxsumid = 1;
set @maxsum = 0;
select
t.id,
t.name,
t.cnt
from (
select
id + 0 * if(@cnt = 30, (if(@cursum > @maxsum, (@maxsum := @cursum) + (@maxsumid := @uqid), 0)) + (@cnt := 0) + (@cursum := 0) + (@uqid := @uqid + 1), 0) id,
name,
@uqid uniq_id,
@cursum := if(@cursum + price <= 500, @cursum + price + 0 * (@cntchanged := 1) + 0 * (@cnt := @cnt + 1), @cursum + 0 * (@cntchanged := 0)) as cursum, if(@cntchanged, @cnt, 0) as cnt
from (select id, name, price from items order by rand() limit 10000) as orig
) as t
where t.cnt > 0 and t.uniq_id = @maxsumid
;
Allora come funziona? All'inizio selezioniamo 10.000 righe ordinate casualmente dagli articoli. Dopo di esso sommiamo i prezzi degli articoli fino a raggiungere 30 articoli con una somma inferiore a 500. Quando troviamo 30 articoli, ripetiamo il processo finché non esaminiamo tutti i 10.000 articoli selezionati. Durante la ricerca di questi 30 elementi, risparmiamo la somma massima trovata. Quindi alla fine selezioniamo 30 elementi con la somma maggiore (che significa il più vicino al target 500). Non sono sicuro che sia quello che volevi inizialmente, ma trovando l'esatto somma di 500 richiederebbe troppo sforzo sul lato DB.