Autor Zpráva
Lucyk
Profil
Prosím o pomoc s doplnění následujícího kódu o funkci, který by mi vypisované zkratky nahrazoval za celé názvy.

Mám tabulku, která obsahuje mj. sloupce national1, national2. V těchto sloupcích mám uvedeny zkratky CZE, SVK, SLO, RUS apod.

Níže uvedený kód je součástí vyhledávacího formuláře, který mi automaticky naplňuje option value dle aktuálního plnění v databázi. Tzn. že se vypisují CZE, SVK, SLO ...

<?php
    $rs=mysql_query("select distinct national1 as national FROM tabulka WHERE national1!='' AND national1 IS NOT NULL UNION select distinct national2 as national FROM tabulka WHERE national2!='' AND national2 IS NOT NULL ORDER BY national");
    $rows = mysql_fetch_assoc($rs);
    $tot_rows = mysql_num_rows($rs);
    if($tot_rows > 0) {
        echo "<td><select name=\"narodnost\" id=\"narodnost\" class=\"vyber\" style=\"width:100px;\">";
        echo "<option value=\"\">Any &hellip;</option>";
        do {        
            echo "<option value=\"".$rows['national']."\">".$rows['national']."</option>";
        } while($rows = mysql_fetch_assoc($rs));
        echo "</select></td>";
    }
    mysql_free_result($rs);
?>

Po delším pátrání po internetu jsem našla vzor, jak bych toho mohla teoreticky dosáhnout (funkce array), ale nedaří se mi najít správný zápis.

Zkoušela jsem níže uvedenou funkci doplnit do různých částí výše uvedeného kódu, ale buď to nefungovalo anebo to naopak zobrazovalo prázdnou rozbalovací nabídku.
$rows=Array( "CZE" => "Czech", "SLO" => "Slovak", "RUS" => "Russian",);

A nebo ještě druhý způsob zápisu o který jsem se snažila:
$rows=array();
$rows['CZE']="Czech";
$rows['SLO']="Slovak";
$rows['RUS']="Russian";

Vím, že tato skladba tabulky není nejoptimálnější, že nejlepší by bylo vytvořit samostatnou tabulku pro národnosti a tam udělat sloupečky ID - zkratka - plný název a pak to propojit s hlavní tabulkou, ale chtěla bych zatím zůstat u toho řešení, neboť bych pak ztratila přehled jaké číslo u každého záznamu nahrazuje jakou národnost apod.

Děkuji za jakoukoliv radu jak docílit výpisu s plným názvem.
juriad
Profil
Lucyk:
Pokud ti vadí, že se id v tabulce národností by byly číselné, tak ta tabulku vytvoř prostě jen s dvěma sloupci: zkratka, plný název, kde zkratka bude primární klíč.
Snadno pak získáš jejich seznam, budeš je všechny mít uložené na jednom místě a bude možné je přijoinovat k jiným tabulkám.
Mít číselné id je jen doporučení, které má za úkol usnadnit updaty v případě, že bys chtěl změnit zkratku, také zjednodušuje indexování, protože číslo je téměř vždy menší než text.
Lucyk
Profil
juriad:
Tak jsem vytvořila následující tabulku, ale nedaří se mi ji přijoinovat ke stávajícímu dotazu.

Nově vytvořená tabulka narodnost se sloupečky zkratka a nazev.

Ve výše uvedeném kódu jsem nahradila stávající dotaz následujícím:
$rs=mysql_query("select nazev as national FROM narodnost");
Vypisuje to plné názvy jak má, ale nyní jsem se zasekla, jak ji propojit se stávajícím dotazem pro vyhledávač.

Mám sestaven dotaz pro zadání jména v této podobě:
$dotaz="SELECT * FROM tabulka WHERE jmeno LIKE '$query'",

