Schamann.net

…děláme vJeci jinak…

MySQL – tisk adresních štítků

Narazil jsem na zajímavý problém s tiskem adresních štítků z naší databáze. Potřeboval jsem odesílat více balíků z jedné zakázky na stejnou adresu. Normálně jsme tiskli jeden štítek několikrát. Ale stalo se, ze kurýr u zákazníka nevěděl kolik balíků má ve skutečnosti předat. Takže jsem chtěl udělat číslování balíků v rámci zakázky ve formátu 1z5, 2z5, atd. Řešení je tak překvapivě jednoduché, že jsem se o něj chtěl podělit.

Jasné, řešení existuje spousta a každý programátor i začátečník by si s tím nějak poradil po svém. Ale protože v našem .NET používáme pro tisky CrystalReport bylo by elegantní řešení nechat to přímo na databázi a výsledek podstrčit rovnou z MySQL. To znamená ve výsledném SELECTU chci úmyslně tolik duplicitních řádků adres, kolik mám balíků a zároveň doplnit číslování těch duplicit, aby mi vznikla kompletní sada adresních štítků.

I tady existuje několik možností přes dočasné tabulky nebo nějaké funkce, všechno mi přišlo zbytečně složité. Ale pojďme postupně.

Pokud JOINuju dvě tabulky, které mají různý počet řádků, buď mi vzniknou duplicity nebo bude něco chybět. Pojďme tedy využít těch duplicit a jen je očíslovat.

Jak na to? Důležité je vyrobit si očíslovaný seznam v jiné tabulce, která bude sloužit pro získání pořadí. Buď se dá založit nějaká dočasná tabulka, která bude seznam obsahovat, například:

CREATE TABLE max_baliku (PORADI INT(11) PRIMARY KEY)
INSERT INTO max_baliku VALUES(1),(2),(3),(4),(5)

Musí se ovšem, předem zjistit maximální počet balíků ve všech adresách (pokud tisknete štítky, tak jako my, v dávkách) které chci tisknout, a po tisku po sobě zase uklidit. To znamená čas a kódování navíc. Protože je tohle u nás celkem pravidelná věc, tak jsem jednoduše založil tabulku ciselnik_max_baliku s jediným sloupcem PORADI, který obsahuje číselník s dostatečnou rezervou (100) řádků.

Pro ucelený příklad mějme ještě tabulky adresy a baliky:

  • adresy.CISLO_ZASILKY, adresy,ADRESA
  • baliky.CISLO_ZASILKY , baliky.POCET_BALIKU

JOINovat umíme všichni a spojení 3 tabulek dáme do kupy velice rychle:

SELECT a.ADRESA, c.PORADI, b.POCET_KUSU 
FROM adresy AS a
LEFT JOIN baliky AS b ON b.CISLO_ZASILKY = a.CISLO_ZASILKY
LEFT JOIN ciselnik_max_baliku AS c ON c.PORADI = b.POCET_KUSU  

A je čas na kouzlo. Celý fígl je v tom že v klauzuli ON se nemusí používat pouze „=“ jak jsem všichni notoricky zvyklí, ale můžeme použít libovolný operátor. A pokud použiju v našem případě „<=“ vznikne přesně to co potřebuju: Očíslovaný seznam adresních štítků. Ono „<“ totiž pak bude vyhovovat všem řádkům z tabulky ciselnik_max_baliku az do hodnoty baliky.POCET_KUSU a tyto řádky do výsledku přidá a protože k nim v tabulce adres nejsou protihodnoty musí je zduplikovat. Nakonec ještě nějaký ORDER, aby se vytiskly ve správném pořadí a je hotovo.

SELECT a.ADRESA, c.PORADI, b.POCET_KUSU 
FROM adresy AS a
LEFT JOIN baliky AS b ON b.CISLO_ZASILKY = a.CISLO_ZASILKY
LEFT JOIN ciselnik_max_baliku AS c ON c.PORADI <= b.POCET_KUSU
ORDER BY a.CISLO_ZASILKY, c.POCET
Jak jsem řekl, překvapivě jednoduché a elegantní řešení, bez jakýchkoliv
dalších cyklů, selektů, funkcí a zbytečného kódování...


  • 🙂

Posted 5 months ago at 00:51.

Add a comment