Toon posts:

[PHP - Templates] Probleem opbouw array - relaties subarrays

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hoi,

Mijn dbase heeft de volgende structuur: game -> league -> war. Dus per gametype zijn er aantal leagues en in elke league worden er een aantal wars gespeeld. Elke tabel bevat dus de key van de vorige tabel (behalve voor de tabel game uiteraard, dat is de top). (1-N relatie)

Nu heb ik 3 queries: 1 voor de games, 1 voor alle leagues en 1 voor alle wars. Ik ben akkoord dat het aantal queries hier verminderd (zelfs tot 1 normaal gezien) kan worden, maar dan is de query (volgens mij) uitermate onderheving aan reduntantie, omdat ik in die ene query altijd opnieuw per rij de informatie over het gametype en over de league moet neerhalen. Vandaar heb ik het dus gedaan in 3 queries, zodat redundantie = 0%.

Nu maak ik gebruik van templates (jazeker! :>) en geef ik alle informatie in 1 array door aan de template parser. Mijn array ziet er als volgt uit:

code:
1
2
3
4
5
6
7
8
9
array $warListData:
    -> ['game_id'] (x)
        -> ['game_name']
        -> ['leagues'] (x)
                -> ['league_id'] (x)
                    -> ['league_name']
                    -> ['wars'] (x)
                    -> '[war_id'] (x)
                        -> ['war_timestamp']


(ik heb overbodige velden weggelaten, dus alleen de structuur heb ik overgehouden). Zoals je ziet maak ik de sub-arrays ahv. de primary keys uit de database: per ID maak ik telkens een index die overeenkomt met de desbetreffende inhoud van de database. (vb. game_name, league_name, war_timestamp)

Echter bij het maken van deze array heb ik "moeilijkheden" met mijn array, en dit om volgende reden: ik moet steeds de vorige primary keys kennen, want anders kan ik de gegevens niet invullen in mijn array. Dus ik moet altijd mijn query zo opbouwen, dat ik altijd eindig aan de top (in dit geval de tabel game), want anders kan ik de gegevens niet in de array invullen.

Bijv:
query1: gametypes neerhalen

Geen problemen hier met deze query.

query2: leagues neerhalen

Geen problemen hier met deze query.

query3: wars neerhalen

Probleem: ik moet mijn query zo opbouwen, zodat hij "eindigt" bij de eerste tabel (game), want anders kan ik mijn resultaten van de query niet op de juiste plaats zetten, want ik ken de Y in $warListData[Y]['leagues']... niet.

Op zich is dat in dit geval niet zo'n probleem, maar stel dat ik nog relatie zoals seasons, maps, .. wil gaan inbouwen. Dan ga ik altijd "problemen" hebben vanaf de derde query.

Mijn vraag nu: is dit "normaal", of scheelt er iets aan .. mijn array-opbouw? mijn queries? structuur? Of hoe moet ik het dan wel aanpakken?

Alle suggesties zijn welkom! :) Ik wil dit eerst goed hebben, vooraleer ik verder ga met het "echte" werk.

Ik hoop dat het duidelijk is :X

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 07:40
Het probleem is mij niet duidelijk. Als je leages wilt uitsplitsen naar games, dan lijkt het me niet meer dan logisch dat je de leages erbij wilt hebben? Als je alle leages wilt hebben, zonder te weten bij welke game ze horen, wat let je dan om het eerste 'nivo' van je array weg te laten?

Verwijderd

Topicstarter
OOPS, een klein foutje gemaakt precies :( :( sorry

Het probleem zit hem niet in de tweede query (die relatie is inderdaad overbodig, ik beschik daar al over de key game_id), maar in de derde (en eventuele latere vierde, vijfde, ..) query.

Het probleem in de derde query (moet ik hem posten?) is dat ik terug moet gaan met mijn relaties tot bij game, want ik heb game_id nodig.
Doe ik dat niet, dan is de Y in volgende gelijkheid onbekend:

$warListData[Y]['leagues'][$row['league_id']]['wars'][$row['war_id']]['war_timestamp'] = $row['war_timestamp'];

blame het weer :)
Soultaker schreef op 20 augustus 2002 @ 14:35:
Het probleem is mij niet duidelijk. Als je leages wilt uitsplitsen naar games, dan lijkt het me niet meer dan logisch dat je de leages erbij wilt hebben? Als je alle leages wilt hebben, zonder te weten bij welke game ze horen, wat let je dan om het eerste 'nivo' van je array weg te laten?
Omdat ik op mijn pagina alles per per gametype, en daaronder per league wil sorteren, en niet per league met "ernaast" het gametype (op hetzelfde niveau dus).

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 07:40
Sorry, misschien ligt het aan het weer ( ;) ) maar ik snap nog steeds niet waar je heen wil en wat nu precies het probleem vormt. Misschien kun je een kort voorbeeldje geven met de layout waar je naar toe wilt?