A pak k němu na základě podmínky, zda je určitý selector vybrán či nikoliv se připojuje zbytek dotazu, tzn. že v tomto případě by to mělo být něco ve smyslu:
$dotaz.=" AND national1=(SELECT * from narodnost LEFT JOIN tabulka ON narodnost.zkratka=tabulka.national1 WHERE nazev='$_POST[national]')"

Ale nefunguje mi to a hlásí to chybu např. Operand should contain 1 column(s).

Předpokládám, že jdu na to asi špatně. Neberu-li nyní v potaz, že se to snažím rozchodit zatím pouze pro national1.
Lucyk
Profil
Tak se mi to podařilo propojit, ale ještě jsem narazila na jeden zádrhel, který asi spočívá ve skladbě hlavního dotazu.

Mám tabulku seznam, která obsahuje sloupce
jmeno1, prijmeni1, jmeno2, prijmeni2, jmeno3, prijmeni3, narodnost1, narodnost2, narodnost3, rocnik1, rocnik2, rocnik3

Mám sestaven dotaz pro vyhledání jména na základě jeho zadání, tzn.
$dotaz= "SELECT jmeno1, prijmeni1, jmeno2, prijmeni2, jmeno3, prijmeni3, narodnost1, narodnost2, narodnost3, rocnik1, rocnik2, rocnik3, concat(jmeno1,' 'prijmeni1), concat(prijmeni1,' 'jmeno1), concat(jmeno2,' ',prijmeni2), concat(prijmeni2,' ',jmeno2), concat(jmeno3,' ',prijmeni3), concat(prijmeni3,' ',jmeno3) FROM tabulka WHERE ((concat(jmeno1,' ',prijmeni1) LIKE '$searchqueryname%' or concat(prijmeni1,' ',jmeno1) LIKE '$searchqueryname%') OR (concat(jmeno2,' ',prijmeni2) LIKE '$searchqueryname%' or concat(prijmeni2,' ',jmeno2) LIKE '$searchqueryname%') OR (concat(jmeno3,' ',prijmeni3) LIKE '$searchqueryname%' or concat(prijmeni3,' ',jmeno3) LIKE '$searchqueryname%'))";    

A pak mám ještě selectory pro různé sloupce, tzn. zadají jméno a žádný selector nebude vybrán (provede se základní dotaz uvedený výše) nebo zadají jméno a zároveň národnost nebo zadají jméno a ročník nebo zadají jméno, národnost a ročník.

Strukturu mám takovou, že k hlavnímu dotazu připojuji zbývající podmínky. Např. zadají jméno a zároveň ročník. Měla jsem to udělané následovně:
$dotaz.=" AND (narodnost1='$_POST[national]' OR narodnost2='$_POST[national]' OR narodnost3='$_POST[national]')"

Myslela jsem, že to bude fungovat, ale nikoliv.

V tabulce budu mít např. hodnoty:
jmeno1 - prijmeni1 - jmeno2 - prijmeni2 - jmeno3 - prijmeni3 - narodnost1 - narodnost2 - narodnost3 - rocnik1 - rocnik2 - rocnik3
Jiri - Novak - Jan - Laco - ... - ... - Czech - Slovak - ... - 1998 - 1999 - ...

Teď mi to funguje tak, že když zadám Jiri Novak a vyberu národnost Slovak, tak mi to vypíše daný řádek, ale ve skutečnosti by se nic vypsat nemělo, protože Jiri Novak je Czech, ale jelikož mám i na řádku uvedenou hodnotu Slovak, tak mi výše uvedený podmínkový dotaz nerozezná, že má pouze porovnávat buňky jmeno1, prijmeni1 a narodnost1.

