reklama
Aktuality  |  Články  |  Recenze
Doporučení  |  Diskuze
Grafické karty a hry  |  Procesory
Storage a RAM
Monitory  |  Ostatní
Akumulátory, EV
Robotika, AI
Průzkum vesmíru
Digimanie  |  TV Freak  |  Svět mobilně

MySQL SELECT z viacerých tabuliek

dabelik (110)|31.3.2011 15:52
Zdravím,

máme MySQL script:

"SELECT fight_enemy.nick, DATE_FORMAT(fight.time,'%D %M %Y %H:%i:%s') AS time, fight_enemy.experience AS ene_exp, fight_me.experience AS me_exp, IF(fight_me.gold = 0, (SELECT -fight_enemy.gold FROM fight_enemy WHERE fight_enemy.fight_id_fight = fight.id_fight LIMIT 1), fight_me.gold) AS gold, fight.win, fight_me.attacker FROM fight JOIN fight_enemy ON fight_enemy.fight_id_fight = fight.id_fight JOIN fight_me ON fight_me.fight_id_fight = fight.id_fight GROUP BY fight_enemy.nick ORDER BY time DESC"

Select vyberie všetky súvisiace dáta ako potrebujem avšak vyberá prvý výskyt v DB, totiž v tabuľke fight sú informácie o čase zápasu a pod., v tabuľke fight_enemy sa nachádzajú duplicitné údaje (boj s rovnakým protivníkom) a ja by som potreboval vybrať len raz (unikátne) nick protivníka (preto som dodal GROUP BY) ale dáta z posledného boja (akosi neviem kde zahrnúť podmienku aby vybrala DB zápas, ktorý má "MAX(fight.time)"). Netuším či som to dostatočne zrozumiteľne vysvetlil ale napadá niekoho nejaké možné riešenie?

Vopred vďaka za odpovede, s pozdravom striky..
Pabler (425)|31.3.2011 19:09
Neviem ci som spravne pochopil, ale

pokial ti to dava spravny result set a zoradeny tak ako chces,
tak by sa dal pouzit limit
http://php.about.com/od/mysqlcommands/g/Limit_sql.htm

potom by bol Limit 0,1 (0- od prveho, pocet 1)


Inak sa to dost strasne cita .... odporucam formatovat dako takto:

Select o.meno,o.priezvisko, p.id
From Osoby o, Pracovnici p
Where o.pkey = p.rc //vlastne join on ....
AND p.id < 50000
Order by bla bla...
Group by bla bla...


taktiez nie je na skodu, daka ilustracia tabuluky/tabuliek //nemusi byt cela, staci aby clovek vedel co ktora tabulka obsahuje a co ide kam ako Pkey-Fkey
dabelik (110)|31.3.2011 19:48
Ahoj,

ak ale použijem LIMIT tak mi vypíše len jeden nick, nie? Ja potrebujem každý nick iba raz, čiže ekvivalent k DISTINCT (čo v tomto selecte nefunguje).

Schéma:

Tab1::fight
(PK)id_fight, time, win
1, 2011-03-30 00:48:24, 1
2, 2011-03-30 01:48:24, 1
3, 2011-03-30 03:48:24, 0
...

Tab2::fight_enemy
(PK)id_enemy, (FK)fight_id_fight, nick, gold, experience
1, 1, enemy1, 0, 0
2, 2, enemy2, 0, 0
3, 3, enemy1, 70, 0
...

Tab3::fight_me
(PK)id_me, (FK)fight_id_fight, nick, gold, experience
1, 1, me, 100, 0
2, 2, me, 50, 0
3, 3, me, 0, 0
...

Result:
nick, time, gold, win
enemy1, 2011-03-30 03:48:24, 100, 1 // Tu DB vyberie prvý zápas pre daný nick
enemy2, 2011-03-30 01:48:24, 50, 1

Miesto toho aby mi vyšlo toto:
nick, time, gold, win
enemy1, 2011-03-30 00:48:24, -70, 0 // Takto je to správne (posledný zápas pre daný nick)
enemy2, 2011-03-30 01:48:24, 50, 1

Myslím, že to už vnieslo trošku svetla do problému, prípadne sa pýtaj ďalej. Ďakujem ti za reakciu.
Pabler (425)|1.4.2011 16:09
Acha asi uz viem co mas na mysli, ... no zda sa ze sa nevyhnes /tolko nenavidenemu/ vnorenemu selectu

takze miesto toho Order by Time desc (pokial si to planoval kvoli tomu aby nahadzovalo posledny cas - v skutocnosti to triedi az celu vyslednu mnozinu)
-ak si to celkove triedenie planoval, tak samozrejme nechaj ....


ale tak este ten vnoreny select v podmienke na konci ...
WHERE time = (SELECT MAX(pomF.Time)
FROM fight pomF
WHERE pomF.id_enemy = xxx.id_enemy
)
xxx by bolo pomenovanie tabulky fight_enemy vo vonkajsom from //alias
dabelik (110)|4.4.2011 18:46
Ahoj,