Ik zit nu te denken aan:
code:
1
2
3
4
5
6
7
8
9
10
11
Quake
    League X
        Soultaker vs DiEane
        ....
    League Y
        ...
Doom
    League A
        ...
    League B
        ...


Dat is tenminste waar je, met de eerste array structuur, op uit komt.

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

Als ik jou was zou ik een mooie query maken met enige inner joins erin en vervolgens telkens de gegevens die constant blijven checken... Zoiets:

PHP:
1
2
3
4
5
6
7
8
9
10
$last = array();
while ($row = mysql_fetch_array($res)) {
     if ($last["gameid"] != $row["gameid"]) {
         // doe print dingen voor tussen de games
     }

     // doe dingen voor elke war

     $last = $row;
}


Dit werkt niet helemaal netjes met error_reporting op E_ALL, maar goed, meer als proof of concept.

Rustacean


Verwijderd

Topicstarter
Als reply op beide:

Eerst had ik volgende query, die perfect werkt:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
SELECT  omg_war.war_id,
                omg_war.war_timestamp,
                omg_war.war_result_omg,
                omg_war.war_result_opponent,
                omg_clanlist.clan_tag,
                omg_clanlist.clan_name,
                omg_clanlist.clan_url,
                omg_leaguelist.league_id,
                omg_leaguelist.league_name,
                omg_leaguelist.league_name_short,
                omg_leaguelist.league_url,
                omg_leaguelist.game_id,
                omg_gamelist.game_id,
                omg_gamelist.game_name
            FROM omg_gamelist
            INNER JOIN omg_clanlist ON
                omg_war.clan_id = omg_clanlist.clan_id
            INNER JOIN omg_leaguelist ON
                omg_gamelist.game_id = omg_leaguelist.game_id
            INNER JOIN omg_war ON
                omg_leaguelist.league_id = omg_war.league_id
            WHERE   omg_leaguelist.league_extern = 'YES' AND
                (
                    omg_war.war_result_opponent <> 0 OR
                    omg_war.war_result_omg <> 0
                )
            ORDER BY omg_gamelist.game_position ASC,
                 omg_leaguelist.league_name ASC,
                 omg_war.war_timestamp DESC


Nu is er niets verkeerd met deze bovenstaande query. Maar ik vind dat deze query een beetje "te" onderheving is aan redundantie, en daarom wou ik het eens proberen in 3 queries: query game, query league en query war, zodat er geen sprake was van reduntantie.

Het doel was dus dat ik wat benchmarks kon gaan uitvoeren, en zien welke oplossing de beste oplossing is.

query 1:
PHP:
1
2
3
4
SELECT  omg_gamelist.game_id,
                omg_gamelist.game_name
            FROM omg_gamelist
            ORDER BY omg_gamelist.game_position ASC


query 2:
PHP:
1
2
3
4
5
6
7
8
SELECT  omg_leaguelist.league_id,
                omg_leaguelist.league_name,
                omg_leaguelist.league_name_short,
                omg_leaguelist.league_url,
                omg_leaguelist.game_id
            FROM    omg_leaguelist
            WHERE   omg_leaguelist.league_extern = 'YES' 
            ORDER BY omg_leaguelist.league_name ASC


query 3:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT  omg_war.war_id,
                omg_war.war_timestamp,
                omg_war.war_result_omg,
                omg_war.war_result_opponent,
                omg_war.league_id,
                omg_clanlist.clan_tag,
                omg_clanlist.clan_name,
                omg_clanlist.clan_url,
                omg_gamelist.game_id
            FROM omg_war, omg_clanlist, omg_leaguelist, omg_gamelist
            WHERE   omg_war.clan_id = omg_clanlist.clan_id AND
                (
                    omg_war.war_result_opponent <> 0 OR
                    omg_war.war_result_omg <> 0
                ) AND
                omg_war.league_id = omg_leaguelist.league_id AND
                omg_leaguelist.game_id = omg_gamelist.game_id AND
                omg_leaguelist.league_extern = 'YES'
            ORDER BY omg_war.war_timestamp DESC


Het probleem zit hem nu in de derde query.

Zoals je in mijn eerste post ziet, gaat mijn array steeds dieper en dieper. De bedoeling was dus dat ik (in de derde query) de wars apart ging neerhalen, zonder rekening te houden met de leagues/gametypes. Echter ben ik verplicht deze query op te bouwen zoals hij nu is en terug te gaan tot het hoogste level (level gametype in dit geval, en dus wel rekening houden), omdat ik moet beschikken over het veld omg_gamelist.game_id WANT anders kan ik bijv. het veld war_timestamp niet invullen, want de Y (die staat voor game_id) in $warListData[Y]['leagues'][league_id]['wars'][war_id]['war_timestamp'] = ... kende ik dan niet.

Snap je nu wat ik bedoel? Het probleem zit hem dus niet in het resultaat, maar hoe ik tot dat resultaat kom.

Mijn vraag is nu hoe ik dit moet oplossen en of ik mijn array verkeerd opstel, zodat ik in mijn queries niet hoef terug te keren naar de root opdat ik de informatie wel kan invullen in de $warListData array.

EDIT: hoe fix ik dat 'YES'-gedoe?

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

Misschien een beetje een dooddoener, maar doe het gewoon met die mega-query. Niet alleen maak je het jezelf nodeloos ingewikkeld met die tweede manier, de kans is ook zeer groot dat de tweede manier slomer is dan de eerste, omdat de redundantie waarschijnlijk niet compenseert voor de overhead bij het uitvoeren van twee extra queries.

Rustacean


Verwijderd

Topicstarter
Ok dan, want na 3 dagen vloeken begin ik het inderdaad moe te worden :) Ik zal de ene grote query gebruiken, ook al is hij ondergeschikt aan redundantie ;) OF is er nog een andere oplossing, beter dbase model?

Echter heb ik dan nog 2 vragen:

· Maakt het uit of ik omg_leaguelist.league_extern = 'YES' in de where clause of in de desbetreffende join 'INNER JOIN omg_leaguelist ON ..' zet?
Zelf zou ik zeggen dat de relaties in de JOIN komen te staan, en de voorwaarden/beperkingen in de WHERE, maar dan is dan ook maar uit mijn duim gezogen :)

· Als ik de tweede en de derde INNER JOIN aanpas in een LEFT JOIN zou hij normaal gezien ook de gametypes/leagues moeten tonen waar nog geen geen leagues/wars voor gespeeld zijn (en gewoon de velden in deze kolommen leeg/null laten, zodat ik in mijn template zinnetjes kan zetten als "No leagues yet for this gametype." en "No wars yet in this league."). Echter werkt dat niet, heb jij (of iemand anders :>) enig idee waarom en hoe ik dat wel gedaan krijg?

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

Verwijderd schreef op 20 augustus 2002 @ 19:29:
· Maakt het uit of ik omg_leaguelist.league_extern = 'YES' in de where clause of in de desbetreffende join 'INNER JOIN omg_leaguelist ON ..' zet?
Zelf zou ik zeggen dat de relaties in de JOIN komen te staan, en de voorwaarden/beperkingen in de WHERE, maar dan is dan ook maar uit mijn duim gezogen :)
Ik gebruik nooit de tekst INNER JOIN, maar stop die dingen in mijn WHERE (bijvoorbeeld WHERE table.field=tabel.veld). Alleen voor OUTER JOINs gebruik ik zo'n expliciete syntax. Ik zou dat criterium sowieso in je WHERE laten staan, dan gaat het vast goed. :)
Verwijderd schreef op 20 augustus 2002 @ 19:29:
· Als ik de tweede en de derde INNER JOIN aanpas in een LEFT JOIN zou hij normaal gezien ook de gametypes/leagues moeten tonen waar nog geen geen leagues/wars voor gespeeld zijn (en gewoon de velden in deze kolommen leeg/null laten, zodat ik in mijn template zinnetjes kan zetten als "No leagues yet for this gametype." en "No wars yet in this league."). Echter werkt dat niet, heb jij (of iemand anders :>) enig idee waarom en hoe ik dat wel gedaan krijg?
k Heb zelf niet enorm veel ervaring met outer joins, maar k zal ff kijken.

