Avatar billede hojgaard Nybegynder
15. april 2008 - 18:08 Der er 8 kommentarer og
1 løsning

SELECT problem med mange-til-mange relation

Hej eksperter

Jeg er rendt ind i et SELECT problem med en mange-til-mange relation.
Jeg har en opskrifts database, der bl.a. indeholder følgende 3 tabeller.


Recipe
-----------------
RecipeID
Name
Description
CookingTime
Persons
...

RecipeIngredient
-----------------
RecipeID
IngredientID
...

Ingredient
-----------------
IngredientID
Name
Description
Difficulty
...



En opskrift (Recipe) har relationer til en eller flere ingredienser (Ingredients).
Samtidig kan en ingrediens være relateret til en eller flere opskrifter.

Jeg kunne godt tænke mig at hente opskrifter ud fra en eller flere ingredienser.
F.eks. har jeg navnet på 3 ingredienser, og ønsker at få alle opskrifter, der har disse 3 ingredienser tilknyttet.

Problemet er jeg hele tiden ender med at få alle opskrifter hvor bare én af ingredienser er i - ikke alle 3.
Avatar billede kalp Novice
15. april 2008 - 18:53 #1
select Recipe.Name as RecipeName
from Recipe, RecipeIngredient, Ingredient
where Recipe.RecipeID = RecipeIngredient.RecipeID
and Ingredient.IngredientID = RecipeIngredient.RecipeID
and Ingredient.Name = 'Pepper'
or Ingredient.Name  = 'Salt'
or Ingredient.Name = 'Karry'
group by Recipe.Name
Avatar billede kalp Novice
15. april 2008 - 19:21 #2
sorry.

sådan.




select Recipe.Name as RecipeName
from Recipe left join RecipeIngredient on  Recipe.RecipeID = RecipeIngredient.RecipeID
left join Ingredient on Ingredient.IngredientID = RecipeIngredient.RecipeID
where Recipe.RecipeID in (
select RecipeIngredient.RecipeID from RecipeIngredient left join Ingredient on Ingredient.IngredientID = RecipeIngredient.IngredientID
where Ingredient.Name = 'Salt'
or Ingredient.Name = 'Pepper'
or Ingredient.Name = 'Karry'
group by RecipeIngredient.RecipeID

)
group by Recipe.Name
Avatar billede kalp Novice
15. april 2008 - 19:32 #3
hmm.. okay.. jeg misforstod dit spørgsmål.

godt nok er det her ineffektiv SQL. men det virker og gør som du forventer.




select Recipe.Name as RecipeName
from Recipe left join RecipeIngredient on  Recipe.RecipeID = RecipeIngredient.RecipeID
left join Ingredient on Ingredient.IngredientID = RecipeIngredient.RecipeID
where Recipe.RecipeID in (
select RecipeIngredient.RecipeID
    from RecipeIngredient left join Ingredient on Ingredient.IngredientID = RecipeIngredient.IngredientID
    where Ingredient.Name = 'Salt'
group by RecipeIngredient.RecipeID
)
and Recipe.RecipeID in (
select RecipeIngredient.RecipeID
    from RecipeIngredient left join Ingredient on Ingredient.IngredientID = RecipeIngredient.IngredientID
    where Ingredient.Name = 'Pepper'
group by RecipeIngredient.RecipeID
)
and Recipe.RecipeID in (
select RecipeIngredient.RecipeID
    from RecipeIngredient left join Ingredient on Ingredient.IngredientID = RecipeIngredient.IngredientID
    where Ingredient.Name = 'Karry'
group by RecipeIngredient.RecipeID
)
group by Recipe.Name
Avatar billede hojgaard Nybegynder
15. april 2008 - 20:24 #4
Perfekt kalp... dit sidste eksempel gjorde præcis hvad jeg havde brug for!
Du skulle vel ikke have et tip til hvordan jeg kan gøre det mere effektivt?

1000 tak for hjælpen ;o)
Avatar billede kalp Novice
15. april 2008 - 20:41 #5
jeg arbejder desværre ikke nok med SQL til, at have været inde over de mere effektive fremgangsmåder.
men det kan sikkert gøres på en måde hvor man ikke behøver selecte 4 gange:-)

men det vil fungere fint.. du skal have mange rekords før det bliver mærkbart langsomt.
Avatar billede hojgaard Nybegynder
15. april 2008 - 20:47 #6
ok... umiddelbart ser det også ud til at performe fint ;)
Tak igen :)
Avatar billede kalp Novice
15. april 2008 - 20:54 #7
ingen årsag:)
Avatar billede HenrikSjang Nybegynder
15. april 2008 - 21:41 #8
Den her giver samme resultat, men er i mine øjne lidt pænere.

SELECT Recipe.Name
FROM Recipe
LEFT JOIN RecipeIngredient ON Recipe.RecipeID = RecipeIngredient.RecipeId
LEFT JOIN Ingredient ON RecipeIngredient.IngredientId = Ingredient.IngredientID
WHERE
    Ingredient.Name = 'curry'
    OR Ingredient.Name = 'VAND'
GROUP BY Recipe.Name
HAVING COUNT(*) = 2

Hvis man vil søge efter opskrifter med præcis 4 ingredienser, skal man bare tilføje et par "OR Ingredient.Name = 'xxx'" i WHERE klausulen, og så justere COUNT-tallet til sidst. På denne måde, vil man rent faktisk også kunne finde de opskrifter der indeholder flest muligt ingredienser, kan man fjerne "HAVING COUNT(*) = X", og så sortere efter antallet i stedet for... sådan her:

SELECT Recipe.Name, COUNT(*) AS AntalIngrediensMatch
FROM Recipe
LEFT JOIN RecipeIngredient ON Recipe.RecipeID = RecipeIngredient.RecipeId
LEFT JOIN Ingredient ON RecipeIngredient.IngredientId = Ingredient.IngredientID
WHERE
    Ingredient.Name = 'curry'
    OR Ingredient.Name = 'VAND'
    OR Ingredient.Name = 'OST'
GROUP BY Recipe.Name
ORDER BY 2 DESC
Avatar billede kalp Novice
16. april 2008 - 00:15 #9
så ville jeg lave den om til.

SELECT Recipe.Name
FROM Recipe
LEFT JOIN RecipeIngredient ON Recipe.RecipeID = RecipeIngredient.RecipeId
LEFT JOIN Ingredient ON RecipeIngredient.IngredientId = Ingredient.IngredientID
WHERE
    Ingredient.Name = 'Karry'
    OR Ingredient.Name = 'Salt'
GROUP BY Recipe.Name having
COUNT(*) = 3
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