ak som to správne pochopil tak by to malo vyzerať takto:
"SELECT f_e.nick, DATE_FORMAT(f.time,'%D %M %Y %H:%i:%s') AS time, f_e.experience AS ene_exp, f_m.experience AS me_exp, IF(f_m.gold = 0, (SELECT -f_e.gold FROM fight_enemy f_e WHERE f_e.fight_id_fight = f.id_fight LIMIT 1), f_m.gold) AS gold, f.win, f_m.attacker, f_e.fight_id_fight AS test FROM fight f JOIN fight_enemy f_e ON f_e.fight_id_fight = f.id_fight JOIN fight_me f_m ON f_m.fight_id_fight = f.id_fight WHERE f.time = (SELECT MAX(pomF.time) FROM fight pomF WHERE pomF.id_fight = test) GROUP BY f_e.nick ORDER BY f.time DESC"

Čo ale nefunguje pretože alias vo WHERE nieje ešte naplnený a použitie HAVING kvôli aliasu sa mi akosi tiež nedarí rozchodiť. Neviem čo s tým no. Ale vďaka za snahu :)
Pabler (425)|5.4.2011 20:00
myslel som to dako takto:

SELECT f_e.nick, DATE_FORMAT(f.time,'%D %M %Y %H:%i:%s') AS time,
f_e.experience AS ene_exp, f_m.experience AS me_exp,
IF(f_m.gold = 0, (SELECT -f_e.gold FROM fight_enemy f_e WHERE f_e.fight_id_fight = f.id_fight LIMIT 1), f_m.gold) AS gold,
f.win, f_m.attacker,

FROM fight f
JOIN fight_enemy f_e ON f_e.fight_id_fight = f.id_fight
JOIN fight_me f_m ON f_m.fight_id_fight = f.id_fight

WHERE f.time = (SELECT MAX(pomF.time) FROM fight pomF WHERE pomF.id_fight = f_e.fight_id_fight)
GROUP BY f_e.nick
ORDER BY f.time DESC"


hadze to daky error ?
dabelik (110)|5.4.2011 20:07
Ahoj,

myslím, že som to už aj takto predtým skúšal a síce nevyhodí to žiaden error ale stále to selectuje ako "MIN" než "MAX" date. Myslím, že som zle navrhol databázu alebo čo, nieje možné aby to robilo takéto problémy :(
Pabler (425)|5.4.2011 21:41
neviem ako vyzera cela DB, no pride mi kusok "naopak"

osobne by som robil tabulku s hracmi ...

Player (Table)
(PK_ID_Player)
--------
+ jeho dalsie data


a udaje o boji reprezentoval ako m:n vazbu medzi tablukami Player >-< Player (medzi tou istou tabulkou)
kde by potom ako privatny kluc figuroval kompozitny key

-------------------
ID_player_attacker
ID_player_victim
timeOfFight
-------------------
+ dodatocne data pre boj


----------------------------------
este ma napada daco s kurzorom, .... najprv otazka:

Tab2::fight_enemy
(PK)id_enemy, (FK)fight_id_fight, nick, gold, experience
1, 1, enemy1, 0, 0
2, 2, enemy2, 0, 0
3, 3, enemy1, 70, 0

id_enemy je PK
enemy nick nie je rovnaky pri kazdom Id_enemy ?

lebo mam teraz nejasno, ci urcujes o akeho hraca ide len podla jeho "nick" a id_enemy je len umely private key (zrejme autoincrement)

alebo prave platí ze id je spate s nickname, a id_enemy jednoznacne reprezentuje dakeho hraca, ... bo v takom pripade sa kazdy hrac s is_enemy moze do boja zapojit len raz
dabelik (110)|5.4.2011 21:54
Tak asi bude najlepšie skúsiť popremýšľať o zmene databázy. Ale máš pravdu, id_enemy je len AI (auto_increment). Mne tie vzťahy už na škole robili problémy, stále som si to ináč vysvetlil a potom nevzniknú dostatočne efektívne tabuľky. Vďaka ti teda za rady :)
Pabler (425)|5.4.2011 22:54
SELECT OFE.nick
FROM fight_enemy OFE //--Outer Fight Enemy
WHERE OFE.id_Fight =
(
SELECT id_fight
FROM Fight F, Fight_Enemy FE
WHERE f.id_fight = fe.id_fight
AND fe.Nick = ofe.Nick
AND fe.time =
(
SELECT max(time)
FROM Fight ff, fight_enemy ffe
Where f.id_fight = ffe.id_fight
And ffe.nick = OFE.nick
)
)


No tak henten select (ak taku nechutnost este mozem tak pomenovat :) ), by ti "mal" dat ten nick co si chcel, ... vdaka tym opacnym id, sa ti to rozbija tak ako nechces, .... a kedze treba viazat z opacnej strany a podmienovat podla mena, ...

kratko povedane vysvetlenie " zobraz nick ktory obsahuje id_fight rovny id_fightu do ktoreho sa zapojil moj nick, a ten fight ma najvyssi cas z tych do ktorych sa moj nick zapojil ..."

dalsi neprijemny dosledok, ak vonkajsi select previazes s inou tabulkou, tak to zacne davat inaksie vysledky, lebo to zacne rozbijat, ... ak by si chcel vypisat cas boja, tak za OFE.Nick, by siel dalsi vnoreny select, kde by sa selectol time s podmienkou where(aliasFE.id_fight = OFE.fight)

