Autor Zpráva
tee.vee
Profil
Dobrý den, řeším poněkud speciální záležitost. Mám v mysql jednu tabulku, do které si přidávám položky a z druhé strany si z toho chci připravit sestavu připravenou k tisku. Jedná se víceméně o produkty, u kterých si eviduji id, název, kategorii, balení, množství, množstvíCelkem a datum. Je to vlastně dost podobné objednávkám. Na druhé (výstupní) straně si potřebuji udělat přehled, kdy - čeho - kolik - za kolik penez. To by bylo ještě v pohodě, ALE... teď to začne být zajímavější:



Takto má vypadat denní výstup "do výroby", nahoře jsou v řádku základní kategorie (do dřeva, do cihly...) a v jednotlivých sloupcích jsou vypsané celkové počty ze všech objednávek jednoho (mnou zvoleného) dne. Výrobna si tedy vyjede tento list, a ví, že musí vyrobit určité množství zadaného artiklu do každé kategorie. Dost zběsilé, že? :)

Struktura tabulky je jednoduchá, rámcově:

id | nazev | kategorie | baleni | mnozstvi | mnozstvicelkem | datum

1 | vruty | do dřeva | 500 | 10 | 5000 | 7.12.2012
2 | srouby | do plechu | 500 | 7 | 3500 | 7.12.2012
3 | hrebiky | do betonu | 330 | 3 | 990 | 7.12.2012
4 | vruty | do dreva | 500 | 5 | 2500 | 7.12.2012
5 | vruty | do betonu | 330 | 8 | 2640 | 7.12.2012
.....

50...
80...
...

- takže do tabulky se zapisují jednotlivé (jakoby) objednávky, kde si pak vyberu den, a vypíše se mi taková tabulka jako nahoře. Ve výpisu tedy vidím kategorie, názvy artiklů a jejich balení + jejich objednané množství + celkový přepočet co se má vyrobit.

Jenže:

1) unikátních artiklů bude třeba 40
2) každý artikl je umístěn v každé kategorii (takže vlastně 40 artiklů * 5 kategorií) protože každá kategorie má přednastavené balení (500, 330 atp)
3) zde je podstatné množství (v kategorii "do dreva" je všechno 550, v kategorii "do betonu" 330)

Abych pravdu řekl, absolutně nevím jak postupovat, snažil jsem se různě sdružovat sloupce, ale nikdy jsem nedocílil rozumného výpisu. Navíc, abych ten výstup dostal do formy, jako je na obrázku :/

Nejprve jsem to udělal klasicky přes: select * from tabulka where datum='7.12.2012' - to si vypíši všechny objednávky toho dne.

Pak jsem si začal sumovat jednotlivé položky: SELECT nazev, kategorie, baleni, SUM(mnozstvi), SUM(mnozstvicelkeml) FROM tabulka WHERE datum = '7.12.2012' GROUP BY nazev, baleni

Tím jsem si dokázal sloučit sloupce s množstvím a vypsat si je. Jenže problémem bylo to, že na každém řádku byl jeden artikl několikrát (až 5x dle kategorií) takže seznam měl několik stránek. Tou tabulkou se vlastně sdruží základní kategorie a artikl se vypíše jen jednou - takže ve finále ta tabulka bude mít max. 40 řádků.

Poradíte prosím s nějakým návrhem nebo řešením? Můžu sem případně dodat ještě php kód (ale je tam víceméně jen while cyklus a výpis echo). Předem díky :)
Tori
Profil
Rozdělila bych to do několika tabulek, ale pro lepší radu prosím ještě upřesněte:
1) Na čem je závislá gramáž balení? Např. vruty do plechu se vždy balí po půl kile, nebo jsou (mohou v budoucnu být) i jiné možnosti?
2) Je gramáž v rámci kategorie stejná pro všechny artikly? Tj. - pokud vruty do plechu jsou balené po 500g, znamená to automaticky, že šrouby do plechu i hřebíky do plechu budou taky balené po 500g?
tee.vee
Profil
Ono je to ve finále celé se vším takhle:

Mám tabulku s artikly (id, nazev, kategorie, baleni, cena), například: (#1, Vrut malý, Do dřeva, 500, 60)

Pak mám tabulku objednavky (id, id_uzivatele, datum, cena, stav), například (#1, 5, 7.12.2012, 300, nové)

Pak mám tabulku polozky (id, id_objednavky, nazev, kategorie, baleni, mnozstvi, mnozstvicelkem, datum)

Během vytvoření objednávky si vytvořím nový záznam v tabulce objednavky a všechny objednané artikly si přidám do tabulky polozky. V tabulce polozky si už nebudu tahat údaje o artiklech z tabulky artikly, ale při vytvoření objednávky jsem si všechny údaje zapsal na pevno sem (v případě, že bych artikl v průběhu smazal, upravil... tak abych tam měl pořád tu skutečnou informaci, která byla platná ve dne objednávky). Tabulky jsem si tedy propojil přes identifikátory, aby se hezky párovaly. To všechno funguje naprosto v pohodě.

Když však na řadu přijde ten výstup, abych si sloučil ty objednané produkty s kategorií, je zle.

K Vašemu dotazu:
1) v každé z pěti hlavních kategorií bude cca 40 stejně pojmenovaných artiklů, a lišit se budou pouze v balení (některé budou mít 500, některé 330, některé 100). Takže ve finále, artikl vruty bude v kategorii "do dřeva" mít množství 500, ale třeba v kategorii "do betonu" jen 330, v kategorii "do plechu" třeba jen těch 100. Takže to bude pokaždé různorodé, nedá se říct že to bude vždy pravidlem (že to bude v kategorii stejné).
2) gramáž v jedné kategorii by měla být víceméně stejná, ale není to pravidlem, protože se tam může objevit artikl, který bude třeba jen po 100g místo 500g.
Tori
Profil
Aha, nevěděla jsem, tak potom je ta databáze OK. (Jen snad názvy kategorií by mohly být buď jako další tabulka nebo typ ENUM, a datum bych určitě ukládala jako typ DATE - budou se vám líp dělat jakékoli statistiky typu "celkové objednávky hřebiků po jednotlivých měsících" apod.)

Pořád ale nerozumím tomuhle: „Jenže problémem bylo to, že na každém řádku byl jeden artikl několikrát (až 5x dle kategorií)
- myslíte teď zobrazenou HTML tabulku, nebo data která vrátil ten dotaz? Těch pár řádků mi s uvedeným dotazem vrátilo takovýhle výsledek - jak by to mělo vypadat jinak?
sloučenýchŘádků   nazev   kategorie       baleni  SUM(mnozstvi)   SUM(mnozstvicelkem)    datum
1                   hrebiky do betonu       330     3             990     2012-12-07
1                   srouby  do plechu       500     7             3500    2012-12-07
1                   vruty   do betonu       330     8             2640    2012-12-07
2                   vruty   do dřeva        500     15            7500    2012-12-07
tee.vee
Profil
Ano, datové typy jsem měl už přiřazené od začátku, kromě ENUM, ten jsem nepoužíval.

