Sziasztok,
Kedves SQL guruk az alábbi problémában kérném a segítségeteket: Adott egy példa tábla, melyben blog kommentek vannak. A szerkezet: blog_id, felhasznalo_id, komment, bejegyzes_datum. Ebből a táblázatból kellene blogok kapcsolatát felderítenem (legalább X számú különböző, de közös kommentelőjük van). Tehát olyan lekérdezést kellene futtatnom, aminek az eredménye: blog1, blog2, kozos_komment_szam.
Az a baj, hogy csak egy blogra tudom könnyen megírni a lekérdezést, pl.:
select owner_id, blog_id from bloghu_comment where
( owner_id in (SELECT distinct(owner_id) FROM bloghu_comment where blog_id=3) )
and blog_id != 3
De ez csak a 3. sorszámú blog kapcsolatait adja vissza (ebből természetesen még darabszámot kell kinyerni, de az rendben van). Nekem "egy menetben" kellene az összes.
Előre is köszönöm!
- 5326 megtekintés
Hozzászólások
Ezzel legeneralod az osszes blog part, mar csak ki kell szamolni a kozos kommentelok szamat es kiszurni azokat, amelyeknel ez nulla:
select b1.blog_id, b2.blog_id from blog_comment b1 join blog_comment b2 on b1.blog_id > b2.blog_id
----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
- A hozzászóláshoz be kell jelentkezni
Ez a megoldás teljesen jogos, csak az a gondom, hogy a tábla méret miatt a join-olt tábla nagyon nagy lesz. Persze tudom, valamit valamiért. Eddig sok kis lekérdezést kellett futtatni, itt viszont egy marha nagyont.
- A hozzászóláshoz be kell jelentkezni
1. Miért aggódsz? Annyi az adat, amennyi, nem? :) Ha két dolog kapcsolatát kérdezed, nyilván joinolni kell.
2. Nem fog feltétlenül memóriában létrejönni a teljes szorzat. Pl. az első táblán egyesével fog iterálni.
3. Mivel count-ot kérdezel tőle, megfelelő indexek esetén csupán indexből is megválaszolható a kérdés.
- A hozzászóláshoz be kell jelentkezni
Persze teljesen jogos, hogy a kapcsolat = join. Csak az első 5000 sor maradt meg a táblában, a többit kidobtam. Ezután a leírt join futtatva a sorok száma valamivel 10M fölött van. Ezt a join kellene előállítanom egy 640e sort tartalmazó táblára.
- A hozzászóláshoz be kell jelentkezni
Nem feltetlenul kell az a join, mert nem ket "dolog" kapcsolata kell, hanem ket "halmaz" kapcsolata, amire vannak nagyon jo kis SQL operatorok:
- A hozzászóláshoz be kell jelentkezni
-
- A hozzászóláshoz be kell jelentkezni
Ez esetleg közelebb visz?
CREATE TABLE temp_dist
AS (
select
distinct
blog_id
,owner_id
FROM
bloghu_comment
);
SELECT t1.blog_id
,t2.blog_id
,COUNT(*) no_of_owner
FROM
temp_dist t1
JOIN
temp_dist t2
ON t1.owner_id=t2.owner_id
AND t1.blog_id>t2.blog_id
GROUP BY
t1.blog_id,t2.blog_id
HAVING
no_of_owner > X /*közös kommentelők*/
;
- A hozzászóláshoz be kell jelentkezni
Ezt kipróbálom köszi, itt is (lsd. feljebb) a join tábla mérete miatt aggódok.
- A hozzászóláshoz be kell jelentkezni
Milyen DB-ről van szó?
- A hozzászóláshoz be kell jelentkezni
Mysql (innodb), a feldolgozandó sorok száma pedig 640e.
- A hozzászóláshoz be kell jelentkezni
Kb így:
select t1.blog_id as b1,
t2.blog_id as b2,
count(1) as cnt
from (
select blog_id, owner_id
from bloghu_comment
group by blog_id, owner_id
) t1,
(
select blog_id, owner_id
from bloghu_comment
group by blog_id, owner_id
) t2
where t1.owner_id = t2.owner_id
and t1.blog_id < t2.blog_id
group by t1.blog_id, t2.blog_id
order by t1.blog_id, t2.blog_id;
Jahh, látom fentebb már volt megoldás...
- A hozzászóláshoz be kell jelentkezni
Ez tetszik!!! A próba adatbázison szépen lefutott, gyorsabban mint a join-os megoldás. Kipróbálom a teljesre (méretet írtam fentebb). Noh ezt meg az egyel lejjebb levő megoldást kell átnéznem mindkettő gyorsan lefut, csak az eredmény nem ugyanaz! :)
- A hozzászóláshoz be kell jelentkezni
Noh, teszteltem egy próba adatbázison: ez adott helyes megoldást. Köszönöm!
- A hozzászóláshoz be kell jelentkezni
SELECT c1.blog_id, c2.blog_id, CONCAT( c1.blog_id, c2.blog_id ) AS ignore_me, COUNT( c1.user_id ) AS common_user_cnt
FROM commentz c1 USE INDEX ( IX_blog_user_id )
JOIN commentz c2 USE INDEX ( IX_blog_user_id ) ON c1.blog_id != c2.blog_id
WHERE c1.blog_id < c2.blog_id
AND c1.user_id = c2.user_id
GROUP BY ignore_me
A common_user_cnt elvileg megadja a közös usereket (mindkét blogon létezik ugyanaz a user_id).
Olyan sorokat joinol, ahol nem egyezik a blog_id. A bidirekcionális egyezéseket a where első fele eldobja. Az ignore_me alapjan csoportositunk az aggregáthoz. Biztosan van jobb megoldas, de a heti sör mar megvolt.
Lehet profilozni :) Nincs kedvem 5millió sort berandomizálni.
- A hozzászóláshoz be kell jelentkezni
Köszi ez is jónak néz ki. Egyel feljebb van egy megoldás ami szintén gyors, csak a kettő eredménye nem egyezik meg. :)
- A hozzászóláshoz be kell jelentkezni
lol :D
- A hozzászóláshoz be kell jelentkezni
Null-ok, text -> <- num konerziók be tudnak kavarni. :)
Eseteleg a végrhajtásban előforduló különbésgek is okozhatnak eltérést.
- A hozzászóláshoz be kell jelentkezni