Pokial mas moznost zmenit databazu, tak ju radsej zmen, ... uz jeden vnoreny select je podla niektorych ludi prasarna kvoli degradacii vykonu, ...
napr v Oracle odporucaju, ak uz vnoreny select, tak ho aspon napisat pomocou In, Exists //pricom sa ma clovek snazit radsej pouzit exists kvoli lepsej optimalizacii dotazu zo strany ich cost based optimalizera ...


Co sa tyka tych vztahov, odporucam poriadne pozriet, navrh od toho zavisi,
darmo sa tymto databazam nehovori Relacne (Relationship-vztah)
na autoincrement pk nie je nic zle, len musí byt s niecim spojene (1PK pre jednu entitu)

taka pomocka autoincrement je vhodny tam kde neexistuje prirodzeny privatny kluc, alebo privatny kluc tvoria mnoziny vela atributov,... vtedy je ich vhodne nahradit umelym klucom, no pri vkladani davat pozor aby nevznikla ta ista entita s dvoma klucmi ....

pekny priklad

Meno, priezvisko, adresa (menovcov neuvazujeme, ine udaje dostupne nemame)

PK mozu tvorit tieto tri, no je vhodne nahradit AI

0, jozo, mrva, brno....
1, peter, mrva, brno...
2, jozo, mrva, praha...
3, jozo, mrva, brno... <------ DTB s AI to umozni, lebo su to pre neho rozne data, no prave tomuto musime zabranit, napr trigger on insert co skontroluje ci taka kombinacia uz neexistuje .....

prajem vela zdaru
grafnev (69)|12.4.2011 11:27
Pokud vezmu váš původní dotaz mohu vytvořit následující SQL:

Select vyberie všetky súvisiace dáta ako potrebujem avšak vyberá prvý výskyt v DB, totiž v tabuľke fight sú informácie o čase zápasu a pod., v tabuľke fight_enemy sa nachádzajú duplicitné údaje (boj s rovnakým protivníkom) a ja by som potreboval vybrať len raz (unikátne) nick protivníka (preto som dodal GROUP BY) ale dáta z posledného boja (akosi neviem kde zahrnúť podmienku aby vybrala DB zápas, ktorý má "MAX(fight.time)"). Netuším či som to dostatočne zrozumiteľne vysvetlil ale napadá niekoho nejaké možné riešenie?

1) Potřebujete unikátní nick protivníka:
Mimo jine podle struktury tabulky unikatni nick neni, pouze unikatni ID
[code]
select distinct
nick
,id_enemy
from fight_enemy
[/code]

2) Potrebujete k nemu dotahnout zapas s maximalnim casem, toto bude delat divne veci, pokud mohou byt dva zapasy v jednom case. Nejprve vybereme ke kazdemu id maximalni cas zapasu ... a pak zpet k maximalnimu casu vybereme id_zapasu. Ted kdyz na to koukam, tak vlastne neni potreba ani ten select distinct z predchoziho kroku, protoze tento obsahuje jednou kazde id_enemy, ktere melo nekdy zapas.
[code]
select -- vysledek je id posledniho zapasu (pokud nemohou mit 2 zapasy stejny cas) ke kazdemu id_enemy
max_cas.id_enemy
f.id_fight
from fight as f
inner join ( -- tento vnitrni select vybere ke kazdemu id_enemy maximalni cas zapasu
select
id_enemy
,max(time) as maxtime
from fight as fi
inner join fight_enemy as fe on (fi.fight_id_fight eq fi.fight_id)
group by id_enemy
) max_cas
on (f.time eq max_cas.max_time)
[/code]

3) A ted lze ty predchozi selecty pouzit jako zdroj pro dalsi ... nebudu to psat uz bych tam nasekal moc chyb ... pri ladeni je dobre si kazdy ten select udelat do tabulky nebo do view odladit a na konci v tom poslednim selectu dosadit misto view ten kod.


WHERE f.time = (SELECT MAX(pomF.time) FROM fight pomF WHERE pomF.id_fight = f_e.fight_id_fight)

Tohle by nemelo fungovat protoze v tom vnitrnim dotazu neni definovan alias f_e (mozna ze to ma mysql nejak osetrene, ale ve standardnim sql to nejde. Navic tam chybi k tomu maximu agregace (group by).

Co se tyka struktury databaze, tak nevim co presne chcete delat, takze me ani nenapada nejaka optimalizace ... ale to co mate nevypada uplne spatne ... akorat nick a id_enemy by si asi zaslouzilo svoji vlastni tabulku.

Pokud naspecifikujete presne co chcete a date struktury muzeme ten dotaz klidne dotvorit.

P.S.
darmo sa tymto databazam nehovori Relacne (Relationship-vztah)
Relační databáze se nazývají relační, protože nad nimi lze provádět relační opearace ... neboli tabulky jsou v matematicke relaci.
dabelik (110)|12.4.2011 16:11
Ahoj,

skúsil som znovu vytvoriť návrh DB a postupoval som takto:

1) Rozpísal som si dáta, s ktorými budem pracovať:
- fight, time, link, win, nick, clan, gold, experience, level, fight_value, power, defense, skill, stamina, charisma, hit_chance, chance, injury, energy_btf, energy_atf, attacker

