tags:

views:

648

answers:

6

This is a very very important sql query after which my whole website is based..

and its not working..

Its difficult to explain without an example..

There are 2 tables, One is IngredientsTable and other one is ProductsTable.

In IngredentsTable i have the following

  1. Bread
  2. ChickenBreast
  3. Noodles
  4. Mayonaise
  5. Cheese
  6. Ketchup
  7. Butter

And the ProductsTable

  1. Spageti
  2. Chicken Breast Sandwich

And there is a MAPPING TABLE that connects both tables. It has IngredientID and ProductID

Now, Mapping table Chicken Breast Sandwich - Bread

Chicken Breast Sandwich - Mayonase

Chicken Breast Sandwich - Cheese

Chicken Breast Sandwich - Ketchup

Spageti --- Noodles

Spageti --- Cheese

Spageti --- Ketcup

You'll notice that Cheese and Ketchup are common entries to both Chicken Breast And Spageti

I want to write an sql query that gets the IDs OF PRODUCTS THAT HAVE THE SPECIFIED INGREDIENTS.

I'm able to achieve it partially with the following query

SELECT 
  ProductTable.id,
  ProductTable.Name 
FROM ProductTable 
INNER JOIN MappingTable 
  ON ProductTable.id = MappingTable.ProductID
WHERE MappingTable.IngredientID =  5;

Suppose 5 was cheese, I'm successfully able to get results of Chicken Breast Sandwich and Spageti

But If i add One more, WHERE MappingTable.IngredientID = 5,6; 6 being Bread, it should only show me an Chicken Breast Sandwich and NOT Spageti

I'm getting Error "," syntax.. even "and" is not getting results.

How can I check multiple Ingredients like WHERE MappingTable.IngredientID = 5,6,7;

ANY HELP IS GREATLY APPRECIATED!!!

i need to have this in a single query..

Please show me options

+1  A: 
WHERE MappingTable.IngredientID IN (5, 6, 7)

Sorry, my bad. How about this?:

SELECT 
  p.id,
  p.Name 
FROM ProductTable p
INNER JOIN (SELECT * FROM MappingTable WHERE IngredientID IN (5, 6, 7)) m
  ON p.id = m.ProductID
flayto
I don't think so... With this any product with 5 OR 6 will pass, not with 5 AND 6 both
Svetlozar Angelov
Its not working this way.. IS SQLite responsible???
A: 

You need to link to the mapping table individually for each ingredient:

SELECT 
  ProductTable.id,
  ProductTable.Name 
FROM ProductTable 
INNER JOIN MappingTable AS MappingTable1
  ON ProductTable.id = MappingTable1.ProductID
  AND MappingTable1.IngredientID = 5
INNER JOIN MappingTable AS MappingTable2
  ON ProductTable.id = MappingTable2.ProductID
  AND MappingTable2.IngredientID = 6

If you use the IN operator as other posters have suggested, you will get both spaghetti and chicken sandwich for bread and cheese because IN is inherently an OR type query.

Jeff Hornby
+2  A: 

With 2 queries you could use intesection of your results

But you say that you want it in one query.

A close approximation would be to have group by statement and count amount of rows received from your result. It must be equal to amount of your ingredients. It will not work if your ingredients repeat more than once in the same product though.

something along this line for 2 Ingredient IDs:

SELECT ProductTable.id, ProductTable.Name FROM ProductTable 
INNER JOIN MappingTable ON ProductTable.id = MappingTable.ProductID 
WHERE MappingTable.IngredientID in (5,6) group by ProductTable.id, ProductTable.Name 
HAVING count(*) = 2;
dimus
This works too :) thanks dimus
A: 

Its not working.. The IN thing and the statements you made welbog. OR brings in everything. I want it to be and.. but event that isnt working!

Im using sqlite

+1  A: 

First of all, edit your question so that the data in your example tables matches the example question... If 5 is cheese and 6 is Bread, then make the Ingredients table match that. it's confusing otherwise.

Secondly, you're stating that ", it should only show me an Chicken Breast Sandwich and NOT Spageti" makes me think you want to know the products that have ALL the listed ingfrediants, not ANY of them. If so then you want the following

  Select P.id,  P.Name 
  FROM ProductTable P 
  Where Exists (Select * From Mapping Table
                Where ProductId = P.ProductId
                    And IngredientId = 5)
    And Exists (Select * From Mapping Table
                Where ProductId = P.ProductId
                    And IngredientId = 6)
    And Exists (Select * From Mapping Table
                Where ProductId = P.ProductId
                    And IngredientId = 7)

or, us8ng counting logic:

   Select P.id,  P.Name 
   From ProductTable P 
   Where (Select Count(Distinct IngredientId)
          From MappingTable M
          Where ProductId = P.ProductId 
            And IngredientId In (5,6,7)) = 3
Charles Bretana
edited the question, and u got it, it worked great with the first query,, although not with the reverse logic
A: 

This should work, although you need to supply two 'variables' to it - the first is a comma-delimited set of IngredientIDs, the second (@IngredientsCount) is the number of ingredients in that list.

SELECT ProductsTable.id, ProductTable.Name
FROM ProductsTable
INNER JOIN (SELECT ProductID, Count(*) AS Ingredients
    FROM MappingTable
    WHERE IngredientID IN (...ids of ingredients here...)
    GROUP BY ProductID
    HAVING Count(*) = @IngredientsCount) AS ProductIngredients ON ProductsTable.ProductID = ProductIngredients.ProductID

If it's possible for the same ingredient to be recorded twice (although your table structure doesn't look it allows for that, and it's probably not necessary), switch the two Count(*) to Count(Distinct IngredientID) and change @IngredientCount to be the number of different ingredients used.

CodeByMoonlight