Rustacean


Verwijderd

Topicstarter
Manuzhai schreef op 20 augustus 2002 @ 20:44:
[...]
Ik gebruik nooit de tekst INNER JOIN, maar stop die dingen in mijn WHERE (bijvoorbeeld WHERE table.field=tabel.veld). Alleen voor OUTER JOINs gebruik ik zo'n expliciete syntax. Ik zou dat criterium sowieso in je WHERE laten staan, dan gaat het vast goed. :)


[...]
k Heb zelf niet enorm veel ervaring met outer joins, maar k zal ff kijken.
Moet dat met een OUTER JOIN? Zoiets hoort toch met een LEFT join, niet?

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
SELECT                      omg_war.war_id, 
                            omg_war.war_timestamp, 
                            omg_war.war_result_omg, 
                            omg_war.war_result_opponent, 
                            omg_clanlist.clan_tag, 
                            omg_clanlist.clan_name, 
                            omg_clanlist.clan_url, 
                            omg_leaguelist.league_id, 
                            omg_leaguelist.league_name, 
                            omg_leaguelist.league_name_short, 
                            omg_leaguelist.league_url, 
                            omg_leaguelist.game_id, 
                            omg_gamelist.game_id, 
                            omg_gamelist.game_name 
FROM                        omg_gamelist 
NATURAL LEFT JOIN           omg_clanlist
NATURAL LEFT JOIN           omg_leaguelist
NATURAL LEFT JOIN           omg_war
WHERE                       omg_leaguelist.league_extern = 'YES' AND 
                            ( 
                                omg_war.war_result_opponent <> 0 OR 
                                omg_war.war_result_omg <> 0 
                            ) 
ORDER BY                    omg_gamelist.game_position ASC, 
                            omg_leaguelist.league_name ASC, 
                            omg_war.war_timestamp DESC
Zoiets? (LEFT is een vorm van OUTER :)).

Rustacean


Verwijderd

Topicstarter
Als ik die query doe, krijg ik resultaten die totaal niet kloppen... ik ben nog bezig aan het debuggen om te zien wat er mis loopt, maar voor het moment zie ik niets verkeerd.

Daarnaast snap ik de bedoeling niet goed. Als ik de doc goed lees, is een NATURAL LEFT JOIN identiek aan een LEFT JOIN, alleen legt hij automatisch de verbanden tussen de indices/keys.

Stel ik heb deze inhouden:
code:
1
2
3
4
5
6
7
8
9
10
quake
    quake league 1
    quake league 2
        ikke vs jij
ut
    ut league 1
cs
    cs league 1
        hij vs haar
rtcw
Dan geeft mijn bovenstaande (en waarschijnlijk ook jou, als het goed wordt toegepast) query na aanpassen van JOIN 2 en 3 in een LEFT JOIN, alleen "quake->quake league 2-> ikke vs jij" en "cs->cs league 1->hij vs haar" en hij geeft niet de overige gametypes en/of leagues + laat eventuele velden leeg/null.

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

Verwijderd schreef op 20 augustus 2002 @ 22:00:
Stel ik heb deze inhouden:
code:
1
2
3
4
5
6
7
8
9
10
quake
    quake league 1
    quake league 2
        ikke vs jij
ut
    ut league 1
cs
    cs league 1
        hij vs haar
rtcw
Als het zou werken zoals ik het bedoeld heb zou het iets anders doen:

code:
1
2
3
4
5
quake | league 1 |
quake | league 2 | ikke vs jij
ut | league 1 |
cs | league 1 | hij vs haar
rtwc | |

Rustacean


Verwijderd

Topicstarter
Manuzhai schreef op 20 augustus 2002 @ 22:20:
[...]
Als het zou werken zoals ik het bedoeld heb zou het iets anders doen:

code:
1
2
3
4
5
quake | league 1 |
quake | league 2 | ikke vs jij
ut | league 1 |
cs | league 1 | hij vs haar
rtwc | |
Dat moet het doen outputten ja, maar ik had het over de inhoud van de dbase, niet over de gewenste output.