2) Dáta rozdelil do skupín a vyšli mi tri tabuľky:
- player => nick (PK), clan
- player_skill => id_player_skill (PK, AI), level, fight_value, power, defense, skill, stamina, charisma, hit_chance, chance, injury, energy_btf, energy_atf
- fight => fight (PK), time, link, win, gold, experience, attacker

3) Určil si požiadavku na dáta:
- zoznam zápasov pre každý nick, ktorý mal so mnou zápas usporiadaný podľa času

4) Určil vzťahy medzi tabuľkami:
- player - player_skill => 1:n
- tab.1: Koľko vlastností môže mať jeden hráč? Práve jednu čiže 1.
- tab.2: Koľko hráčov môže mať takéto skúsenosti? Viacerí čiže n.
- player - fight => 1:n
- tab.1: Koľko práve takých zápasov môže mať jeden hráč? Práve jeden čiže 1.
- tab.2: Koľko hráčov môže mať práve taký zápas? Dvaja čiže n.

5) Doplnil som FK do tabuliek na základe bodu 4.:
- player_skill => player_nick (FK)
- fight => player_nick (FK)

Myslíte, že takýto návrh by mohol svižnejšie fungovať?

Vopred vďaka za reakcie, s pozdravom striky..
grafnev (69)|12.4.2011 21:01
1) No jdes na to podle me ze spatneho konce ... zkus si nejprve napsat co chces ... typu:
Potrebuji vytvorit databazi pro hru. Hra spociva zapaseni jednotlivych hracu mezi sebou. Zapas vypada tak ze ... atd...

Z toho si pak muzes udelat seznam co vsechno potrebujes ... prvni nastrel se dela, ze podstatne jmeno je atribut a sloveso je vztah mezi tabulkami (treba: zapas, hrac ... hraci zapasi). Podle me najdes spoustu veci na ktere bys jinak zapomnel.

2) V bode 4 to je nejake popletene (pokud vlastnost = skill) tak player -> skill 1:n znamena ze jeden hrac muze mit nekolik skillu. Nicmene v realu to je M:N jeden hrac muze mit vice skillu jeden skill muze mit vice hracu ... resi se to vazebni tabulkou.

3) Nektere veci nejsou jasne, tak to napisu tak jak si myslim ze to je pripadne me muzes opravit (budu pouzivat anglicke vyrazy at se to neplete).

Tohle si myslim ze tu je napsane:
Player ma nekolik udaju - prislusnost ke clan
Player muze mit nekolik skill
Player muze zapasit s jinym player to je fight
Fight ma nekolik udaju - time, link, win, gold, experience, attacker
Skill ma nejake vlastnosti/parametry - level, fight_value, power, defense, skill, stamina, charisma, hit_chance, chance, injury, energy_btf, energy_atf

Tohle mi chybi:
Clan ma nejake udaje - nazev

Dale nevim jestli parametry skill zavisi nejak na hraci, predpokladam ze ne.

Takze by mi z toho vychazelo - nejprve entity a atributy
player (player_id (pk), player_name)
skill (skill_id (pk), skill_name, parametry ....)
fight (fight_id (pk), time, gold ...)
clan (clan_id (pk), clan_name ...)


Ted bych to propojil (propojovaci tabulky):
a) hrac patri do nejakeho klanu - tady si lze zvolit cizi klic ke hraci, protoze patri prave do jednoho klanu, nebo udelat propojovaci tabulku ... dame cizi klic do tabulky player
player (player_id (pk), player_name, clan_id (fk) )
b) hrac ma nekolik skillu - predpoklad je, ze parametry skillu nezavisi na hraci
zalozime tabulku player_has_skill (player_id (pk), skill_id (pk)) ta nam propoji ciselnik skillu s hraci
c) to nejtezsi budou asi ty souboje
zde jsou ruzne moznosti
- bud do tabulky fight doplnit player_id kteri bojovali (zde se ale dopoustime rozliseni na prvniho a druheho player_id a to nemusi byt spravne a komplikujeme si s tim vybery)
- vyrobime tabulku s informaci, ze se hrac ucastnil fightu player_had_fight (player_id(pk), fight_id(pk)) - nevyhoda je trosku slozitejsi dotaz, vyhoda je ze lze rozsirit system na 2 hrace.

Dale pokud time nema zadny fyzikalni vyznam (pepa hral v 17:35) lze podle me nahradi nejakym poradovym cislem zapasu ze sekvence.

Vazby jsou
player - clan 1:1
player - player_has_skill 1:N
player_has_skill - skill N:1
player - player_had_fight 1:N
player_had_fight - fight N:1 (pro 2 hrace by to bylo 2:1)

Neresim ted constrainty ty v praci nepouzivam, takze o nich nemam aktivni znalost, ale mely by osetrit ruzne veci jako, ze jednoho zapasu se ucastni 2 hraci atd. ale to lze udelat az nakonec.

