Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[MYSQL] maximaal x rows ophalen, gelijkmatig verdelen

Pagina: 1
Acties:

  • cheazers
  • Registratie: November 2002
  • Laatst online: 17:10
Wat ik een maximum aantal rows ontvangen over een grote datareeks. Het aantal rijen moeten echter gelijkmate in de tijd verdeeld zijn. Ik heb nu zoiets:

SQL:
1
2
3
4
5
6
7
SET @interval = (datediff(@starttime,@endtime)/@maxresults);

SELECT  bla
WHERE bla
GROUP BY (DATEDIFF(@starttime, loc.GMTDate)/(@interval/@maxresults)), loc.LocID
ORDER BY loc.GMTDate
LIMIT (0,@maxresults);


starttime en endtime zijn dus een value in datetime formaat. loc.GMTDate is het timestamp veld ook in datetime formaat. LocID is het id veld.

Deze query haalt echt alleen de eerste @maxresults op.

[ Voor 1% gewijzigd door een moderator op 21-11-2007 13:48 . Reden: Code leesbaar gemaakt ]


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
De DateDiff functie onder MySQL geeft dagen terug ;) Dat lijkt me een essentieel verschil met RobIII in "[MySQL] Max 200 waarden opvragen, tijdst..." :) ;)

[ Voor 12% gewijzigd door RobIII op 21-11-2007 13:53 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • cheazers
  • Registratie: November 2002
  • Laatst online: 17:10
RobIII schreef op woensdag 21 november 2007 @ 13:53:
De DateDiff functie onder MySQL geeft dagen terug ;) Dat lijkt me een essentieel verschil met RobIII in "[MySQL] Max 200 waarden opvragen, tijdst..." :) ;)
klopt, echter geeft (timestamp-starttime) als uitkomst 0. Daarom vroeg ik ook wat timestamp en startime voor velden zijn (datetime of unixtime of ...) Voor de volledigheid zijn functie:

SQL:
1
2
3
4
SELECT eenhoop FROM tabellen
WHERE voorwaarden
GROUP BY ROUND((timestamp - starttime)/((starttime - endtime)/maxresults - 1)), sourceid
ORDER BY timestamp

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Je kunt een extra veld op basis van rand() opnemen en dan sorteren op het extra veld.

SQL:
1
select eenhoop, rand() as rv from .... order by rv, timestamp limit 0, 20;

If it isn't broken, fix it until it is..


  • cheazers
  • Registratie: November 2002
  • Laatst online: 17:10
Niemand_Anders schreef op woensdag 21 november 2007 @ 14:57:
Je kunt een extra veld op basis van rand() opnemen en dan sorteren op het extra veld.

SQL:
1
select eenhoop, rand() as rv from .... order by rv, timestamp limit 0, 20;
dankje,

ik ben echter op zoek naar een exact (berekend aan de hand van het maximaal aantal resultaten) tijdsinterval.

  • P.O. Box
  • Registratie: Augustus 2005
  • Niet online
dan heb je sowieso een probleem als je data niet gelijkmatig verdeeld is...
als je 10 records in week 1 hebt en 80 in week 2, welke records wil je dan hebben?
oftewel stel maxrows=5 wil je dan van het aantal records de x/5de, 2x/5, 3x/5, 4x/5, 5x/5 de record van de complete geordende dataset... of wil je echt die van de datum... waarbij het kan voorkomen dat (extreem gezien) dat ook gelijk de laatste vijf records zijn?

bijv:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
01-01-2008 record0
01-01-2008 record1
01-01-2008 record2
01-01-2008 record3
01-01-2008 record4
01-01-2008 record5
01-01-2008 record6
01-01-2008 record7
01-01-2008 record8
01-01-2008 record9
05-01-2008 record10
10-01-2008 record11
15-01-2008 record12
20-01-2008 record13
25-01-2008 record14
30-01-2008 record15


Hier zou je dan in eerste geval terug kunnen krijgen:
record0, record3, record6, record9, recordrecord12, record=15

