Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: Arthur 21. 06. 2013, 11:00:18
-
Zdar,
potřeboval bych poradit kterak v dotazu zvolit parametricky tabulku dle nějaké hodnoty.
nejprve situace, kterou umím snadno řešit:
tabulka "hodnoty" :
|kod|hodnota|
--------------
|1 | 10|
|2| 50|
...
tabulka "nazvy"
|kod|nazev|
------------
|1 | PolozkaA|
|2| PolozkaB|
chci polozit takovy dotaz, aby me to vyplivlo hodnoty a nazvy podle odpovidajiciho kodu, tak se dotazu napr.:
SELECT n.nazev, h.hodnota FROM nazvy n, hodnoty h WHERE <nejake podminky> AND n.kod=h.kod
a ted tedy co potrebuju:
co kdyz budu mit kody rozdelene do skupin, napr. mala,stredni,velka, potom tabulka hodnoty bude
|skupina|kod|hodnota|
----------------------
|mala|8 | 10|
|velka|8| 50|
|stredni|2| 13|
a kazda skupina bude mit svou tabulku nazvu pro jednotlive kody :
nazvy_male
nazvy_stredni
nazvy_velke
jak mam provest vyse uvedeny dotaz, abych dostal hodnoty a nazvy podle kodu z odpovidajici skupiny ? Diky predem.
-
Vypada to dost podivne, proc nemohou byt nazvy v jedne tabulce?
Nicmene k dotazu - bud muzes sestavit text dotazu dynamicky (doplnit nazev tabulky dle situace), nebo si udelat view, ktere ti poskytne abstrakci te jakoby jedne tabulky (union dotazu z jednotlivych tabulek s rozlisujicim sloupcem s hdontami 'mala', 'velka' atd.), do ktereho se muzes dotazovat na hodnotu toho pomocneho sloupce.
-
Co třeba spojit tabulky pomoci join???
-
Například postgresql má klauzuli execute immediate, pokud je to to, co hledáš.
Nicméně, pokud tu databázi teprve navrhuješ, tak tabulky nazvy_male, nazvy_velke značí spíš špatný databázový návrh.
takže ideálně bys to měl rozdělit do tabulek:
nazvy (nazevid, nazev, skupinaid)
skupiny (skupinaid, jmeno_skupiny)
které potom při dotazech budeš spojovat pomocí (left) joinu, nebo subquery. Případně, jak navrhoval předřečník si můžeš vytvořit databázové view.
-
jak mam provest vyse uvedeny dotaz, abych dostal hodnoty a nazvy podle kodu z odpovidajici skupiny ? Diky predem.
Pouzit trojnasobny left join.
Vysledok bude hroza, ktora Vas donuti zamysliet, ci naozaj taky nezmysel potrebujete :P
-
Vypada to dost podivne, proc nemohou byt nazvy v jedne tabulce?
no jo, mohou :-) to me mohlo napadnout taky, dat skupinu jako dalsi sloupecek, viz odpoved nize :-), pac to bude nejjednosussi reseni ... neni nad to pracovat s cistou hlavou :-)
Nicmene k dotazu - bud muzes sestavit text dotazu dynamicky (doplnit nazev tabulky dle situace), nebo si udelat view, ktere ti poskytne abstrakci te jakoby jedne tabulky (union dotazu z jednotlivych tabulek s rozlisujicim sloupcem s hdontami 'mala', 'velka' atd.), do ktereho se muzes dotazovat na hodnotu toho pomocneho sloupce.
[/quote]
nicmene kdyz uz jsme u toho, jak by se tedy provedl ten dynamicky dotaz ? to je to do ceho jsem se zaboril a nevyhrabal ...
-
jak mam provest vyse uvedeny dotaz, abych dostal hodnoty a nazvy podle kodu z odpovidajici skupiny ?
Správným návrhem databáze ;-)
-
nicmene kdyz uz jsme u toho, jak by se tedy provedl ten dynamicky dotaz ? to je to do ceho jsem se zaboril a nevyhrabal ...
Provedl by se tak, jak se to udela v tvem konkretnim prostredi (o kterem jsi nic nenapsal). Obecne je dotaz text, v nemz urcita cast je nazev tabulky - tuto cast muzes mnoha zpusoby upravit a tim menit tabulku, nad kterou se dotaz provede. Dynamicnost je v tom, ze cilovy text dotazu neni predem znam (napr. pri prekladu) a tato technika se v obecnosti z vice duvodu nedoporucuje. Existuji pochopitelne i pripady, kdy dynamicke sestavovani dotazu smysl ma, konkretne ten, ktery uvadis, to as nebude.
-
Nevim presne co a na jakem prostredi to resis, ale pokud system povoluje view, tak by ti to mohlo pomoci.
Udelas view, kde budou vsechny nazvy a sloupec s identifikaci tabulky a to pak spojis tim co jsi uz napsal..
select nazev, 'tab1' from tab1
union
select nazev, 'tab2' from tab2
To ale zalezi na to co presne resis- z tveho popisu, jsem to uplne nepochopil..
Alexej
-
Souhlasim s ostatnimi, ze bude lepsi udelat spravny navrh databaze, nez takoveto silenosti. Nicmene, mozne to je pomoci prepare:
SELECT @jmeno:=(SELECT jmeno_tabulky FROM tabulka1 WHERE ... LIMIT 1);
SET @dotaz:=concat("SELECT * FROM ",@jmeno);
PREPARE mujdotaz FROM @dotaz;
EXECUTE mujdotaz;
-
SELECT n.nazev,h.hodnota from hodnoty h,
(select 'mala' as skupina,kod,nazev from nazvy_male
UNION ALL
select 'stredni',kod,nazev from nazvy_male
UNION ALL
select 'velke',kod,nazev from nazvy_velke) n
WHERE <nejake podminky> AND n.kod=h.kod AND n.skupina=h.skupina
Netestoval som to. Snad ti to pojde.
-
jak mam provest vyse uvedeny dotaz, abych dostal hodnoty a nazvy podle kodu z odpovidajici skupiny ?
Správným návrhem databáze ;-)
Přesně tak. https://en.wikipedia.org/wiki/Database_normalization . To, co, Arthure, popisuješ, smrdí průserem.
Každá aspoň trochu knížka o databázích tomuto věnuje min. 1 kapitolu. Ano, je to opruz (= nudná teorie), ale zrovna tady se to hodí. Osobně doporučuji knihu "A Developer's Guide to Data Modeling for SQL Server" (http://it-ebooks.info/book/2132/), která je velmi hezky napsaná.
-
Dík za reakce,
pro mě bohatě stačí to triviálně spojit do jedné tabulky a hotovo, na čož bych asi přišel časem taky, ale tímto nakopnutím jsem aspoň dost času ušetřil. Ta ostatní řešení jsou zřejmě pro tu mou aplikaci zbytečně komplexní ale jsem rád že o nich vím, kdybych se k tomu zas někdy dostal.
Jinak teď už dopovím spíš zbytečně, ale jedná se jednoduchou Java+MySQL aplikaci pro evidenci a počítání statistik, kde lidé na několika místech v provozu cvakají údaje a tisknou výpisy apod. Původní lokální verzi jsem kvůli úspoře vlastního času předělal do verze databázové, a teď akorát řeším optimalizace - snižování počtu zbytečných dotazů apod.
-
kde lidé na několika místech v provozu cvakají údaje
Podle toho, co jsi psal, to vypadalo spíš na nějaký školní projekt.
Pokud je to produkční aplikace, tím spíš bych pořádný návrh databáze nepodceňoval. Časem můžeš zjistit, že jsou některé dotazy, které potřebuješ, pomalé (na malém množství dat se to nemusí projevit + ta databáze může časem narůst i co do počtu tabulek atd) nebo tam budeš mít některá data 2x (anebo u ne-normalizovaných databází se můžou i ztrácet). To, že máš chybu v aplikaci snadno opravíš - sice přesvědčit uživatele, aby si nainstalovali update občas není sranda, ale lze to řešit. Nicméně když se Ti podrbou data, tak to často spravit nelze.
-
Podle toho, co jsi psal, to vypadalo spíš na nějaký školní projekt.
nene, to už je dáávno pryč :-), ani jsem nic kolem IT nestudoval, to akorát příležitostně se dostanu před úkol něco naprogramovat a jelikož to není moje denní hobby tak mi chvilku trvá, než se rozjedu ...
Pokud je to produkční aplikace, tím spíš bych pořádný návrh databáze nepodceňoval. Časem můžeš zjistit, že jsou některé dotazy, které potřebuješ, pomalé (na malém množství dat se to nemusí projevit + ta databáze může časem narůst i co do počtu tabulek atd) nebo tam budeš mít některá data 2x (anebo u ne-normalizovaných databází se můžou i ztrácet). To, že máš chybu v aplikaci snadno opravíš - sice přesvědčit uživatele, aby si nainstalovali update občas není sranda, ale lze to řešit. Nicméně když se Ti podrbou data, tak to často spravit nelze.
souhlasím s tím, že věci se mají dělat pořádně od začátku, ale v tomto případě se jedná o aplikaci, která fungovala 3 roky a plně postačovala potřebám pracoviště. A hlavní důvod přechodu k DB byl v tom, že při ukládání dat do sady textových souborů jsem nebyl schopen najít jediného člověka, který by dokázal zkopírovat soubor(y) z disku (např. c:\adresar\soubor.dat) na záložní paměťové médium, a tak jsem těch iks strojů obcházel pravidelně sám, což se projevilo v patřičné ztátě času. Předpokládám, že pokud to bude teď fungovat spolehlivě, tak na to nebudu muset dalších několik let šáhnout.
Co se týče rychlosti, tak při běžném provozu je odezva bleskurychlá, drobné prodlevy se objevují při zpracování statistik za delší období, což je ale výjimečná situace. Ale zajímalo by mě teda následující:
V hlavní tabulce, která primárně roste je cca 30000 záznamů. Pro statistiky za celou historii se dotážu takto
SELECT u.*, p.* FROM ukony u, vysetreni v, pacienti p WHERE u.VysetreniID=v.ID AND u.PacID=p.ID ORDER BY v.Nazev
tab u má cca 30000 řádků x 15 sloupců
tab v má cca 100 řádků x 2 sloupce
tab p má cca 20000 řádků x 7 sloupců
odezva na dotaz trvá cca 1s (při opakování) na localhostu Core2Duo 2.66GHz, 8 GB RAM, MySQL 5.5, Ubuntu 12.04 amd64
Je to odpovídající čas, nebo by to mělo jít významně urychlit změnou struktury databáze apod ? Jestli jsem se ale zeptal pitomě, tak na mě nic nehažte :-)
-
Co se týče času, tak velmi záleží i na tom, co na "localhostu" právě běží. Jestli máš puštěný Firefox, vývojové prostředí, komunikátor, přehrávač hudby, otevřenou knížku v PDFku (... prostě klasickou sadu softwaru nutného pro vývoj :) ), tak ten dvoujádrák dostane celkem slušně pokouřit a hodnota "1s" absolutně není vypovídající. (Já mám na domácím stroji Core2Duo s 2GB RAM, Win7 64bit, tam by to bylo mnohem horší kvůli nedostatku paměti; naproti tomu na produkčním databázovým serveru, kde neběží nic jiného - i kdyby to bylo dvoujádro s 4GB paměti ve Virtual Boxu - to poběží mnohem rychleji. Každopádně na 30000 záznamů je 1s na takový select poměrně dost; ale výkon je třeba testovat na produkčním serveru nebo někde, kde se nastavení blíží produkci, ne na vývoji.)
O efektivitě každého dotazu Ti nejvíce řekne příkaz EXPLAIN PLAN (pro přesnou syntaxi na MySQL se podívej do manuálu, ta se může mezi jednotlivými databázemi lišit - na Oraclu je to EXPLAIN PLAN FOR sql dotaz;).
Obecně platí, že nejvíce času (pokud jsou tabulky normalizované) se dá nahnat na dobrém indexování - u.VysetreniID, u.PacID a v.Nazev by měly mít indexy, pokud select provádíš mnohem častěji, než insert nebo update (takový, který změní hodnoty v indexovaných sloupcích). Jinak MySQL podporuje několik enginů pro ukládání tabulek, které se liší rychlostí a vlastnostmi - nejznámější jsou MyISAM a InnoDB. Jeden je rychlejší, ale nepodporuje referenční integritu (nevím, který je který - s MySQL se běžně nesetkávám; každopádně je to k nalezení v dokumentaci). Případně se zamyslet nad datovými typy - přístup k varcharům je pomalejší než k charům atd, nebo nad samotnou strukturou dotazů - skutečně je potřeba selectit 30000 řádků, přestože to aplikačka nemá šanci zobrazit? Nestačilo by 30 a udělat stránkování nebo delay-loading?
Každopádně se velmi těžko radí, pokud sem nedáš ERD (diagram vztahu entit), dotazy, které provádíš, jak často se provádí ... nejvíce Ti o tomto opět řeknou odborné knížky. Kromě oficiálních zdrojů typu Amazon se válí různě po internetu, takže se můžeš do nich i podívat, a metodou try-before-buy zjistit, jestli to za ty peníze stojí ;-) .