Jinak je to vymyslene na kolene uz jsem to dlouho nedelal, takze jsem toho hodne zapomnel ... u veci, ktere byly v predchozim prispevku nejednoznacne jsem si vybral nejaky vyznam. Kdyztak dovysvetli (idealne napiste slovy co to ma byt) a poresime.
dabelik (110)|12.4.2011 23:21
Ahoj,

budem reagovať postupne na tvoje body..

1) Zaujímavý poznatok o podstatných menách a slovesách (vďaka do budúcna), avšak je nutné dodať že DB je tvorená pre čisto len štatistiku z hry do ktorej "nevidím" (kódovo). Dáta získavam šikovnosťou simple_html_dom, nakoľko cieľom je vytvoriť vlastnú štatistiku bojov (sú ľudia, ktorí majú dostatok rozumu aby neplatili premium účty).

2) Uznávam, že asi takto by to pochopil každý ale je to myslené tak, že hráč má práve také vlastnosti (jeden riadok), ktoré získam z website hry ale môže sa naskytnúť, že presne rovnaké by mal ešte ďalší hráč a preto mi vyšiel vzťah n (i keď to by chcelo obrovskú dávku náhody, kvôli percentuálnym vyjadreniam istých hráčskych vlastností).
EDIT: Pri písaní nižšie uvedeného bodu "c)" v časti prepojenia tabuliek som si uvedomil niečo dôležité a síce to, že tie vlastnosti sa musia ukladať pre každý zápas znovu a znovu. Nakoľko štatistika bude pre každý zápas a teda keby som uložil iba raz a následne ich UPDATE-oval pre daného hráča tak by to už nesedelo lebo pre každý zápas mal daný hráč stále rovnaké hodnoty týchto vlastností. Čiže ešte aj tu bude zrejme musieť pokutovať FK od tabuľky fight.

3) Dobrá poznámka, pozabudol som že vlastne viacerí budú môcť patriť do istého clanu takže tabuľka s clanom je dobrá pripomienka a tá bude obsahovať iba názov clanu, nič viac.

Prejdem tie veci, ktoré si myslíš že sú:
Player ma nekolik udaju - prislusnost ke clan => áno (nick a clan)
Player muze mit nekolik skill => áno (ALE môže mať iba 1. riadok pre daný zápas)
Player muze zapasit s jinym player to je fight => áno (boj sa skladá z dvoch hráčov)
Fight ma nekolik udaju - time, link, win, gold, experience, attacker => áno (time - čas kedy bol zápas odohraný yyyy-mm-dd H:i:s, link - url z ktorého sú dáta vďaka simple vytiahnuté, win - výhra/prehra, gold - získané zlato, experience - získané skúsenosti, attacker - či som útočník ja alebo zaútočil niekto na mňa)
Skill ma nejake vlastnosti/parametry - level, fight_value, power, defense, skill, stamina, charisma, hit_chance, chance, injury, energy_btf, energy_atf => áno (vlastnosti tvorí jeden riadok pre daného hráča a daný boj)

Takže výsledok by bol:
player (player_id (pk), player_name) // Mimochodom, prečo nemôže byť PK zvolený nick? Stále sa musí jednať o dátový typ Integer?
skill (skill_id (pk), parametry ....)
fight (fight_id (pk), time, gold ...)
clan (clan_id (pk), clan_name ...)

Prepojenie tabuliek:
a) Súhlasím, to by sedelo..
b) Tu už to nesedí nakoľko som (dúfam dobre) vysvetlil prečo nie.
c) Potreboval by som selektovať dáta podľa toho s kým som mal zápas, resp. vyselektovať všetky zápasy pre všetkých nepriateľov a pod. takže asi by bol lepší ten druhý spôsob len či sa budú dať potom vyťahovať dobre dáta, to už netuším. Napríklad vytiahnuť pre každé enemy čo so mnou malo zápas, jediný a síce posledný zápas (podľa time) a k nemu všetky súvisiace údaje (aké mal u daného zápasu, daný hráč vlastnosti/player_skill).

Myslím, že som sa v tom trošku zamotal a som unavený tak ak som to ešte viac poplietol tak mi povedz a zajtra to zbúcham do zrozumiteľnejšieho jazyka :)

Ďakujem ti za tvoju snahu, s pozdravom dabelik..
grafnev (69)|13.4.2011 11:22
Aha, myslim si ze jsem nepochopil toto:

Ja jsem bral skill jako dovednost ... tzn. napr. veci jako double kick, fireball apod. ... ale ty beres asi skill jako vlastnost ... tzn. sila, brneni atd.

Z toho plyne: Bod 2) To ze by nahodou nekdo mel stejne hodnoty bych vubec neresil, proste kazdy hrac ma svuj radek informaci o parametrech.

Pokud vezmu skilly timto zpusobem (tj. sila, brneni, zivoty), tyto udaje se ale meni zapas od zapasu.
Takze nejjednodussi (a nejmene elegantni) reseni je to priplacnout k player_had_fight, na tuto situaci se to asi hodi, protoze kdyz budes potrebovat dalsi vlastnost tak proste pridas dalsi radek. Mozna se ty zaznamy o vlastnostech nebudou moc lisit, ale to neva pro takovy ucel. Nevyhoda je, ze nemuzes mit zaznamenane skilly pro hrace, ktery nikdy nebojoval je to takove neciste reseni.
player_had_fight(fight_id(pk), player_id(pk), parametry skillu)

