A rendelési adatbázis önmagában 30 000 Ft árbevételt mutat, a terméksorokkal összekapcsolt riport mégis 80 000 Ft-ot ad. Ez gyakran a táblák eltérő részletezettségéből következik. Egy rendeléshez több tétel tartozik, ezért az összekapcsolás után a rendelés szintű végösszeg több soron ismétlődik.
A hiba nem feltétlenül hibás SQL-szintaxis. A lekérdezés szabályosan végrehajtódhat, miközben az üzleti mutató rossz szinten összegződik. Először ezért azt kell leírni, mit jelent egy sor a forrástáblában és az összekapcsolás után.
Két rendelésből öt riportsor lesz
Az első rendelés végösszege 10 000 Ft, és két terméktételt tartalmaz. A második rendelés 20 000 Ft, három terméktétellel. A rendelési táblában két sor van, végösszegük 30 000 Ft.
A rendelésazonosító szerinti összekapcsolás a tételtáblával öt sort eredményez. Az első rendelés 10 000 Ft-os végösszege kétszer, a második 20 000 Ft-os végösszege háromszor szerepel. Ezek összege 2 × 10 000 + 3 × 20 000 = 80 000 Ft.
A PostgreSQL táblakifejezésekről szóló dokumentációja pontosan leírja, hogy a kapcsolási feltételhez illeszkedő sorpárokból hogyan jön létre az eredmény. A fenti összegek saját tesztadatok; bármely hasonló egy-a-többhöz kapcsolásnál érdemes ugyanilyen kis ellenpéldát készíteni.
A mutatóhoz tartozó szinten összegezz
A teljes rendelési árbevételhez a rendelési táblában minden rendelés egyszer számítson. Ha csak azok a rendelések kellenek, amelyekben egy bizonyos termék szerepel, először a megfelelő rendelésazonosítók egyedi halmazát állítsd elő. Ezután kapcsolódjon hozzájuk a rendelés szintű összeg.
Más feladat a termékenkénti értékesítés. Ott az adott terméksor saját, megfelelően értelmezett összege lehet az összesítés alapja. A szállítási díj, a rendelési kedvezmény vagy egy összesített jóváírás felosztása további üzleti szabályt kíván. Ezeket nem lehet a rendelési végösszeg minden sorra másolásával helyesen kezelni.
A SQL-formázó az áttekinthetőséget segíti. A formázott lekérdezés helyességét a kapcsolatok, a csoportosítás és az ellenőrző adatsor bizonyítja; a rendezett tördelés önmagában kevés.
Az eltérő összegek kiválasztása nem általános javítás
Csábító ötlet csak a különböző rendelési összegeket összeadni. A két első rendelésnél a 10 000 és 20 000 Ft valóban 30 000 Ft-ot adna. Ettől a módszer még hibás marad.
Adj hozzá egy harmadik, külön azonosítójú rendelést 10 000 Ft-tal. A helyes árbevétel most 40 000 Ft. A különböző összegértékek halmaza továbbra is csak 10 000 és 20 000 Ft, így a módszer 30 000 Ft-ra jutna.
A megőrzendő egyediség tehát a rendelés azonosítójához tartozik. Két külön rendelésnek teljesen szabályosan lehet azonos végösszege. Az összeg szerinti duplikációszűrés valódi bevételt is eltüntethet.
Készíts egyeztethető ellenőrző sorokat
A riport mellé kerüljön a forrásrendelések száma, az egyedi rendelésazonosítók száma és a kapcsolás utáni sorszám. A saját példában ezek rendre kettő, kettő és öt. A harmadik rendelés hozzáadása után a rendelésdarabszámnak háromra kell nőnie.
Tesztelj tétel nélküli rendelést is: belső kapcsolásnál kieshet, külső kapcsolásnál más kezelést kap. Azt, hogy üzletileg melyik szükséges, a riport célja dönti el. Az ismeretlen azonosítójú tételeket külön hibalistára célszerű tenni, és a kapcsolási kulcsok egyediségét a forrásban ellenőrizni.
Két részletező tábla már egymás sorait is megsokszorozza
Egy külön próbában egy rendelés végösszege 18 000 Ft. Két terméktétel tartozik hozzá, 7000 és 11 000 Ft-tal, valamint három részfizetés, 5000, 6000 és 7000 Ft-tal. A termékek és a fizetések összege külön-külön helyesen 18 000 Ft.
Ha mindkét részletező táblát pusztán rendelésazonosító alapján kapcsolod ugyanahhoz a rendeléshez, minden terméktétel mellé mindhárom fizetés illeszkedik. Az eredmény 2 × 3 = 6 sor. Háromféle hibás összeg is előáll:
| Összegzett oszlop | Ismétlődés | Hibás összeg |
|---|---|---|
| Rendelési végösszeg | Hatszor | 108 000 Ft |
| Terméktétel összege | Minden tétel háromszor | 54 000 Ft |
| Részfizetés összege | Minden fizetés kétszer | 36 000 Ft |
Itt a terméktétel saját összegének használata önmagában sem oldja meg a problémát, mert a fizetési kapcsolás azt is megismételte. Először a tételeket rendelésszintre összegezd, és külön a részfizetéseket is rendelésszintre. A két eredményben rendelésenként egy sor legyen; csak ezután kapcsold össze őket. A mintában így egy sorban három egyeztethető 18 000 Ft-os értéket kapsz.
Ha a riportnak a még ki nem fizetett rendeléseket is mutatnia kell, a fizetésösszesítő hiánya miatt ne ejtsd ki a rendelést. A hiányzó fizetési sor kezelését külön rögzítsd: azt jelenti, hogy nincs nyilvántartott fizetés, ami nem azonos egy ismeretlen állapotú, be nem töltött adatforrással. A PostgreSQL kapcsolási szabályai alapján a kapcsolás típusát és a sorok részletezettségét együtt kell megválasztani.
A szűrés helye a megmaradó rendeléseket is befolyásolja
Egy külön mintában két rendelés van, 10 000 és 20 000 Ft-tal. Az elsőhöz tartozik 10 000 Ft rendezett fizetés, a másodikhoz egyelőre nincs fizetési sor. A riportnak most mindkét rendelést meg kell őriznie. Bal oldali külső kapcsolásnál a második rendelés is megjelenhet, a fizetés mezőiben hiányzó kapcsolt értékekkel.
Ha ezután a WHERE feltételben kizárólag a „rendezett” fizetési állapotot engeded át, a második rendelés kiesik: két rendelésből egy marad. Ha a fizetési állapot szűrése a kapcsolás ON feltételében szerepel, a két rendelés megmarad, és csak a feltételnek megfelelő fizetési sorok kapcsolódnak hozzájuk. A PostgreSQL dokumentációja külön példával is bemutatja ezt a külső kapcsolási eltérést.
A megfelelő változatot a riport célja dönti el. Ha minden rendelést meg akarsz mutatni, a próba elvárt rendelésdarabszáma kettő legyen. A hiányzó kapcsolt fizetést továbbra is az adatforrás ismert teljessége alapján értelmezd; a lekérdezés önmagában nem igazolja, hogy minden fizetés már bekerült a nyilvántartásba.
Gyakori kérdések
A több riportsor önmagában adatduplikáció?
Nem feltétlenül. Tételszintű riportban természetes, hogy egy rendeléshez több sor tartozik. A rendelési végösszeg ismételt összeadása a probléma.
Az összes sor törlése egy kivételével megoldás?
Csak akkor, ha az adott mutató valóban rendelési szintű, és a választás rendelésazonosító szerint történik. Termékriportnál ezzel valódi tételeket veszíthetsz el.
Mit ellenőrizzek a végösszegen kívül?
Az egyedi kulcsokat, a sorok részletezettségét, a kieső rekordokat és a kapcsolás előtti-utáni darabszámokat. Ezek együtt mutatják meg a hiba helyét.
Záró tudáspróba
Válassz kérdésenként egy választ. A megoldások ellenőrzése után minden helyes válaszért 1 pontot adj magadnak; a hibás, kihagyott vagy több válasszal megjelölt kérdés 0 pont. Összesen 0–3 pont szerezhető.
1. A 10 000 Ft-os rendelés két, a 20 000 Ft-os három tételhez kapcsolódik. Mennyi a helyes rendelési végösszeg?
- A) 80 000 Ft.
- B) 50 000 Ft.
- C) 30 000 Ft.
2. Egy rendelés két terméktételét és három fizetését csak rendelésazonosító alapján együtt kapcsolod. Hány sor lehet?
- A) 2
- B) 6
- C) 3
3. Mi a két részletező tábla helyes rendelésszintű egyeztetése?
- A) Külön rendelésszintre összegzed a tételeket és a fizetéseket, majd az egy sor/rendelés eredményeket kapcsolod.
- B) Csak a különböző pénzösszegeket tartod meg.
- C) A hatsoros eredmény végösszegét mindig hattal osztod.
Megoldások és pontszám
1. C. Minden rendelés egyszer számít: 10 000 + 20 000 = 30 000 Ft. A 80 000 Ft a tételsorokon ismételt végösszegek összeadása lenne.
2. B. Minden tétel mindhárom fizetéssel párosul: 2 × 3 = 6. Ez a termék- és a fizetésösszegeket is megsokszorozhatja.
3. A. Az összesítés szintjét a rendelésazonosító határozza meg. A különböző összegek szűrése vagy egy állandó osztó más adatok mellett hibás eredményt adhat.
3 pont: A kapcsolási sokszorozódást a két részletező táblánál is felismerted. A saját riportodban minden köztes eredményhez rögzítsd, mit jelent egy sor.
2 pont: Az 1. kérdéshez a két eredeti rendelést, a 2.-hoz a két tétel és három fizetés párosítását, a 3.-hoz az előzetes rendelésszintű összegzést nézd át.
0–1 pont: Írd le a 18 000 Ft-os példa mind a hat sorát. Számold meg, hányszor ismétlődik egy tétel és egy fizetés, majd külön összegezd vissza a két forrást.