In het tweede geval zou je kunnen krijgen:
record0, record10, record11, record13, record15

Het is maar wat je wilt...

in beide gevallen zul je je stored procedure met een for-lus moeten uitbreiden denk ik...

  • cheazers
  • Registratie: November 2002
  • Laatst online: 17:10
van de dataset (tussen de 50 en 500 rows, elke row met een timestamp) bv:

id1, 2007-11-21 13:00:00
....
id500, 2007-11-21 18:00:00

de timestamp is echter willekeurig!. hiervan wil ik bv slechts 20 punten hebben. Dus de 1e de laatste, en de rest van die punten moet (in dit geval) over de 5 uur verdeeld zijn.

Het kan dus best zijn dat er 50 entries zijn rond 14:00:00 maar daar wil ik er dus maar 1 van, welke boeit niet. Ik wil dus (in dit geval 20/8=0.25) van ongeveer elk kwartier een punt. daarbij niet kijkende naar het exacte tijdstip, als het maar in de buurt komt. (Stel dat er geen entries tussen 14 en 15 uur, dan maar maar meerdere entries ophalen om 14 en/of 15 uur.

Zo ongelijkmatig zullen de timestamps in werkelijk toch niet verdeeld zijn..

[ Voor 27% gewijzigd door cheazers op 21-11-2007 16:13 ]


  • P.O. Box
  • Registratie: Augustus 2005
  • Niet online
ik heb er even over zitten nadenken... ik kom nog niet tot een slot... maar misschien dat je er mee verder kan... of iemand anders.

ik heb even niet de officiele terminologie bij de hand, dus wordt een soort van pseudocode...
met div bedoel ik delen door zonder rest, met mod bedoel ik juist de rest...

SQL:
1
2
3
4
5
6
7
8
@deelwaarde = (unix_timestamp(@end) - unix_timestamp(@begin)) / @maxrows

select 
    id, 
    (unix_timestamp(datumveld) - (unix_timestamp(@begin)) div @deelwaarde as divide,
    (unix_timestamp(datumveld) - (unix_timestamp(@begin)) mod @deelwaarde as rest
from tabel
order by rest desc


hiermee sorteer je dus op de restwaarde... dus op timestamps die dicht bij de verdeelsleutel liggen... divide moet je zien als de teller van de verdeelsleutel... echter heb je nog wel het probleem dat twee timstamps met dezelfde divide en een iets andere restwaarde nog steeds een restwaarde kunnen hebben die kleiner is dan die van een ander punt op de verdeelsleutel... (weet niet goed hoe ik dat kort moet omschrijven :D)...

voorbeeld:
stel verschil tussen end en begin is 60 en maxrows = 5... dan is de verdeelsleutel 12....

het eerste record is bijv. gelijk aan @begin... dus verschil in tijd = 0.... dan zijn zowel divide als rest gelijk aan 0....

stel tweede record is gelijk aan @begin + 1... dus verschil in tijd met @begin = 1... dan is divide gelijk aan 0 (het 0de interval uit de verdeelsleutel) en rest is gelijk aan 1...

stel derde record is gelijk aan @begin + 27... dus verschil i ntijd met @begin = 27... dan is divide gelijk aan 2 (het 2de interval uit de verdeelsleutel) en rest is gelijk aan 3...

stel het vierde record is gelijk aan @begin + 48.. dus verschil in tijd met @begin = 48... dan is divide gelijk aan 4 (het 4de interval uit de verdeelsleutel) en rest is gelijk aan 0

ga je nu sorteren op rest dan krijg je dus:
code:
1
2
3
4
5
id             rest      divide
record1    0          0
record2    0          4
record3    1          0
record4    3          2


Op zich ben je al een heel eind denk ik zo, alleen krijg je nu uit divide 0 twee records voordat je er 1 uit het 2de interval hebt gekregen....

beetje vaag verhaal... hoop dat je er wat mee kunt... of hoop dat iemand anders een wel simpele oplossing heeft ;)
Pagina: 1