Protoze delas vicemene nejake chytrejsi udelatko z nejake hry tak podle zkusenosti co mam je dobre se vydat co nejjednodussi cestou bez ohledu na to jak ta dabaze pak bude nehezka.
Jine by to bylo, kdybys to pak chtel pouzivat dale a rozsirovat, pak je dobre venovat navrhu vetsi pozornost.


Ad bod c) Pokud ty udaje dobre pospojujes a promitnes tam vsechny vlastnosti a vazby tak jak jsou ve skutecnosti muzes provest dotaz na vsechno. Rozhodne bych ale nijak ve strukture nerozlisoval tebe a ostatni ... to se udela az pak pri vyberu.


Az budes delat nejaky dotaz, tak si ho take napred naformuluj slovne, pak ho rozhod na kousky a pak naprogramuj.
Priklad:
chci vypsat vsechny me posledni zapasy pro kazdeho soupere se kterym jsem bojoval.

Vidim tam: Vsechny me zapasy
Vidim tam: Posledni zapasy
Takze kdyz vsechny me zapasy spojim s poslednimi zapasy budu mit vysledek.

Pozn. A tady vidim nedokonalost toho co jsem navrhl, pri pripojovani hracu a zapasu si musim davat pozor abych nepripojil sam sebe, respektive stejneho hrace. U zapasu 2 hracu proti sobe to je v pohode, kdyz jich bude vice budu mit problem: Pokud spolu budou najednou bojovat hraci A, B, C tak pri propojeni dostanu dvojice AB AC BC.


[code]
select
p1.player_id as player1
,p2.player_id as player2
,p1.fight_id
,f.*
-- Takze nejprve vyberu vsechny bojojici dvojice, davam pozor abych neparoval sebe na sebe
from player_had_fight as p1
inner join player_had_fight as p2
on (p1.fight_id eq p2.fight_id
and p1.player_id ne p2.player_id)
-- K tem dvojicim klidne pripojim udaje o boji, je jedno jestli id vezmu z p1 nebo z p2
inner join fight as f on (p1.fight_id eq p2.fight_id)
[/code]

Tak a tady je to konkretne videt: Tento dotaz mi vybere kazdy zapas 2x a to takhle:

hracA, hracB, zapas152
hracB, hracA, zapas152

Protoze ted konkretne chci abych jeden hrac byl ja, tak to nevadi vyresi to pridani
[code]
where player1 eq moje_id
-- pripadne where player2 eq moje_id
[/code]

Kdybych chtel vybirat vsechny zapasici dvojice tak muzu vyuzit toho, ze id je cislo a pozmenit parovaci podminku takto:
[code]
inner join player_had_fight as p2
on (p1.fight_id eq p2.fight_id
and p1.player_id LT p2.player_id)
-- misto nerovnosti jsem dal mensi nez, takze player 1 bude mit id vzdy mensi nez player 2 a nebudou se mi tvorit prohozene dvojice
[/code]

Po vsech upravach mam tedy tento select, jeste upravim vyber hrace podle nicku
- vsechny moje souboje se vsemi souperi
[code]
select
p1.player_id as player1
,p1.nick as muj_nick
,p2.player_id as player2
,p2.nick as souperuv_nic
,p1.fight_id
from player_had_fight as p1
inner join player_had_fight as p2
on (p1.fight_id eq p2.fight_id
and p1.player_id lt p2.player_id)
inner join fight as f on (p1.fight_id eq p2.fight_id)
where p1.nick eq 'muj_nick'
[/code]

Ted chci ale posledni souboj, ten se urcuje podle casu pro kazdeho hrace

[code]
-- dvojice player a cas posledniho zapasu.
select
id_player
,max(time) as last_player_fight
from player_had_fight as p
inner join fight as f on (p.fight_id eq f.fight_id)
group by id_player
[/code]

A pak cely tento select pouziju k ziskani prislusneho posledniho zapasu a doplnim ho do predchoziho selectu, protoze chci posledni
zapas me a soupere, pripojuji k souperi
[code]
select
p1.player_id as player1
,p1.nick as muj_nick
,p2.player_id as player2
,p2.nick as souperuv_nic
,p1.fight_id
from player_had_fight as p1
inner join player_had_fight as p2
on (p1.fight_id eq p2.fight_id
and p1.player_id lt p2.player_id)
inner join fight as f on (p1.fight_id eq p2.fight_id)
-- vybereme pouze posledni zapasy
inner join (
select
id_player
,max(time) as last_player_fight
from player_had_fight as p
inner join fight as f on (p.fight_id eq f.fight_id)
group by id_player
) as lf on (lf.id_player eq p2.id_player and f.time eq last_player_fight)
where p1.nick eq 'muj_nick'
[/code]
V maximalnim casu nemusime hledat fight_id protoze tabulka fight by mohla mit i klic player, time ... protoze hrac nemuze mit v jednom case vice
zapasu ... problem vyvstava, ze dva hraci maji v jednom case zapas (mezi sebou), to nam ale v tomto pripade nevadi, protoze nas zajima posledni
zapas soupere.