Pokud bych to brala jako automatiku, že ročník musí uživatel zadat vždy, tak bych to vyřešila tak, že bych to hned dala k hlavnímu dotazu
WHERE ((concat(jmeno1,' ',prijmeni1) LIKE '$searchqueryname%' or concat(prijmeni1,' ',jmeno1) LIKE '$searchqueryname%') AND narodnost1='$_POST[national]'

Můj dotaz je, jak se nadefinuje spojovací dotaz, aby když bude splněna podmínka, že pole není prázdné, tak aby se vyhledávalo podle jmeno1, prijmeni1, narodnost1 a jmeno2, prijmeni2, narodnost2.
Keeehi
Profil
Lucyk:
Myslela jsem, že to bude fungovat, ale nikoliv.
To co jsi měla nad touto větou bylo téměř správně. Aby to fungovalo, stačilo celý where obalit do závorek. Aby po připojení té dodatečné podmínky to správně fungovalo.
Tvůj nynější stav 1 or 2 and (3 or 4)
Což se vyhodnotí, jako bys napsala 1 or (2 and (3 or 4))
Stav který chceš (1 př 2) and (3 or 4)

To by bylo k problému. Teď k návrhu tabulky. Není správný, Některé časteji řešené dotazy pro MySQL - FAQ » Musíte pojmenovávat sloupce s indexem (jmeno1, jmeno2, jmeno3, …).
Jméno, příjmení, národnost a ročník mají patřit do samostatné tabulky.

Dále mi přijde zbytečné, volat funkci concat, která bude jen zpomalovat dotaz. No a taky existují lidé, kterým se jméno a příjmení skládá z více než dvou slov. Takže bych to udělal takto: V PHP bych zadaný vyhledávaný dotaz rozdělil podle mezer na jednotlivá slova a pro každé slovo bych do dotazu přidal
 AND (jmeno LIKE '%$slovo%' OR prijmeni LIKE '%$slovo%')

No a úplně na konec tvůj kód obsahuje bezpečnostní zranitelnost, která dovoluje útočníkovi získat data z jakékoli tabulky. Vstupy od uživatele se musí vždy ošetřit, těsně před tím, než se připojí do dotazu. V tvém případě řetězce funkcí mysql_real_escape_string a u čísel stačí přetypování na číslo. Protože když to neuděláš, může útočník do vyhledávacího pole napsat něco jako ' OR 1=1 UNION SELECT nick, heslo, 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx', 'Xx' FROM admin -- a což do výpisu všech uživatelů připojí i výpis všech administrátorských účtů a hesel. Co když se tvá tabulka jmenuje jinak? Nevadí, útočník může vyzkoušet různé typické názvy. Co když se nejmenuje nějak typicky? Nevadí, existuje postup, jak získat jména všech databází, tabulek a sloupců.
Lucyk
Profil
Keeehi:
To co jsi měla nad touto větou bylo téměř správně. Aby to fungovalo, stačilo celý where obalit do závorek. Aby po připojení té dodatečné podmínky to správně fungovalo.
Myslel jsi tento dotaz? Neboť ten už v něm už mám podmínku WHERE obalenou
$dotaz= "SELECT jmeno1, prijmeni1, jmeno2, prijmeni2, jmeno3, prijmeni3, narodnost1, narodnost2, narodnost3, rocnik1, rocnik2, rocnik3, concat(jmeno1,' 'prijmeni1), concat(prijmeni1,' 'jmeno1), concat(jmeno2,' ',prijmeni2), concat(prijmeni2,' ',jmeno2), concat(jmeno3,' ',prijmeni3), concat(prijmeni3,' ',jmeno3) FROM tabulka WHERE ((concat(jmeno1,' ',prijmeni1) LIKE '$searchqueryname%' or concat(prijmeni1,' ',jmeno1) LIKE '$searchqueryname%') OR (concat(jmeno2,' ',prijmeni2) LIKE '$searchqueryname%' or concat(prijmeni2,' ',jmeno2) LIKE '$searchqueryname%') OR (concat(jmeno3,' ',prijmeni3) LIKE '$searchqueryname%' or concat(prijmeni3,' ',jmeno3) LIKE '$searchqueryname%'))";

A k ní už jsem jen přidala
$dotaz.=" AND (narodnost1='$_POST[national]' OR narodnost2='$_POST[national]' OR narodnost3='$_POST[national]')"

Zkoušela jsem ještě následující řešení, ale nevím, jestli je to přípustné a hlásí mi to chybu, kde budu mít asi chybějící závorky?
        $dotaz= "SELECT jmeno1, prijmeni1, jmeno2, prijmeni2, jmeno3, prijmeni3, narodnost1, narodnost2, narodnost3, rocnik1, rocnik2, rocnik3, concat(jmeno1,' 'prijmeni1), concat(prijmeni1,' 'jmeno1), concat(jmeno2,' ',prijmeni2), concat(prijmeni2,' ',jmeno2), concat(jmeno3,' ',prijmeni3), concat(prijmeni3,' ',jmeno3) FROM tabulka WHERE 
          (((concat(prijmeni1,' ',jmeno1) LIKE '$searchqueryname%' or concat(jmeno1,' ',prijmeni1) LIKE '$searchqueryname%')(($national)?' AND narodnost1=(SELECT distinct narodnostl1 FROM tabulka LEFT JOIN narodnost ON narodnost.zkratkanarodnosti=tabulka.narodnost1 WHERE narodnost.nazevnarodnosti='$national')':''))
        OR ((concat(prijmeni2,' ',jmeno2) LIKE '$searchqueryname%' or concat(jmeno2,' ',prijmeni2) LIKE '$searchqueryname%')(($national)?' AND narodnostl2=(SELECT distinct narodnostl2 FROM tabulka LEFT JOIN narodnost ON narodnost.zkratkanarodnosti=tabulka.narodnost2 WHERE narodnost.nazevnarodnosti='$national')':''))
        OR ((concat(prijmeni3,' ',jmeno3) LIKE '$searchqueryname%' or concat(jmeno3,' ',prijmeni3) LIKE '$searchqueryname%')(($national)?' AND narodnost3=(SELECT distinct narodnost3 FROM tabulka LEFT JOIN narodnost ON narodnost.zkratkanarodnosti=tabulka.narodnost3 WHERE narodnost.nazevnarodnosti='$national')':'')))";        

A když uživatel zadá jméno, tak to hlásí:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '((Czech)?' AND narodnost1=(SELECT distinct narodnostl1 FROM tabulka LEFT JOIN narodno' at line 2

Tento kousek kódu by vyhodnocoval, zda byla zadána proměnná $national
(($national)?' AND narodnost2=(SELECT distinct narodnost2 FROM tabulka LEFT JOIN narodnost ON narodnost.zkratkanarodnosti=tabulka.narodnost2 WHERE narodnost.nazevnarodnosti='$national')':'')
Lze něco takového udělat přímo v selectu?

Dále mi přijde zbytečné, volat funkci concat, která bude jen zpomalovat dotaz. No a taky existují lidé, kterým se jméno a příjmení skládá z více než dvou slov. Takže bych to udělal takto: V PHP bych zadaný vyhledávaný dotaz rozdělil podle mezer na jednotlivá slova a pro každé slovo bych do dotazu přidal
 AND (jmeno LIKE '%$slovo%' OR prijmeni LIKE '%$slovo%')
Jenže když budu mít Tebou uvedený kód na vyhledávání jména a příjmení a uživatel třeba napíše Jan Ho tak už se podmínka vyhodnotí jako false, protože pokud jsem to pochopila správně, tak se bude hledat, zda Jan Ho je obsažen ve jménu (to nebude, protože tam jsou jen křestní jména) nebo v prijmeni a tam zase se nikdy nenajde Jan.

No a úplně na konec tvůj kód obsahuje bezpečnostní zranitelnost,
Beru to na vědomí, přečtu si o tom a pak se budu snažit ošetřit finální dotaz.
Keeehi
Profil
Lucyk:
Myslel jsi tento dotaz? Neboť ten už v něm už mám podmínku WHERE obalenou
Myslel. A fakt netuším, jak se mi to mohlo povést přehlédnout. I když nepřehledně to zapsané tedy je. Fungovat by to mělo.

Základem jakéhokoli testování, bude si ten dotaz vypsat těsně před tím, než ho pošleš do databáze a překontroluješ, zda se správně sestavil.


Lze něco takového udělat přímo v selectu?
Lze to v PHP. Stačí jen vylézt z toho řetězce. + místo ($national) bude lepší !empty($national)

pokud jsem to pochopila správně
Úplně ne. Psal jsem, že to má být pro každé slovo. Proto by výsledná složená část dotazu měla vypadat:
AND (jmeno LIKE '%Jan%' OR prijmeni LIKE '%Jan%') AND (jmeno LIKE '%Ho%' OR prijmeni LIKE '%Ho%')
Čehož se dá velmi lehce dosáhnout.
$where = '';
foreach(explode(' ', $searchqueryname) as $word) {
    $where .= (empty($where) ? '' : ' AND'). " (jmeno LIKE '%".mysql_real_escape_string($word)."%' OR prijmeni LIKE '%".mysql_real_escape_string($word)."%')'";
}

Beru to na vědomí, přečtu si o tom a pak se budu snažit ošetřit finální dotaz.
Když už u toho budeš, tak k tomu přidej i rodinu funkcí mysqli_*. Funkce mysql_* byly označeny za zastaralé a v aktuální veri PHP už nejsou. Funkce mysqli_* je nahrazují a jsou velmi podobné, takže změna by neměla činit větší obtíže.
Lucyk
Profil
Keeehi:
Níže uvedený dotaz funguje, ale ne úplně správně, jak bych chtěla
$dotaz= "SELECT jmeno1, prijmeni1, jmeno2, prijmeni2, jmeno3, prijmeni3, narodnost1, narodnost2, narodnost3, rocnik1, rocnik2, rocnik3, concat(jmeno1,' 'prijmeni1), concat(prijmeni1,' 'jmeno1), concat(jmeno2,' ',prijmeni2), concat(prijmeni2,' ',jmeno2), concat(jmeno3,' ',prijmeni3), concat(prijmeni3,' ',jmeno3) FROM tabulka WHERE ((concat(jmeno1,' ',prijmeni1) LIKE '$searchqueryname%' or concat(prijmeni1,' ',jmeno1) LIKE '$searchqueryname%') OR (concat(jmeno2,' ',prijmeni2) LIKE '$searchqueryname%' or concat(prijmeni2,' ',jmeno2) LIKE '$searchqueryname%') OR (concat(jmeno3,' ',prijmeni3) LIKE '$searchqueryname%' or concat(prijmeni3,' ',jmeno3) LIKE '$searchqueryname%'))";
a k němu podmínka
if (!empty($_POST["national"])) ...  $dotaz.=" AND (narodnost1='$_POST[national]' OR narodnost2='$_POST[national]' OR narodnost3='$_POST[national]')"

Mám-li tabulku naplněnou následujícími daty:
jmeno1 - prijmeni1 - jmeno2 - přijmeni2 - jmeno3 - prijmeni3 - narodnost1 - narodnost2 - narodnost3
Jan - Novák - Peter - Suchy - ... - ... - CZE - SVK - ...
Sloupečky s číslem 1 se vztahují k jednomu jmenu, sloupečky 2 ke druhému apod.

Uživatel zadá, že chce najít Jana Nováka a je CZE. V tomto případě se to vyhodnotí správně, protože nejdříve je hledáno, zda je v databázi jméno obsahující query a pak je k tomuto dotazu dodána podmínka, že to musí být CZE, ale prohledává to narodnost1, narodnost2 a narodnost3. Ano, shodu našel.
Jenže když se zadá Jan Novák a SVK, tak aby to plnilo účel, tak by se to mělo vyhodnotit jako false, protože SVK patří ke jménu uvedenému ve sloupci jmeno2, prijmeni2. A v tento moment už můj výše uvedený dotaz nerozezná, že má přiřadit narodnost2 ke sloupečku jmeno2, prijmeni2.
Jelikož mám na řádku vedeno SVK, tak to vyhodnotí, ano našel jsem shodu Jan Novák = SVK.

Šlo by to udělat jedině tímto způsobem:
WHERE ((concat(jmeno1,' ',prijmeni1) LIKE '$searchqueryname%' or concat(prijmeni1,' ',jmeno1) LIKE '$searchqueryname%') AND narodnost1='$_POST[national]')

Ale to bych nesměla mít v selectu i možnost výběru ALL národnosti. Tahle to hází chybu, protože '$_POST[national]' je prázdný.

Vyřešila jsem to následujícím způsobem , i když uznávám, že na první pohled je to asi strašný, ale funguje, jak má.

Napsala jsem kompletní dotaz včetně všech podmínek
$dotaz= "SELECT jmeno1, prijmeni1, jmeno2, prijmeni2, jmeno3, prijmeni3, narodnost1, narodnost2, narodnost3, rocnik1, rocnik2, rocnik3, concat(jmeno1,' 'prijmeni1), concat(prijmeni1,' 'jmeno1), concat(jmeno2,' ',prijmeni2), concat(prijmeni2,' ',jmeno2), concat(jmeno3,' ',prijmeni3), concat(prijmeni3,' ',jmeno3) FROM tabulka WHERE (((concat(jmeno1,' ',prijmeni1) LIKE '$searchqueryname%' or concat(prijmeni1,' ',jmeno1) LIKE '$searchqueryname%') AND narodnost1='$_POST["national"]' AND rocnik1='$_POST["rocnik"]') OR ((concat(jmeno2,' ',prijmeni2) LIKE '$searchqueryname%' or concat(prijmeni2,' ',jmeno2) LIKE '$searchqueryname%')) AND narodnost2='$_POST["national"]' AND rocnik2='$_POST["rocnik"]') OR ((concat(jmeno3,' ',prijmeni3) LIKE '$searchqueryname%' or concat(prijmeni3,' ',jmeno3) LIKE '$searchqueryname%')AND narodnost3='$_POST["national"]' AND rocnik3='$_POST["rocnik"]'))";

a pak používám pomocí na podmínku if str_replace
if (empty($_POST["national"])) {$dotaz=str_replace(array("AND narodnost1='$_POST["national"]'","AND narodnost2='$_POST["national"]'","AND narodnost3='$_POST["national"]'"),"",$dotaz); }
if (empty($_POST["rocnik"])) {$dotaz=str_replace(array("AND rocnik1='$_POST["rocnik"]'","AND rocnik2='$_POST["rocnik"]'","AND rocnik3='$_POST["rocnik"]'"),"",$dotaz); }

Úplně ne. Psal jsem, že to má být pro každé slovo. Proto by výsledná složená část dotazu měla vypadat:
Co se týká concat funkce je nějaký zásadní rozdíl mezi mnou dočasným řešení pro zadání jména a Tvou navrhovaným? Třeba v rychlosti prohledávání apod?

Protože dle Tvého návrhu a zachování stávající struktury mé tabulky, bych musela mít celkem 3x dotaz na jméno a příjmení a v tomto momentě mi to přijde stejný, zda mám napsáno pomocí concat anebo bych to vypisovala např.:
AND (jmeno1 LIKE '%Jan%' OR prijmeni1 LIKE '%Jan%') AND (jmeno1 LIKE '%Ho%' OR prijmeni1 LIKE '%Ho%')
AND (jmeno2 LIKE '%Jan%' OR prijmeni2 LIKE '%Jan%') AND (jmeno2 LIKE '%Ho%' OR prijmeni2 LIKE '%Ho%')
AND (jmeno3 LIKE '%Jan%' OR prijmeni3 LIKE '%Jan%') AND (jmeno3 LIKE '%Ho%' OR prijmeni3 LIKE '%Ho%')
Tomášeek
Profil
Lucyk:
Nechtějí se mi porcházet ty tvoje dlouhé příspěvky výše, ale je nějaký důvod udržovat tuhle hovadskou strukturu tabulky? Proč není uživatel na samostatném řádku tabulky id/name/lastname/nationality? Pokud spolu ti tři uživatelé nějak souvisí, tak propojovací tabulka user1/user2/user3.

Dotaz bude asi desetinový, bude to o řád (nebo více) rychlejší, vyznnáš se v tom i ty - v těch tvých dotazech se nevyznáš ani ty coby jejich autor, neřkuli za nějaký pátek.
Keeehi
Profil
Lucyk:
Třeba v rychlosti prohledávání apod?
Vliv by to mít mohlo. Obzvláště v případě, že by se nepoužilo like, ale porovnávalo by se na přesnou schodu. Tam se dá využít indexů a to by mělo přinést zádové zrychlení. Pokud by se tam volala funkce (třeba ten concat) pak se indexy nemohou použít.

Ono tedy záleží, kolik záznamů v té tabulce budeš mít. Pokud to budou tisíce pak bude asi úplně jedno, jak efektivní ten dotaz bude. Když to budou miliony, má smysl řešit efektivitu. Ono to má tedy smysl řešit i u malých tabulek. V tom případě nepůjde ani tak moc o rychlost, jako o přehlednost, jak psal Tomášeek.
Lucyk
Profil
Tomášeek:
je nějaký důvod udržovat tuhle hovadskou strukturu tabulky? Proč není uživatel na samostatném řádku tabulky id/name/lastname/nationality? Pokud spolu ti tři uživatelé nějak souvisí, tak propojovací tabulka user1/user2/user3

uživatelé souvisí spolu tak, např. budu-li mít databázi knih, kde u jedné knihy mohou být 3 autoři. Takhle mám udělanou tabulku, kde bude uvedeno třeba rok_vydani/ nazev_knihy/ jmeno1/ prijmeni1/ jmeno2/ prijmeni2/ jmeno3/ prijmeni3 ...

Neumím si představit, že bych měla tabulku, kde bych měla rok_vydani/ nazev_knihy/ id_autor1/ id_autor2/ id_autor3/ ...
Když bych se na takovou tabulku chtěla podívat třeba v textovém editoru, a těch záznamů bych měla několik tisíc, tak dohledávat, jaký je autor pod určitým id. Nyní když si ji otevřu, tak mám na jednom řádku napsány všechny informace a nemusím ještě otevírat související tabulky. To je ten důvod, proč jsem už v minulosti udělala jednu velkou tabulku.

Keeehi Děkuji za objasnění týkající se použití concat. Zatím nechám dotaz v tomto stavu a v budoucnu, pokud bych se rozhodla o předělání databáze do "dílčích" tabulek, zkusím to napasovat do Tebou navrhovaného řešení.

Zkusím si ještě nyní alespoň ošetřit vstupy, snad se mi to podaří. Zkusím si vyhledat tady na foru dotazy týkající se ošetření a nějak to dám dohromady.
Keeehi
Profil
Lucyk:
budu-li mít databázi knih, kde u jedné knihy mohou být 3 autoři. Takhle mám udělanou tabulku, kde bude uvedeno třeba rok_vydani/ nazev_knihy/ jmeno1/ prijmeni1/ jmeno2/ prijmeni2/ jmeno3/ prijmeni3
Zrovna u knih a autorů to je ještě složitější, protože co když budou čtyři, nebo pět, ... Tento vztah, kdy jeden autor může mít více knih a kniha zase více autorů, bývá označován jako M:N. A implementován je pomocí tří tabulek. Tabulky pro autory a tabulky pro knihy, kde v každé jsou jen informace o té jedné věci, žádné vztahy se tam neřeší. Ten samotný vztah, že kniha patří k autorovi, nebo autor ke knize pak vyjadřuje třetí tabulka. Dost často se jí říká vazební, jelikož určuje vazby mezi autory a knihami. Tato vazební tabulka může být opravdu jednoduchá. Stačí dva sloupce, kde jeden je pro id autora a druhý pro id knihy. No a každý záznam v takové tabulce pak znamená, že autor s daným id patří ke knize s daným id a naopak.
Tebou navrhovaná možnost, že kniha by měla sloupec(sloupce) pro id autora je vztah 1:M. Typický příklad tohoto vztahu jsou komentáře k článku a jejich autoři. Jeden autor může samozřejmě napsat více komentářů, ale každý komentář ma právě jednoho autora. V takovém případě pak id autora může být uloženo u komentáře.

Když bych se na takovou tabulku chtěla podívat třeba v textovém editoru, a těch záznamů bych měla několik tisíc, tak dohledávat, jaký je autor pod určitým id.
Protože to na to není dělané. Stejně tak bych si mohl ztěžovat, že když excelovskou tabulku otevřu v textovém editoru, tak to budu složitě dohledávat. Ta informace tam taky je, ale není určena pro tento druh zobrazování.

Když použiješ něco, pro správu databází, tak to půjde mnohem lépe. A pokud tabulkám nastavíš cizí klíče, tak ty programy běžně pak sami odkazují na příslušné záznamy v souvisejících tabulkách a přechody mezi nimi jsou pak snadné. Ovšem nejlepší možnost je mít potřebný výpis přímo v aplikaci. Pak vůbec nemusíš lézt do databáze ;)
Lucyk
Profil
Keeehi:
Dobře, uznávám, že bude min. dobré udělat zvláštní tabulku pro jména a do nich zahrnout minimálně jméno, příjmení, národnost.

Jen mě pak ještě trápí jedna věc, resp. nevím, jak se s ní poprat.
To je i ten důvod, proč stále cpu na jeden řádek jméno1, jméno2, jméno3.

Co když bude tabulka typu
rok_vydani/ nazev_knihy/ jmeno1/ jmeno2/ jmeno3/ misto_psani1/ misto_psani2/ misto_psani3 ...
1999 / O Kočičce / Jan Novak / Petr Kunc / ... / ... / Praha / Brno / ...
kde jmeno1 se vztahuje k misto_psani1, jmeno2=misto_psani2.

To bych musela udělat vazební tabulku pro 3 hodnoty?
ID kniha/ ID autor/ ID misto_psani
1 / 1 / 1
1 / 2 / 2

Nebo to vyřešit pomocí JOIN na 3 tabulky by nešlo?
Keeehi
Profil
Lucyk:
To bych musela udělat vazební tabulku pro 3 hodnoty?
Ano přesně tak. V tomto případě máš 3 entity - knihu, autora a město. Entita je něco, co představuje "nějakou věc". Každou entitu reprezentuješ samostatnou tabulkou. Každý řádek tabulky pak reprezentuje už jednu konkrétní "věc".
Tím popíšeš svět své aplikace na základě co v něm je. Pro popis vazeb (vztahů) mezi jednotlivými entitami vytvoříš další tabulky. Co typ vztahu, to samostatná tabulka. Tyto vazební tabulky mají takový počet sloupců, kolika entit se tento typ vazby týká. V tomto případě je to všech tří entit, proto by měla tři sloupce.

Poznámka na okraj. Jeden vztah se klidně může týkat více záznamů v jedné tabulce. Představ si autobazar. Entity jsou Osoba a Auto. No a vztah může být kdo komu prodal jaké auto. Vazební tabulka by pak měla tři sloupce (id auto, id nakupující, id prodávající, i když máš jen 2 tabulky - auto, osoba.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0