[PHP] Searchvoer : Multi array sorteren op 3 waarden

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Basszje
  • Registratie: Augustus 2000
  • Laatst online: 13:17

Basszje

Reisvaap!]

Topicstarter
Wellicht dat een modje even naar een betere topic titel wil zoeken ;) . Maar weer eens een bijdrage van mij :P .

Dit keer met een vraag + oplossing (nieuw!), wellicht dat andere users hier nog wel eens tegenaan lopen.

Het probleem :

PHP:
1
2
3
4
5
6
7
$sql = "SELECT TOPIC_ID, TOPIC_NAME, TOPIC_USER, 
TOPIC_LOCKED,TOPIC_STICKY, TOPIC_LASTPOSTDATE, TOPIC_MESSAGECOUNT, 
TOPIC_FORUM 
FROM 
TBL_TOPIC 
WHERE TOPIC_FORUM = $forum_id
ORDER BY  TOPIC_STICKY DESC, TOPIC_LASTPOSTDATE DESC LIMIT $limit


So far, so good. Echter er is nu een probleem. Ik wil nog een veld, namelijk TOPIC_LOCKED ook sorteren, maar dan onderaan.

Als je dat in je SQL erbij gooit krijg je een hele rare resultset die verre van geordend is ( topics vallen er ineens uit etc ) . Dit komt door de combinatie van limit en het sorteren op 3 velden waarbij de een bovenaan moet uitkomen en de andere onderaan moet uitkomenm, terwijl tegelijkertijd de locked en sticky niet op datum gesorteerd moeten worden, maar de open wel. Dat lukt dus niet.

Mijn array ziet er grofweg gezien zo uit :
code:
1
$topics[row][veldnaam]


-- oplossing --

Ik heb een hele tijd gekeken naar usort, uasort, array_multisort. Maar of ze gaven problemen met multi dimensionale arrays, of met het 'user-defined' sorteren van 3 velden ( hoop gekloot ) .

Om dit probleem te fixen kan het echter ook vele malen korter :

PHP:
1
2
3
4
5
6
foreach ($topics as $key => $tpc) { 
    if ($tpc["TOPIC_LOCKED"] == 1) 
    {   array_push($topics,$tpc);
        unset($topics[$key]);
    }
}


Hij duwt dus elke locked naar het einde en gooit deze in het midden eruit . Zo lukt het dus wel, en veel simpeler dan je in menige search zal vinden :)

-- wat moet je hiermee :? --

Ik wil graag commentaar op gebruikte methode en mochten de gemene modjes ( ;) ) je in de toekomst weer naar de search verwijzen voor zoiets, dan kan je nog altijd aan deze methode denken :)

Beware of listening to the imposter; you are undone if you once forget that the fruits of the earth belong to us all, and the earth itself to nobody.


Acties:
  • 0 Henk 'm!

  • beetle71
  • Registratie: Februari 2003
  • Laatst online: 09-09 15:24
Het werkt toch 8) ........

Over het sorteren van arrays op waarden in subarray heb ik in deze topic:
[rml][ php] multi array sorteren[/rml]
met een oplossing gereageerd.

Misschien heb je er toch iets aan.

Acties:
  • 0 Henk 'm!

  • Basszje
  • Registratie: Augustus 2000
  • Laatst online: 13:17

Basszje

Reisvaap!]

Topicstarter
beetle71 schreef op 15 April 2003 @ 22:55:
Het werkt toch 8) ........

Over het sorteren van arrays op waarden in subarray heb ik in deze topic:
[rml][ php] multi array sorteren[/rml]
met een oplossing gereageerd.

Misschien heb je er toch iets aan.
Had ik al gelezen idd ;) . Maar dat werkt alleen maar voor 1 waarde, terwijl ik er met 3 zat te klooien die allemaal goed moesten staan. Dan wordt je echt maf van de functie die je moet schrijven, terwijl dit dus simpeler is :)

Beware of listening to the imposter; you are undone if you once forget that the fruits of the earth belong to us all, and the earth itself to nobody.


Acties:
  • 0 Henk 'm!

Verwijderd

Van welk kolomtype is het veld TOPIC_LOCKED?