Pozn. eq (equal) pouzivam misto =, lt (lower then) misto <, le (lower equal) <=, gt (greater then) >, ge (greater equal) >= ... jen muj zvyk
dabelik (110)|30.4.2011 20:14
Ahoj,

pardon za malé odmlčanie ale ak sa dívaš na fórum dosť som riešil a ešte aj riešim svoj new NB ale to sem nepatrí :) ..

Prečítal som si to celé a hádam som sa z toho dostatočne dobre ,,vysomáril" a pridávam screen z návrhu DB aby som predišiel zbytočnej snahe a komplikáciám zo selektov, tak ťa prosím o prekontrolovanie ak sa ti podarí ešte dostať do obrazu tejto šlamastiky :)

S pozdravom a vďakou, dabelik..
mydb.png
grafnev (69)|30.4.2011 23:47
No ja nemam porad uplne predstavu k cemu presne ta databaze je. Vypada to celkem OK, jeste se zkusim zamyslet.
Co v fight znamena attacker, expy, gold, win ... to jsou nejake parametry toho zapasu nebo to co hrac vyhral? Je to stejne pro oba soupere? Neboli je to vsechno vlastnost toho zapasu?
Co presne znamenaji ty jednotlive atributy?
dabelik (110)|30.4.2011 23:54
[quote=grafnev;448844]No ja nemam porad uplne predstavu k cemu presne ta databaze je. Vypada to celkem OK, jeste se zkusim zamyslet.
Co v fight znamena attacker, expy, gold, win ... to jsou nejake parametry toho zapasu nebo to co hrac vyhral? Je to stejne pro oba soupere? Neboli je to vsechno vlastnost toho zapasu?
Co presne znamenaji ty jednotlive atributy?[/quote]


Tak postupne:
attacker -> typ integer (0/1) - Znamená či som zaútočil ja alebo protivník útočil na mňa.
win -> typ integer (0/1) - Znamená či som zápas vyhral alebo prehral.
gold -> typ integer - Určuje hodnotu získaného zlata v zápase resp. strateného zlata.
experience -> typ integer - Určuje hodnotu získaných skúseností (ak je protivník vyššieho levelu ako ja alebo vyššej bojovej hodnoty a zápas som vyhral resp. celé naopak znamená pre protivníka)
grafnev (69)|1.5.2011 00:37
Uz jsem unavenej, tak to ber s rezervou, jeste se nad tim zamyslim:
V tom pripade je tabulka fight chybne protoze se na jeden fight pripojuji oba hraci a nepujde rozlisit koho se informace tyka. Mohlo by se to vyresit takto:
Vsechny polozky, ktere se tykaji jednoho hrace pri boji (skilly, expy, vitezstvi, prohra atd.) se daji do jedne tabule (prakticky se bude jednat temer o slouceni player_had_fight a fight) ... tuto tabulku bych nazval treba fight_results_parameters nebo tak ... protoze jsou v ni parametry a vysledky boje ... kdyz nad tim premyslim tak bych tam dal klidne i cas zapasu a cizi klic zpet do tabulky hracu pro soupere.
dabelik (110)|1.5.2011 12:12
[quote=grafnev;448847]Uz jsem unavenej, tak to ber s rezervou, jeste se nad tim zamyslim:
V tom pripade je tabulka fight chybne protoze se na jeden fight pripojuji oba hraci a nepujde rozlisit koho se informace tyka. Mohlo by se to vyresit takto:
Vsechny polozky, ktere se tykaji jednoho hrace pri boji (skilly, expy, vitezstvi, prohra atd.) se daji do jedne tabule (prakticky se bude jednat temer o slouceni player_had_fight a fight) ... tuto tabulku bych nazval treba fight_results_parameters nebo tak ... protoze jsou v ni parametry a vysledky boje ... kdyz nad tim premyslim tak bych tam dal klidne i cas zapasu a cizi klic zpet do tabulky hracu pro soupere.[/quote]

Podľa mňa je správne lebo stále budem jeden z tých dvoch hráčov ja a tie vlastnosti, ktoré som vymenoval sa týkajú v každom zápase len mňa. Čiže z toho stále budem vedieť či som vyhral/prehral a ak prehral tak zapísaná hodnota goldov (ktoré som stratil) vyselektujem ako zápornú hodnotu pomocou IF. Len ma ešte zaujíma či vzťah medzi tabuľkou player - clan (1:1) je správne keď clan môže obsahovať viacerých členov, tak by to mal byť 1:n, nie?
grafnev (69)|1.5.2011 21:06
Vztah mezi hrácem a klanem je samozřejmě 1:n, ono to celkem vyplývá z toho, že clan_id je cizí klíč pro player, takže tam jedno id může být víckrát.

Jinak v tom, že stále rozlišuješ hráče na Tebe a ostatní hráče děláš trochu chybu. Jednak ta databáze není tak postavená, protože pak by Ti stačila jedna tabulka do které si uložíš vše (atributy, výsledky, členství soupeře v klanu, čas zápasu) prostě jednoduchý excel. A druhak si zbytečně omezuješ možnosti, třeba když to bude chtít použít kámoš, nebo když si založíš druhou postavu.