No, jde mi spíš o ten výpis (HTML tabulku). Představte si, že objednaný artikl ve stejné kategorii se může opakovat kolikrát chce (o vruty do betonu může být velký zájem, takže tento artikl třeba 10 lidí objedná v určitém množství - proto by se měli všechny "vruty" v kategorii "do betonu" sečíst a vypsat celkové číslo, kolik se toho má vyrobit. Do tabulky se tak propíše celkové množství (tzn. mělo by to fungovat zjednodušeně tak, že: vyber datum, vypiš všechny položky, seřaď si je k sobě, spočítej celkové množství a zapiš do HTML tabulky). Cílem musí být vytvoření té HTML tabulky ve formě, jako je uvedena v tom obrázku nahoře.

Pořád nad tím přemýšlím, jestli to nejde udělat nějakou alternativou ale co jiného použít než SUM a sloučení řádků?
Tori
Profil
tee.vee:
Jo, a vám se teda na výstupu zobrazí "vruty do betonu" několikrát, každé objednávka extra? Nebo jak?
Kajman
Profil
tee.vee:
Sestavení tabulky podle obrázku bude lepší dělat v aplikaci, která sql zpracovává. Tedy si zjistit ty součty v jednotlivých buňkách díky sql a např. v php data zformátovat do tabulky a sečíst si celkem.

Můžete si např. řádky z [#4] vložit do dvojrozměrného pole a po jeho naplnění celkovou tabulku vypsat.
tee.vee
Profil
Tori:
tee.vee:
Jo, a vám se teda na výstupu zobrazí "vruty do betonu" několikrát, každé objednávka extra? Nebo jak?

Mě to sjednotilo počty balení ale bez kategorie - tzn. kategorie, které měli společný součet to sečetlo dohromady (takže se sečetly všechny 500 a 330 zvlášť). Takže jsem sice věděl, kolik čeho obecně vyrobit, ale už jsem ztratil informaci "kolik" do které "kategorie".

Ale jak psal Kajman, řešením by to mohlo být, ale trochu nerozumím jak to provést na úrovni setřídění dvourozměrných polí. Nedalo by se to spíš udělat s těma SUM? že to setřídění by se zpracovalo na sql úrovni a pomocí php jen zpracovat výstupy a vygenerovat tabulku...?
Tori
Profil
tee.vee:
Mě to sjednotilo počty balení ale bez kategorie - tzn. kategorie, které měli společný součet to sečetlo dohromady (takže se sečetly všechny 500 a 330 zvlášť)
Aha, tak asi mělo být místo GROUP BY nazev, baleni spíš GROUP BY nazev, kategorie (případně GROUP BY nazev, kategorie, baleni, jestli můžou být např. vruty do plechu v několika různých baleních).

jak psal Kajman, řešením by to mohlo být, ale trochu nerozumím jak to provést na úrovni setřídění dvourozměrných polí.
Jak to máte teď? V SQL dotazu si seřadíte data podle názvu, pak podle kategorie, pak podle balení. Pak je buď můžete vypisovat přímo při čtení z DB (postup bude podobný jako u Nejčastější potíže s PHP (FAQ) » Nadpis skupiny nejen při výpisu z databáze, akorát se bude testovat změna ne u jedné, ale u dvou hodnot), anebo je nejdřív nasypete do pole a z toho pak vyrobíte tabulku (to bude asi jednodušší, a i správnější z hlediska oddělení dat od jejich zobrazení). Pole by mohlo vypadat:

$data = [
    "vruty" => [
        "do dřeva" => [ 500 => 10 ]
        "do betonu" => [ 330 => 3 ] ]
    "šrouby" => [
        "do dřeva" => [ 500 => 10 ]
        "do plechu" => [ 500 => 7 ] ]
]
a nějakými dvěma foreach cykly se to vypíše.
tee.vee
Profil
Tak jsem si na základě vašich rad hrál s tím group by a sum, a došel jsem k závěru, že to funguje nakonec dobře a setřídí se to tak, jak potřebuji. Využil jsem k tomu: SELECT nazev, kategorie, baleni, SUM(mnozstvi), SUM(mnozstvicelkem) FROM tabulka WHERE datum = '2012-11-27' GROUP BY nazev, kategorie, baleni

Tím z tabulky dostanu pěkně setříděné položky podle jména - zatříděné podle kategorií u které se vypíše množství a celkové množství. Super.

Teď už chybí nasekat to do HTML tabulky, hezky pod jednotlivé sloupce kategorií. Můžu nějak přinutit vypisování dat do pojmenovaných sloupců? Když si provedu normální vypsání přes while cyklus, dostanu to řádek po řádku. Prakticky vzato, když vím že budu mít 5 kategorií (sloupců), musím dodržet vypisování do předem určených sloupců. To se dá udělat taky přes foreach? Díky za rady.
Tori
Profil
tee.vee:
Můžu nějak přinutit vypisování dat do pojmenovaných sloupců?
Myslíte mysql_fetch_assoc (= sloupce dat z databáze, anebo sloupce v HTML tabulce)?

když vím že budu mít 5 kategorií (sloupců), musím dodržet vypisování do předem určených sloupců. To se dá udělat taky přes foreach?
Napadly mě dva přístupy, oba počítají s tím, že si nejdřív složíte pole (podobné tomu v [#9]) a potřebují navíc pole názvů pro sloupce a pro řádky - array('šrouby', 'vruty', ... apod.).

1) Vypíše jen sloupce a řádky, které obsahují nějakou hodnotu. Takže např. v [#1] by chyběly kategorie cihla a sádrokarton.
Postup: při výpisu z DB do pole si zároveň ukládáte názvy zboží a kategorií do těch dvou extra polí tak, aby se jednotlivé hodnoty neopakovaly (= buď ukládat názvy jako klíče, anebo ukládat jako hodnoty a prohnat array_flip nebo array_unique). Pořadí ovlivníte seřazením těch polí (sort a spol.), i když možná se projeví i řazení zadané v SQL dotazu.

2) Pole názvů zboží i kategorií si napíšete sám. To vám pak vypíše i prázdné sloupce a řádky v libovolném zadaném pořadí.

2b) Pokud byste nečetl data z této tabulky, ale běžným spojením tabulek (zboží, kategorie, objednávky), tak byste mohl získat už z databáze všechny existující hodnoty názvů zboží a kategorií (jen by u těch neobjednaných byly hodnoty NULL). Pro případ, že by se vám třeba často měnila nabídka zboží+kategorií a chtěl byste zobrazovat vždy všechny možné hodnoty, i když nebyly objednané, bez toho abyste musel po každé změně DB upravit i skript.

asi bude i lepší způsob, tohle je tak narychlo
tee.vee
Profil
Smekám před odborníkem, Tori, děkuji za návrh možných řešení, ale trochu se obávám že na to celé jsem už malý pán a je to nad moje síly. :/

„Můžu nějak přinutit vypisování dat do pojmenovaných sloupců?“
Myslíte mysql_fetch_assoc (= sloupce dat z databáze, anebo sloupce v HTML tabulce)?
Myslím tím už konkrétní výpis do HTML tabulky.

Z těch možných variant mi příjde nejlepší kombinace 2 a 2b. Nejlepší by bylo sestavit si mustr sloupců (vytvořit si šablonu tabulky v HTML, do které jen zapisovat jednotlivé řádky položek). Jenže já už tím asi nedocílím abych měl pod sebou vždy kategorii "do cihly", "dřevo" nebo "sádrokarton". Počet buňěk "do pravé strany" by byl závislý přímo na počtu položek (názvů) z databáze. To už by bylo lepší je opravdu doplnit o NULL a nechat tam prostě volnou buňku.

Kategorií bude vždy jen 5, ale celkové počty artiklů (i počet objednaných artiklů) může být vždy jiný. Některé artikly jsou přítomny třeba jen ve dvou kategoriích, naopak některé jsou ve všech (jen s jiným balením a cenou).
Tori
Profil
tee.vee:
Nejlepší by bylo sestavit si mustr sloupců (vytvořit si šablonu tabulky v HTML
Ano, to jsem myslela. Předpokládejme, že si poskládáte data z DB do pole jako v [#9]. Pak by varianta 2) vypadala nějak takhle:

$data = array(); // data z DB
$radky = array('vruty', 'šrouby', 'hřebíky');
$sloupce = array('do dřeva', 'do betonu', 'do sádry', 'do plechu', 'do cihly');
echo '<table><tr><th>Název</th><th>'.implode('</th><th>', $sloupce).'</th><th>Celkem</th></tr>';
foreach ($radky as $nazev) {
    $total = 0;
    echo "<tr><td>$nazev</td>";
    foreach ($sloupce as $kategorie) {
        echo '<td>';
        if (isset($data[$nazev][$kategorie])) {
            list($baleni, $pocet) = each($data[$nazev][$kategorie]);
            $vaha = $baleni * $pocet;
            echo $baleni.'g &times; '.$pocet.'ks<br>';
            echo '<b>'.number_format(($vaha / 1000), 1, ',', ' ').'kg</b>';
            $total += $vaha;
        } else { 
            echo '&nbsp;'; 
        }
        echo '</td>';
    }
    echo '<td><b>'.number_format(($total / 1000), 1, ',', ' ').'kg</b></td></tr>';
}
echo '</table>';
Ale je to děsná prasárna, asi by se mělo místo názvů kategorií radši používat ID, a šablony a vůbec... Asi bych spíš použila variantu 2b a načetla z DB i všechny možné druhy zboží+kategorií, aby to nebylo závislé na těch pomocných polích, nevim.
tee.vee
Profil
Mě to jako prasárna moc nepřijde, vypadá to i dost funkčně, jen drobnost - u if chybí jedna kulatá závorka na konci, pak už se to rozjede.

if(isset($data[$nazev][$kategorie])){
...
}

Zkusil jsem to ještě upravit aby to sedělo, načetl celé pole ale ve finále mi vyjela prázdná tabulka. Název sloupců je v pořádku, jednotlivé řádky se taky zobrazily ale dovnitř se už nic nevyplnilo. Tak ještě přemýšlím, jak to upravit přímo na tu variantu 2b, kdy by se to mohlo vzít celé z té databáze. Ostatně, všechno důležité tam uvnitř je uložené, a nemuseli by vyjíždět prázdné řádky jako ve variantě 2 spolu s aktualizací výrobků (když nějaké přidáme nebo ubereme). Zase na druhou stranu, výrobky bych mohl načítat z jiné tabulky (z tabulky artiklů), jenže jestli v tom nedělá zrovna nepořádek ten stejný název (když je tam ten artikl třeba 5x se stejným názvem, ale zařazením do jiné kategorie). V tom případě by měl být v poli jen jednou, ne? (myslím název artiklu) - z pole $radky = array(...);

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: