Avatar billede gyxi Nybegynder
02. juni 2008 - 19:27 Der er 9 kommentarer og
1 løsning

Flere betingelser i en mange-til-mange

Det her burde være ret simpelt, men jeg kan bare ikke få det til at fungere. Jeg har 3 tabeller:

- Posts
- Categories
- Categorizations

Sidstnævnte er en mange-til-mange tabel mellem Posts og Categories, så den indeholder altså PostId og CategoryId for hver række. Det fungerer helt fint.

Jeg vil nu gerne have de Posts ud som er medlem af to bestemte kategorier. Det jeg har giver altid 0 resultater, selvom der burde være nogle:

SELECT COUNT(distinct Posts.Id) as count
FROM    Posts INNER JOIN
Categorizations ON Posts.Id = Categorizations.PostId INNER JOIN
Categories ON Categorizations.CategoryId = Categories.Id
WHERE ((Categorizations.CategoryId = 735)  AND  (Categorizations.CategoryId = 1187))

Jeg forstår faktisk godt HVORFOR det giver 0 resultater, men jeg kan ikke lige regne ud hvordan jeg gør det rigtigt.
Avatar billede HenrikSjang Nybegynder
02. juni 2008 - 19:56 #1
Som det lyder til du selv kan indse, så har du jo fx 3 rækker, hvis en post er medlem af 3 kategorier. Du vil tjekke for, om den præcis er medlem af de to som har ID 735 og 1187. Dvs, at du vil have de postings, hvor der er 2 rækker i resultatet. Prøv fx med dette (jeg har ikke lige testet det, men det vil kun virke på en sql 2005):

WITH aCTE
AS
(
SELECT Posts.Id
FROM    Posts
INNER JOIN Categorizations ON Posts.Id = Categorizations.PostId
INNER JOIN Categories ON Categorizations.CategoryId = Categories.Id
WHERE
  (Categorizations.CategoryId = 735) 
  OR (Categorizations.CategoryId = 1187)
GROUP BY Posts.Id
HAVING COUNT(*) = 2
)

SELECT COUNT(distinct Posts.id) as count
FROM aCTE

----------------
Idéen er, at du bruger en cte, som er en slags midlertidig view. Select'en returnerer alle de posts, som enten har categoryid 735 ELLER 1187. Det betyder dog, at den også returnerer de posts, som kun hører til én af kategorierne. Men ved at lave en GROUP BY på posts.id, og så tilføje "HAVING COUNT(*) = 2", så returneres KUN de posts, som netop både en kategori 735 OG en 1187. Ved at putte select'en ind i en CTE, kan du derefter lave en simpel "select count" på cte'en, så du får returneret antallet af posts, som opfylder dit ønske.
Avatar billede gyxi Nybegynder
02. juni 2008 - 20:08 #2
Tak for et hurtigt svar. Det kald ser frygteligt dyrt ud. Den skal jo hente alle de posts frem, bare for at finde antallet. Men der er måske ingen billigere måde ... :(
Avatar billede HenrikSjang Nybegynder
02. juni 2008 - 20:22 #3
Jeg tror nu ikke det er så slemt. En count er i og for sig heller ikke billig. Bemærk, at alle rækkerne jo ikke returneres til klienten - det er kun internt den junglerer rundt med dataene. Og det vil den også gøre for at lave en alm. count.
Avatar billede gyxi Nybegynder
02. juni 2008 - 22:53 #4
Interessant nok. Jeg tror stadig det er ret meget dyrere at oprette sådan en midlertidig samling data, men du har nok også ret i det ikke er overvældende når den ikke skal returnere dem. I stedet for at gisne, prøver jeg :)

Denne linje skulle jeg i øvrigt lige ændre:

SELECT COUNT(distinct Posts.id) as count
til
SELECT COUNT(distinct Id) as count

Nok fordi den selecter på den midlertidige datakilde og ikke på selve tabellen. Det ser ud til den returnerer et tal der godt kunne være rigtigt :) tak!
Avatar billede arne_v Ekspert
03. juni 2008 - 02:47 #5
alternativt forslag:

SELECT COUNT(DISTINCT p1.id) AS count
FROM posts p1
    INNER JOIN categorizations pc1 ON p1.id = pc1.postid
    INNER JOIN categories c1 ON pc1.categoryid = c1.id
    INNER JOIN posts p2 ON p1.id = p2.id
    INNER JOIN categorizations pc2 ON p2.id = pc2.postid
    INNER JOIN categories c2 ON pc2.categoryid = c2.id
WHERE (pc1.categoryid = 735) AND (pc2.categoryid = 1187)

Men så vidt jeg kan se så har categorizations alle de felter du skal bruge, så du
kan faktisk nøjes med:

SELECT COUNT(DISTINCT pc1.postid) AS count
FROM categorizations pc1
    INNER JOIN categorizations pc2 ON pc1.postid = pc2.postid
WHERE (pc1.categoryid = 735) AND (pc2.categoryid = 1187)
Avatar billede gyxi Nybegynder
03. juni 2008 - 11:08 #6
Tak arne, det ser en hel del simplere ud. Er du ikke også enig i det, Sjang?
Avatar billede HenrikSjang Nybegynder
03. juni 2008 - 18:38 #7
Det ser faktisk snedigt ud. Hvis også det giver det ønskede resultat, ja så ville jeg da også klart vælge Arnes forslag :)
Avatar billede arne_v Ekspert
05. juni 2008 - 04:26 #8
Det må jo være muligt at teste om de returnerer det rigtige.
Avatar billede gyxi Nybegynder
08. juni 2008 - 11:10 #9
Det virker helt perfekt. Takker. Læg svar så vi kan lukke.
Avatar billede arne_v Ekspert
08. juni 2008 - 14:49 #10
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester