Prosim za pomoč pri sestavi querija (mysql)

Imam na primer spodnjo tabelo

id cena kolicina datum
1 100 0.01 2017-11-19 23:07:19
2 70 0.4 2017-11-19 15:07:19
3 25 6 2017-11-19 01:07:19
4 98 0.1 20 2017-11-19 23:07:19

Želel bi izpisati vnose katerih skupna količina je recimo manjša od neke vrednosti. Vnosi so recimo razvrščeni po datumu in ceni.

Torej...

SELECT * FROM tabela ORDER BY datum DESC cena ASC

izpiše
id cena kolicina datum
1 98 0.1 20 2017-11-19 23:07:19
2 100 0.01 2017-11-19 23:07:19
3 70 0.4 2017-11-19 15:07:19
4 25 6 2017-11-19 01:07:19

In sedaj bi rad iz te tabele dobil podatke kjer je skupna količina manjša od recimo 0.3, torej da bi se v tem primeru izpisalo...
1 98 0.1 20 2017-11-19 23:07:19
2 100 0.01 2017-11-19 23:07:19
(ker je 0.1+0.01 < 0.3, 3. vrstica pa že več ne ustreza pogoju, ker 0.1+0.01+0.4 ni manj kot 0.3)

Ima kdo idejo, kako bi to naredil? Pa če se da brez gnezdenih poizvedb (to rešitev že imam in jo ne mislim uporabiti, ker je potencialno zelo potratna)

5 odgovorov

Em ... ne štekam ravno, dobiš količine kjer je količina nižja od 0.3, kaj bi rad grupiral po datumu pa seštel količine?

SELECT * FROM tabela WHERE kolicina < 0.3 ORDER BY datum DESC cena ASC

Primer?

SELECT *, SUM(kolicina) as sumkolicina FROM tabela GROUP BY DATE(datum) HAVING sumkolicina < 0.3

Dvomim, da obstaja enostavna SQL-only rešitev (brez zanke in subqueryev).
Sicer pa je zelo trivialna rešitev, da sortiraš po količini naraščajoče in v zanki seštevaš količino, dokler ne dosežeš ciljne. Tam narediš break in imaš željeni seznam.

1

Lahko poskusiš z user variables, nekaj v stilu:

@sum = 0;
SELECT * FROM tabela WHERE (@sum:=@sum+kolicina) < 0.3;

Ne vidim pa uporabnosti te rešitve za karkoli, imam občutek, da nekaj delaš narobe. Kaj točno bi rad dosegel?

Plus zgornja rešitev ni prav blazno optimizirana. Če imaš veliko recordov, lahko to tudi traja, ker bo query naredil sequential scan.

1

Aha, ne, štekam zdaj, potrebuješ recorde po posameznih datumih, potem tale moja rešitev ne bo v redu.

Subquery bi bil rešitev, ne vem zakaj se ga otepaš. Moraš pa seveda poskrbeti za pravilno indeksiranje.

1

Vini:
Aha, ne, štekam zdaj, potrebuješ recorde po posameznih datumih, potem tale moja rešitev ne bo v redu.

Subquery bi bil rešitev, ne vem zakaj se ga otepaš. Moraš pa seveda poskrbeti za pravilno indeksiranje.

Se opravičujem, sem se zmotil pri razvrčanju. Najprej se razvrsti po ceni, šele nato po datumu.
Bom poskusil vse še enkrat opisati, ker sem včeraj pisal pozno, pa mogoče ni bilo vse skupaj najbolj jasno.
Torej za osnovo imam tabelo, ki je prikazana v 1. sporočilu, da ne bo dvoma, jo kopiram še enkrat.

id cena kolicina datum
1 100 0.01 2017-11-19 23:07:19
2 70 0.4 2017-11-19 15:07:19
3 25 6 2017-11-19 01:07:19
4 98 0.1 20 2017-11-19 23:07:19

Želim ustvaril poizvedbo, ki bi po datumu in ceni razvrčenem seznamu (ORDER BY cena DESC, datum ASC) ob od uporabnika določenem pogoju o max. skupni zahtevani količini* (WHERE -?-), vrnila seznam ustreznih vrstic.
*vsota količin se sešteva tako kot sem zapisal v prvem sporočilu, torej, če uporabnik zapiše za max. skupno zahtevano količin 0.3 potem bi želel, da mysql od 1. vrstice naprej preverja ta pogoj (sešteva podane količine in vkolikor je skupna vsota večja od 0.3, vse naslednje vrstice ne bodo ustrezne). Sicer pa tako vidim, da si Vini vse razumel.

Rešitev, ki deluje, a me skrbi, da ni optimalna, je ta...

SELECT
  *,
  (SELECT
     sum(cena) FROM tabela
   WHERE id <= t.id) 'skupaj'
FROM tabela t
HAVING skupaj < 2

Zgornje rešitve nisem implementiral, trenutno imam urejeno tako, da najprej izvedem query brez pogoja o količini, le ob pogoju o ceni (ja, tudi cena je pogoj, a ceno in hkrati količino v isti poizvedbi ne morem (?) uporabiti, ker je trik, namreč, če je skupna vsota količin več kot od uporabnika določena vrednost, se del količine lahko tudi odvzame naslednje, sicer po merilih poizvedbe neustrezne vrstice... omb, upam, da bo kdo razumel, kaj želim povedati :) ne znam drugače razložiti, v glavnem, to poizvedbo "o tej famozni vsoti količin" bi potem uporabil izključno, da bi dobil število ustreznih vrsti + 1(!), in to vrednost bi potem uporabil kot max. LIMIT pri spodnji poizvedbi)

SELECT * FROM tabela WHERE cena >= od_uporabnika_dobljena_vrednost  ORDER BY cena DESC, datum ASC.

Trenutno, po izvedbi zgornje poizvedbe ("ki je še brez LIMIT"). filtriram ustrezne vrstice iz polja zadetkov (recimo "narocila"), s PHP zanko. Ko so pogoji izpolnjeni, se zanka ustavi (break),

Pri tem načinu me skrbi to, da je polje "naročila", ki ga dobim iz poizvedbe, lahko zelo veliko, ker v poizvedbi pač nisem upošteval parametra o največji dovoljeni vsoti količin. Recimo, če uporabnik za ceno vpiše 0, potem bodo ustrezni čisto vsi zapisi v bazi, pa čeprav bi bila količina recimo le 0.1 in bi dejansko bil ustrezen le 1. zapis. Torej trenutno imam na pladnju 2 rešitvi, prva je ta s potecialno zelo velikim poljem (RAM) ali gnezdeno poizvedbo, ki bi pa potencialno lahko izvedla ogromno podquerijev, če bi na primer bile ustrezne količine v bazi majhne (recimo 0.00001), od uporabnika določena količina pa bi bila npr., ne vem, 100, potem bi bilo teh delnih vsot (in s tem podquerijev), predno bi se vse skupaj zaključilo ogromno.

Sicer bom tako vse potestiral, ko pride to na vrsto (s par milijoni dummy zapisov & explain) ampak me vseeno zanima, če se da ta delna vsota količin nekako elegantneje rešiti, ker ta rešitev mislim, da ni optimalna, ali pa mogoče, da se da vse zapisati celo z enim querijem (+1 dodatni "neustrezni" vnos).

4