Ono to bude špatně i z hlediska správného návrhu databází, protože pokud připojím hráče k fightu (připojej se mi tam samozřejmě 2) tak bez nějaké dodatečné informace (výsledky se týkají hráče, který jsem já) nevím koho se ty informace týkají.

Pokud chceš zachovat ten pohled "ty vs. ostatní" tak bych doporučoval styl excel, jinak bych radši upravil návrh směrem k univerzálnímu použití a jednoznačnému významu atributů.




P.S. Jestli vadí tykání tak se omlouvám, stejně tak přeskakuju sem a tam.
dabelik (110)|1.5.2011 21:42
Myslím, že chápem čo sa mi snažíš vysvetliť a teda ako vlastne si predstavuješ návrh DB? Pridá sa tam fight_results? A tá vlastne bude s kým prepojená? Iba s player a fight nie? Či?

Neviem či sa ti chce ale mohol by si mi urobiť taký ten finálny náčrt? Myslím, že tak ako je aj ostane len zmením ešte ten vzťah medzi clan - player a ak dobre chápem tak sa pridá teda tabuľka fight_results, ktorá sa prepojí ako som hovoril vyššie s tab. player a fight. Síce neviem k nim vzťahy ale tak by to malo byť vcelku optimalizované, nie?

P.S.: Nie, to vôbec nevadí ale teraz sa ťažko rozmýšľa keď prehrávame 3:0 proti nemcom :/ ..
grafnev (69)|2.5.2011 10:49
Tabulka player zustava
clan zustava

player_had_fight prejmenovat (pokud chces) na fight_results a do ni dat win, gold, xp ... atd. z fight, proste veci ktere se tykaji hrace

v tabulce fight zustane pouze fight_id, fight_time a asi link ... proste veci, ktere se tykaji pouze zapasu
dabelik (110)|2.5.2011 11:00
Ahoj,

takže asi vo finálnej verzii by to mohlo vyzerať takto:
player - clan (1:n)
player - fight_result (n:1)
fight_result - fight (1:n)

Ostatné info priložené v prílohe (screen z návrhu DB)..

Uvidíme či sa to ujme, snáď áno :)
mydb2.png
grafnev (69)|2.5.2011 11:16
1) V tabulce clan nema byt player ID
2) V tabulce player ma byt clan ID
3) V tabulce fight_results musi byt fight_id a player_id
4) V tabulce fight nema byt fight_results_player_had_fight
5) Otocena vazba mezi clan a player a mezi fight a fight result
grafnev (69)|2.5.2011 11:18
jinak kardinalita
Jeden klan muze mit vice clenu
1 clan n player
clan - player (1:n)
do player umistim cizi klic do clan
dabelik (110)|2.5.2011 11:28
Jop, hovoril som si, že to naopak robím ale niečo mi hovorilo aby som to nechal tak :D

Takže oprava, screen v prílohe..
mydb3.png
grafnev (69)|2.5.2011 11:48
1) Clan Id ve fight results nema byt, je v playerovi
2) Nevyznam se moc v tech ikonkach, ale:
player ma klic player_id a nic jineho, ostatni jsou cizi klice
fight_results ma klic fight_result_id a ostatni jsou cizi klice
dabelik (110)|2.5.2011 11:51
[quote=grafnev;449143]1) Clan Id ve fight results nema byt, je v playerovi
2) Nevyznam se moc v tech ikonkach, ale:
player ma klic player_id a nic jineho, ostatni jsou cizi klice
fight_results ma klic fight_result_id a ostatni jsou cizi klice[/quote]

1) To pridalo samo po tom ako som pridal vzťah 1:n medzi player - fight_result, tiež nechápem prečo ale tak dám to preč teda..
2) Všetko sedí. Úplne hore sa zobrazuje primárny kľúč a dole foreign keys..
dabelik (110)|3.5.2011 00:04
Nuž nešiel už EDIT príspevku tak len dodám, že pri snahe vložiť hráča do tabuľky player bez toho aby existoval akýkoľvek záznam o clane (nie každý hráč musí mať clan) tak to skončí errorom o FK clan_clan_id, aj keď som sa mu snažil postrčiť nulu tak sa mu to nepozdávalo. Mimochodom ako by si riešil unique nick hráča? Iba overovať či sa už v DB nachádza a basta? :)

P.S.: Prikladám ss..
mydb4.png
grafnev (69)|3.5.2011 10:15
Ten nastroj ve kterem to delas, ti tam vyrabi nejake constrainty ... pravdepodobne tam je rozdil mezi povinnou a nepovinnou vazbou. To ze hrac nemusi mit clan by se melo odrazit v tom, ze vazba mezi player a clan je nepovinna. Pomalu se ale dostavame na uroven toho navrhovaciho nastroje, ktery ja ale neznam, takze nemohu pomoci ... pri nejhorsim si ty tabulky vyrob rucne (vyedituj si ten skript, kterej ten program pravdepodobne vyrabi).

Pozadavek na unique nick nebyl nikde zminovan ani z pohledu databaze potreba, takze to lze osetrit treba pri zadavani nebo udelat nejake integritni omezeni.