[PHP] Query voor pyramide probleempje

Pagina: 1
Acties:
  • 207 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Afbeeldingslocatie: http://lemon.nexen.net/pyramide.gif
Dit is het probleem:

Ik heb een referral systeem waarbij mensen zich aanmelden en dan wordt de referID van die gene opgeslagen bij het nieuwe lid...

Nou wil ik per persoon zien hoeveel mensen hij onder zich heeft (zie plaatje, het systeem wordt oneindig lang...)

Nu heb ik in gedachten:

SELECT ID WHERE user = 1
while bla bla
SELECT ID WHERE refID = $ID

maar zo kom ik maar 1 laag diep... en voor alle lagen een voorgebakken code maken wordt ook een ramp...

heeft iemand een idee om dit op te lossen?? (alleen globale opzet, rest werk ik zelf wel uit...)

P.S. Volgens mij is deze structuur eigenlijk hetzelfde als op die messageboards, mailinglists gebruikt wordt... (men reageert op reactie op reactie etc) mischien moet ik zo'n script eens opduikelen?

Acties:
  • 0 Henk 'm!

Verwijderd

Volgens mij moet je dit oplossen m.b.v. recursie.
Je maakt een functie die kijkt of een id mensen onder zich heeft. Je geeft als argument het id mee. Als hij mensen onder zich heeft roep je vanuit die functie zichzelf weer aan, met als argument het id.

Als het niet zo is stopt, dan stopt ie.

Het is misschien een beetje wazig, maar als je eenmaal de recursie door hebt is het heel erg makkelijk.

Acties:
  • 0 Henk 'm!

Verwijderd

Wat je in ieder geval kunt doen is een optimalisatie te maken zodat je maar 1 query per 'level' hoeft te doen.

De eerste keer als je een query doet, sla alle ChildID's van het eerste ID in een array op. Bij de volgende select (en alle daarna doe je een SELECT met WHERE id IN (), om dus te zoeken op alle child id's van de child id's uit de array. Maak wel iedere keer de array leeg, zodat je niet voor id's twee keer ga zoeken. En ook gaat het helemaal mis als er 'loops' in je referenties zitten, dus dat mag absoluut niet voorkomen.

Ik hoop dat je er wat aan hebt. Succes :)

Acties:
  • 0 Henk 'm!

  • tomato
  • Registratie: November 1999
  • Niet online
Een vergelijkbaar probleem hebben we hier eerder gehad (ik dacht dat het Burat was). We kwamen dacht ik niet verder dan een recursieve functie, dus geen 'magische query'. Als je echt veel niveaus hebt vind ik het wel een beetje een ranzige oplossing, maarja.
Misschien moet je hem een beetje aanpassen (ik weet niet precies hoe je velden heten enzo), maar je kunt zoiets als dit doen:<BLOCKQUOTE><font size=1 face=Verdana, Arial, Helvetica>quote:</font><HR>function GetCID ($cid) {

global $db, $cidarray;

$query = "SELECT cid FROM cats WHERE parent = $cid";

$resultaat = mysql_query($query, $db);

if ($rij = mysql_fetch_array($resultaat)) {

do {

if (!GetCID($rij["cid"]))
$cidarray[count($cidarray)] = $rij["cid"];

} while ($rij = mysql_fetch_array($resultaat));

return true;

} else {

return false;

}

}

$db = mysql_connect($mysql_host, $mysql_gebruiker, $mysql_wachtwoord);
mysql_select_db($database_naam,$db);

GetCID ($cid);[/quote]Nu heb je dus in $cidarray alle id's van rows die onder je opgegeven $cid vallen. Hopelijk kun je er iets mee...
Oja, dit is dus nog voor optimalisatie vatbaar!

edit:
Code tags gebruik ik hier echt NOOIT meer :(

Acties:
  • 0 Henk 'm!

Verwijderd

Met de bovenstaande query moet je dus voor alle nodes 1 query afvuren behalve voor de ondersten. Als je het doet met een WHERE id IN (1,3,5,7, ... ) hoef je maar in query af te vuren voor een hele rij.

Uit www.mysql.com/documentation/mysql/bychapter/manual_Reference.html#Comparison_functions haal ik het volgende:<BLOCKQUOTE><font size=1 face=Verdana, Arial, Helvetica>quote:</font><HR>expr IN (value,...)
Returns 1 if expr is any of the values in the IN list, else returns 0. If all values are constants, then all values are evaluated according to the type of expr and sorted. The search for the item is then done using a binary search. This means IN is very quick if the IN value list consists entirely of constants. If expr is a case-sensitive string expression, the string comparison is performed in case-sensitive fashion. [/quote]Om jouw voorbeeld aan te houden, levert dat het volgende verschil op:
a) oplossing WHERE id = (val): 13 queries nodig om alle nodes op te halen
b) oplossing WHERE id IN (val1, val2, val3, .. ): 3 queries nodig om alle nodes op te halen.

Voor b) geldt: hoe dieper de boom, des te groter de winst. In het meest ongunstige geval (iedere node heeft maar 1 child) heb je evenveel quries nodig als met a), anders altijd minder.

Enjoy :)

Acties:
  • 0 Henk 'm!

  • tomato
  • Registratie: November 1999
  • Niet online
Ja, het kan dus even wat sneller :). Ik zag ook dat je alle onderliggende waarden in de boom wilde hebben, de functie die ik net gaf geeft alleen de 'uiteinden', maar dat is makkelijk aan te passen...

edit:
Die in() functie van MySQL komt hier trouwens idd erg goed van pas. Met wat aanpassingen is de functie overigens snel om te bouwen en hij is dan ook, zoals je al zegt, veeeel sneller.
* tomato vindt dat MrX nogal eens toffe oplossingen heeft

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Mensen alvast bedankt, ik ga dit allemaal eens even bestuderen en wat aanpassingen doen...

Verwijderd

Glad I could help :-)

Overigens zit die WHERE kolom IN (val1, val2, ...) in vrijwel iedere serieuze RDBMS voor, dus die oplossing is nog behoorlijk overdraagbaar ook. Het helpt dus wel ontzettend veel als je een index hebt op die kolom trouwens. :)

Verwijderd

Topicstarter
hehe, ik wilde eigenlijk de index op de email van die persoon doen >:)

  • paulh
  • Registratie: Juli 1999
  • Laatst online: 29-08 09:58
sjaak: je kan ook meerdere indexen op één tabel leggen ... dus dat mag geen probleem zijn.

[ZwareMetalen.com] - [Kom in aktie tegen de CO2 maffia]

Pagina: 1