En misschien moet je eens gaan denken aan een andere opzet van je forum.
Je hebt nu twee 'boolean' velden, TOPIC_STICKY en TOPIC_LOCKED, waar je eigenlijk net zo goed iets als TOPIC_STATE had kunnen gebruiken, een veld met een foreign key naar een andere tabel, die aangeeft wat elke state precies inhoudt. Vervolgens pas je het zaakje zo aan dat de id van de state 'sticky' kleiner is dan die van gewone topics, en 'locked' juist groter.

TOPIC ( TOPIC_ID, TOPIC_NAME, TOPIC_STATE_ID )

TOPIC_STATE ( TOPIC_STATE_ID, TOPIC_STATE_NAME )

Ook had je hier een GROUP BY clause kunnen gebruiken. Dat kan denk ik zo ook wel, als je geen zin hebt om je DB ontwerp om te gooien.

Dit is wel met SQL op te lossen, en daarmee hoor je het ook op te lossen als het kan. Bijna alles is beter dan zelf wazige programmeer-oplossingen bedenken :)

[ Voor 3% gewijzigd door Verwijderd op 15-04-2003 23:02 ]


Acties:
  • 0 Henk 'm!

  • Basszje
  • Registratie: Augustus 2000
  • Laatst online: 13:17

Basszje

Reisvaap!]

Topicstarter
Cheatah -> Hoe krijg je dan bv via die TOPIC tabel de TOPIC_STATES met id =1 bv bovenaan, die met id = 2 onderaan en die met 0 geordende op datum ertussen ?

Ik noem maar wat :)

Beware of listening to the imposter; you are undone if you once forget that the fruits of the earth belong to us all, and the earth itself to nobody.


Acties:
  • 0 Henk 'm!

  • thomaske
  • Registratie: Juni 2000
  • Laatst online: 17-09 07:55

thomaske

» » » » » »

Basszje schreef op 15 april 2003 @ 23:41:
Cheatah -> Hoe krijg je dan bv via die TOPIC tabel de TOPIC_STATES met id =1 bv bovenaan, die met id = 2 onderaan en die met 0 geordende op datum ertussen ?
Je kan toch gewoon orderen op topic_state en datum!

Brusselmans: "Continuïteit bestaat niet, tenzij in zinloze vorm. Iets wat continu is, is obsessief, dus ziekelijk, dus oninteressant, dus zinloos."


Acties:
  • 0 Henk 'm!

  • beetle71
  • Registratie: Februari 2003
  • Laatst online: 09-09 15:24
Cheatah -> Hoe krijg je dan bv via die TOPIC tabel de TOPIC_STATES met id =1 bv bovenaan, die met id = 2 onderaan en die met 0 geordende op datum ertussen ?
...
Door even verder te denken en dan:
TOPICSTATES:
1 sticky
2 normal
3 locked
... en dan sorten op topicstate,date...

Acties:
  • 0 Henk 'm!

Verwijderd

Ik heb ook zo'n probleem:

PHP:
1
2
3
4
5
6
7
<?php
    $sql = "SELECT *, topic.status AS status, topic.topic_id AS topic_id, reply.titel AS titel FROM reply, topic WHERE topic.cat='$f'AND topic.topic_id=reply.topic_id ORDER BY topic.status AND reply.date DESC";


    $query = mysql_query($sql) or die(mysql_error());

?>


Ik wil dus orderen op 2 velden, op "status" en op "laatste reply", dat voor "date" staat.
Nu is mijn probleem: hij sorteert op de date van het gepostte topic, die hij van reply haalt, (met andere woorden dus de datum dat het topic werd gepost) maar hij moet eigenlijk sorteren op het laatste id van de reply, hoe doe ik dit? Ik vrees dat ik daarvoor een andere query zal moeten maken, want in deze kan je hem toch niet bijgooien of wel?

Acties:
  • 0 Henk 'm!

  • beetle71
  • Registratie: Februari 2003
  • Laatst online: 09-09 15:24
@ bReEzAh,