Hij geeft dus alleen maar 'quake | league 2 | ikke vs jij' en 'cs | league 1 | hij vs haar' en niet de rijen waar lege velden in voorkomen, ondanks de left join.

query:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
SELECT      omg_gamelist.game_id,
                omg_gamelist.game_name,
                omg_leaguelist.league_id,
                omg_leaguelist.league_name,
                omg_leaguelist.league_name_short,
                omg_leaguelist.league_url,
                omg_leaguelist.game_id,
                omg_war.war_id,
                omg_war.war_timestamp,
                omg_war.war_result_omg,
                omg_war.war_result_opponent,
                omg_clanlist.clan_tag,
                omg_clanlist.clan_name,
                omg_clanlist.clan_url
            FROM omg_gamelist
            LEFT JOIN omg_leaguelist ON
                    omg_leaguelist.game_id = omg_gamelist.game_id
            LEFT JOIN omg_war ON
                    omg_war.league_id = omg_leaguelist.league_id
            INNER JOIN omg_clanlist ON
                    omg_clanlist.clan_id = omg_war.clan_id
            WHERE   omg_leaguelist.league_extern = 'YES' AND
                (
                    omg_war.war_result_opponent <> 0 OR
                    omg_war.war_result_omg <> 0
                )
            ORDER BY omg_gamelist.game_position ASC,
                     omg_leaguelist.league_name ASC,
                     omg_war.war_timestamp DESC


Iemand idee waarom?

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

Verwijderd schreef op 20 augustus 2002 @ 22:24:
[...]


Dat moet het doen outputten ja, maar ik had het over de inhoud van de dbase, niet over de gewenste output.

Hij geeft dus alleen maar 'quake | league 2 | ikke vs jij' en 'cs | league 1 | hij vs haar' en niet de rijen waar lege velden in voorkomen, ondanks de left join.

query:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
SELECT      omg_gamelist.game_id,
                omg_gamelist.game_name,
                omg_leaguelist.league_id,
                omg_leaguelist.league_name,
                omg_leaguelist.league_name_short,
                omg_leaguelist.league_url,
                omg_leaguelist.game_id,
                omg_war.war_id,
                omg_war.war_timestamp,
                omg_war.war_result_omg,
                omg_war.war_result_opponent,
                omg_clanlist.clan_tag,
                omg_clanlist.clan_name,
                omg_clanlist.clan_url
            FROM omg_gamelist
            LEFT JOIN omg_leaguelist ON
                    omg_leaguelist.game_id = omg_gamelist.game_id
            LEFT JOIN omg_war ON
                    omg_war.league_id = omg_leaguelist.league_id
            INNER JOIN omg_clanlist ON
                    omg_clanlist.clan_id = omg_war.clan_id
            WHERE   omg_leaguelist.league_extern = 'YES' AND
                (
                    omg_war.war_result_opponent <> 0 OR
                    omg_war.war_result_omg <> 0
                )
            ORDER BY omg_gamelist.game_position ASC,
                     omg_leaguelist.league_name ASC,
                     omg_war.war_timestamp DESC


Iemand idee waarom?
Ik gok dat de laatste INNER ook LEFT moet worden.

Rustacean


Verwijderd

Topicstarter
Manuzhai schreef op 20 augustus 2002 @ 23:17:
[...]
Ik gok dat de laatste INNER ook LEFT moet worden.
Neen hoor, je hebt altijd de garantie dat een war gespeeld wordt tegen een clan, dus die relatie zal er ook zijn. Een war zonder opponent bestaat niet, dus een LEFT JOIN is niet nodig hier.

For the record: Ik heb het uitgeprobeerd, en zoals ik al aangaf: no difference.

ps: je moet die code niet helemaal opnieuw quoten :)

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

Verwijderd schreef op 20 augustus 2002 @ 23:27:
ps: je moet die code niet helemaal opnieuw quoten :)
Ik moet nix. :P

Dan weet ik het ook even niet meer.

Rustacean


Verwijderd

Topicstarter
Jammer :)

Iemand anders? (ja, akkoord, ik heb geen 24h gewacht, maar ik verwachtte toch geen antwoord meer)
Pagina: 1