Hai!

Voor het klassement van mijn mahjongclubje heb ik een algemeen klassement bedacht waarbij de beste 20 resultaten van iedere speler tellen.
In het bestand functions.php is dat als volgt gedefinieerd:

function standmetscoresmetid($id) {
// Get database connection
$db = JFactory::getDbo();

$qry = "SELECT SpelerID, SpelerNaam, Average, Aantal, Hoogste, Laagste "
. "FROM vwStand "
. "WHERE SeizoenID = " . $db->quote($id). " AND AANTAL<>0 ORDER BY Average DESC;";

$db->setQuery($qry);
$db->query();
$result=$db->loadRowList();

$tbl = new HTML_Table(null, 'display', 1, 0, 4, array('width'=>'100%'));

}

Maar deze methode bevalt me niet meer zo goed. Ik zou ook de "slechtste" resultaten willen laten
meetellen. Bijvoorbeeld de beste 10 en de slechtste 10, en daar dan het gemiddelde van.
Maar ik heb geen idee hoe ik de 'slechtste 10' moet definiëren.
Iemand een hint?? Alvast bedankt!
Hier kan ik wel wat mee ;-)
Ik ga ermee aan de slag en meld me weer als ik meer weet.

Dank (^^)
Maar wat krijg je dan als resultaat als er minder dan 20 resultaten zijn?
De hoogste 10 en de laagste 10 overlappen dan.

SELECT
	s.SpelerID,
	s.SpelerNaam,
	s.Aantal,
	AVG(CASE
			WHEN r.rijnummer <= 10 THEN r.score
			ELSE
				CASE 
					WHEN r.rijnummer > 10 AND r.rijnummer > s.Aantal - 10 THEN r.score
					ELSE NULL END
		END) gemiddelde,
	MAX(CASE
			WHEN r.rijnummer <= 10 THEN r.score
			ELSE
				CASE 
					WHEN r.rijnummer > 10 AND r.rijnummer > s.Aantal - 10 THEN r.score
					ELSE NULL END
		END) hoogste,
	MIN(CASE
			WHEN r.rijnummer <= 10 THEN r.score
			ELSE
				CASE 
					WHEN r.rijnummer > 10 AND r.rijnummer > s.Aantal - 10 THEN r.score
					ELSE NULL END
		END) laagste
FROM
	(
	SELECT
		d.SpelerID,
		d.SpelerNaam,
		COUNT(*) Aantal
	FROM
		deelnemers d
	JOIN
		resultaten r1
		ON d.SpelerID = r1.SpelerID
	WHERE r1.SeizoenID = 5
	GROUP BY d.SpelerID
	) s
JOIN
	(
	SELECT
		@rijnummer := CASE WHEN ro.SpelerID <> @id THEN 1 ELSE @rijnummer + 1 END rijnummer,
		@id := ro.SpelerID SpelerID,
		ro.score
	FROM
		(
		SELECT
			d1.SpelerID,
			r2.Score
		FROM
			deelnemers d1
		JOIN
			resultaten r2
			ON d1.SpelerID = r2.SpelerID
		WHERE r2.SeizoenID = 5
		ORDER BY d1.SpelerID, r2.score
		) ro
	CROSS JOIN
		(
		SELECT
			@rijnummer := 1,
			@id := 0
		) var
	) r
	ON s.SpelerID = r.SpelerID
GROUP BY s.SpelerID, s.SpelerNaam, s.Aantal
ORDER BY gemiddelde DESC,s.Aantal

De eerste subquery haalt de spelers en het totaal aantal gespeelde partijen op.
De tweede haalt alle resultaten op en nummert deze per speler (in PostGres/Oracle/SQLserver etc gaat dit veel eenvoudiger).

Dit wordt dan gebruikt om te bepalen welke resultaten mee moeten worden genomen in de aggegrate functies (NULL wordt genegeerd)

Edit:
JOIN Conditions toegevoegd
Ger van Steenderen op 19/08/2015 11:45:00


De eerste subquery haalt de spelers en het totaal aantal gespeelde partijen op.
De tweede haalt alle resultaten op en nummert deze per speler (in PostGres/Oracle/SQLserver etc gaat dit veel eenvoudiger).

Dit wordt dan gebruikt om te bepalen welke resultaten mee moeten worden genomen in de aggegrate functies (NULL wordt genegeerd)


Ger, dit ziet er heel indrukwekkend uit, maar toch kom ik er niet helemaal uit. Kun jij me de weg wijzen in wat voor bestand ik deze code moet plakken?
Dank!

Dit haal in 1 query het SpelerID, SpelerNaam, Aantal, Gemiddelde, Hoogste en Laagste op.
Probeer de query eens gewoon uit en kijk met print_r() wat hij terug geeft.
Hai Ger van Steenderen - Complimenten, briljant! Pas vandaag kon ik er iemand bij halen die veel meer verstand heeft van PHP dan ik en die mij geholpen heeft je script te implementeren. We hadden het niet verwacht, maar het werkt, met wat kleine aanpassingen. Het is verder een kwestie van een beetje peuteren en dan werkt het allemaal.
Eén vraag nog. Er zijn grote verschillen in de aantallen wedstrijden die spelers afwerken. Nu loop je de (theoretische) kans dat een speler één keer speelt, een topscore haalt en het dan verder voor gezien houdt. Op die manier zou hij kampioen worden.
In onze huidige ranking lossen we dat op door alle spelers die minder dan 20 wedstrijden hebben gespeeld, 30.000 punten voor iedere niet-gespeelde wedstrijd te geven.Dat zou ook in de nieuwe oplossing passen.
Hoe kunnen we dat implementeren in jouw script?
Nogmaals enorm bedankt, ben hier erg blij mee.
Martin
Dan gebruik je in plaats van AVG() SUM() en bij minder dan 20 wedstrijden tel je er een x aantal bij op.

	(SUM(CASE
			WHEN r.rijnummer <= 10 THEN r.score
			ELSE
				CASE 
					WHEN r.rijnummer > 10 AND r.rijnummer > s.Aantal - 10 THEN r.score
					ELSE NULL END
		END) + CASE
			WHEN s.Aantal < 20 THEN (20-s.Aantal) * 30000
			ELSE 0 END) / 20 gemiddelde,
Kan ik je een PM sturen, en zo ja, hoe?


[size=xsmall]Toevoeging op 29/10/2015 06:56:35:[/size]

Martin Rep op 28/10/2015 23:06:41

Kan ik je een PM sturen, en zo ja, hoe?


…Je hebt 'm al! (^^)

Reageren