Waarom door je een AND tussen de sort fields?? Dat moet toch een , (komma) zijn.. Ik weet niet zeker wat er met AND gebeurd, maar ik kan me voorstellen dat dat hier als een logische AND wordt gebruik, hij sorteert dan op de uitkomst van (topic.status AND reply.date) en dat is 0 of 1.. (waarschijnlijk neemt hij daarna de volgorde van de records in de database en lijkt het voor jouw of 'ie daarop sorteert)

Je zegt dat je wilt sorteren op eerst de status en vervolgens op de datum van reply. dat doe je dus zo
code:
1
ORDER BY topic.status, reply.date

[ Voor 12% gewijzigd door beetle71 op 16-04-2003 08:59 ]


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 16:51
beetle71 schreef op 16 April 2003 @ 08:39:
[...]
...
Door even verder te denken en dan:
TOPICSTATES:
1 sticky
2 normal
3 locked
... en dan sorten op topicstate,date...
Dit is inderdaad een hele mooie manier vind ik. Alleen kun je later alleen nog een nieuw niveau onder de andere niveau's plaatsen toch? Anders zou je komma-getallen moeten gaan gebruiken en dat is ook niet echt handig ;)

Als je het helemaal top wilt maken kun je denk ik beter iets als dit doen:
De foreign key naar STATUS laten staan, en dan de status-tabel wijzigen in:
id-omschrijving-niveau

Je kunt dan de volgorde van de niveau's veranderen zonder dat je de id's wijzigd. B)

Verder is het misschien verstandig om deze gegevens gewoon in een array te zetten als je de gebruiker deze gegevens toch niet wilt laten veranderen. Als dit wel de bedoeling is kan je het natuurlijk wel beter in een database zetten.

[ Voor 18% gewijzigd door djluc op 16-04-2003 10:05 . Reden: typo ]


Acties:
  • 0 Henk 'm!

Verwijderd

beetle71 schreef op 16 April 2003 @ 08:57:
@ bReEzAh,

Waarom door je een AND tussen de sort fields?? Dat moet toch een , (komma) zijn.. Ik weet niet zeker wat er met AND gebeurd, maar ik kan me voorstellen dat dat hier als een logische AND wordt gebruik, hij sorteert dan op de uitkomst van (topic.status AND reply.date) en dat is 0 of 1.. (waarschijnlijk neemt hij daarna de volgorde van de records in de database en lijkt het voor jouw of 'ie daarop sorteert)

Je zegt dat je wilt sorteren op eerst de status en vervolgens op de datum van reply. dat doe je dus zo
code:
1
ORDER BY topic.status, reply.date
Hartelijk dank Noline!
Ik wist dat er iets fout was, heb deze fout trouwens al meer gemaakt!
Mijn verontschuldigingen. ;)

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Het kan, met die limit zo, idd niet echt handig in SQL (kan wel, maar dan mag je al gauw richting subselects gaan zoeken).

Als je echter een beperking op je datum legt dan is het relatief simpel:
SQL:
1
2
3
4
5
6
7
8
select ... from topics
where 
(   topicdatum > $begintijd
    OR
    topicstatus = X )
AND 
forumid = Y
order by ...

Als je het een beetje handig aanpakt heb je dan zelfs geen limit nodig.

Het nadeel is natuurlijk dat je dan geen echte paginering van een vaste hoeveelheid topics/pagina kan geven :)

Owja, nog iets.
Mysql sucked op die query ;)

De query is helemaal correct, maar mysql krijgt het niet voor elkaar die efficient uit te voeren omdat er twee aparte filtertjes zijn.

[ Voor 15% gewijzigd door ACM op 16-04-2003 10:22 ]


Acties:
  • 0 Henk 'm!

  • Basszje
  • Registratie: Augustus 2000
  • Laatst online: 13:17

Basszje

Reisvaap!]

Topicstarter
beetle71 schreef op 16 April 2003 @ 08:39:
[...]
...
Door even verder te denken en dan:
TOPICSTATES:
1 sticky
2 normal
3 locked
... en dan sorten op topicstate,date...
Thanks voor alle reacties. Toch nog even reactie hierop ^^^ . Als je dit doet dan moet je vaste nummers als ID gebruiken voor je states . Dat is ook niet bepaald netjes. Oplossing van djluc zou dat idd wel oplossen, maar dat is imo allemaal weer een beetje overkill ;) ( ik hou liever het aantal tabellen beperkt) .

en om nou idd op start datum te gaan checken vind ik ook niet erg prettig aangezien datums nou wel eens vage dingen willen doen en idd het moet wel allemaal netjes te pagineren zijn etc :)

Beware of listening to the imposter; you are undone if you once forget that the fruits of the earth belong to us all, and the earth itself to nobody.

Pagina: 1