Portál AbcLinuxu, 12. května 2025 16:54
Zdravim.
Mam nasledujici problem. Mam ulozeny IP adresy v 5 tabulkach. Potreboval bych pomoci SQL dotazu vybrat vsechny IP adresy ze vsech tabulek, "zgrupovat" duplicitni zaznamy a zaroven spocitat, kolikrat se ktera IP adresa ve vsech tabulkach nachazela. Pro jednu tabulku jsem to resil naledovne - "SELECT IP, COUNT(*) as Pocet FROM tabulka GROUP BY IP", ale pro vice tabulek jsem bezradny.
dekuji za pomoc Petr
btw. "nalit" vsechny data do jedne tabulky se mi nechce, protoze v kazde tabulce je cca 0,5 mil zaznamu.
Diky, toto mi bohuzel nepomohlo - neslo o JOIN ale o UNION (kde je ale problem s funkci COUNT)
Vyresil jsem to tak, ze jsem vytvoril view do ktereho jsem vybral IP adresy ze vsech tabulek (pomoci UNION ALL) a nasledny COUNT a GROUP BY jsem udelal nad timto view.
Pokud by se nekomu podarilo nacpat vse do "jednoho" SQL dotazu, tak pro zajimovost prosim o zaslani. Alespon bych udelal benchmark co je rychlejsi
Neznám strukturu tabulek, ale napadá mě toto:
SELECT ip_address, COUNT(1) FROM (SELECT ip AS ip_address FROM ip1 UNION ALL SELECT ip FROM ip2) GROUP BY ip_address /
Pokud tě zajímají hlubší statistiky, například groupovat i po tabulkách (postupné součty), jde to udělat takto:
SELECT ip_address, table_type, COUNT(1) FROM (SELECT ip AS ip_address, 1 AS table_type FROM ip1 UNION ALL SELECT ip, 2 FROM ip2) GROUP BY ip_address, table_type /
Postupné součty:
SELECT table_type, ip_address, COUNT(1) FROM (SELECT ip AS ip_address, 1 AS table_type FROM ip1 UNION ALL SELECT ip, 2 FROM ip2) GROUP BY ROLLUP ( table_type, ip_address) /
Na databázích, které nepodporují GROUP BY ROLLUP
, se to musí trošku vochcat:
SELECT table_type, ip_address, COUNT(1) FROM (SELECT ip AS ip_address, 1 AS table_type FROM ip1 UNION ALL SELECT ip, 2 FROM ip2) GROUP BY table_type, ip_address UNION ALL SELECT table_type, NULL, COUNT(1) FROM (SELECT ip AS ip_address, 1 AS table_type FROM ip1 UNION ALL SELECT ip, 2 FROM ip2) GROUP BY table_type UNION ALL SELECT NULL, NULL, COUNT(1) FROM (SELECT ip AS ip_address, 1 AS table_type FROM ip1 UNION ALL SELECT ip, 2 FROM ip2) /
Z toho je vidět, že se musí ty tabulky probrousit několikrát, což není dvakrát cool. Ale naštěstí Oracle i DB2 je v klidu.
Co se výkonu týče, byl bych úplně vklidu. Zrovna dneska jsem třeba dopsal SELECT
, který brousí tabulky s několika miliony záznamů. Je to celkem zajímavý report, tak mě to bavilo. A výsledková sada je u klienta do 30 sekund. Ani jsem neřešil indexy
protože by to stejně při tak malém množství vyšlo na FULL SCAN.
Dobrá, tak vážně. Pokud s datovou strukturou nemůžeš pohnout, zajímal bych se o materializované pohledy. Jak jsem to pochopil, spíš se u tebe jedná o nějaké logy, takže spíš pod tlakem smažíš nové záznamy. Materializovaný pohled umí být FAST REFRESH ON COMMIT
, což by mělo jít na MySQL nějak očurat (ano, fackuju se) triggerem. Kdyžtak kdykoli můžeš ty logy odlejt někam do historie, udělat z nich agregát a k němu pak připočítávat (tabulka IP_AVG
obsahuje ten agregát tabulky IP1) (sakra, já jsem dneska nějakej dobrej; asi bych toho měl už nechat…):
SELECT NVL(x.ip, y.ip) AS ip, NVL(x.cnt, 0) + NVL(y.cnt, 0) AS cnt FROM (SELECT ip, COUNT(1) AS cnt FROM ip2 GROUP BY ip) x FULL OUTER JOIN (SELECT ip, cnt FROM ip_avg) y ON (x.ip = y.ip) /
Až na ten FULL OUTER JOIN
se mi to líbí. A ten jde obejít takto:
SELECT ip, SUM(cnt) FROM (SELECT ip, COUNT(1) AS cnt FROM ip2 GROUP BY ip UNION ALL SELECT ip, cnt FROM ip_avg) GROUP BY ip /
Jo. A místo NVL()
jde použít NULLIF()
.
A mimochodem: díky za zpříjemnění večera. Už jsem se bál, že se budu nudit.
P.S.: Jako obvykle: v příloze je skript na hraní; tak hodně štěstí!
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.