Reputation: 2476
lets say i have the following two MySQL-Tables:
item: _ID,_CAT_ID,...
item_attribute: _ID,_ITEM_ID,...
i want to (filter items) get ONLY items which have ALL selected attributes (1,32,555,...an array of selected attributes )
something like this:
SELECT _I.*
FROM item _I
INNER JOIN item_attribute _IA
ON (_I._ID = _IA._ITEM_ID AND (_IA._ID=1 OR _IA._ID=132, ...))
WHERE _I._CAT_ID=? ORDER BY _I._LAST_UPDATE ASC;"
this "wrong" statement returns items when one(due to OR) of the linked ids found, what i want is: only items which have all linked attributes.
if i change
(_IA._ID=1 OR _IA._ID=132 OR...)
to
(_IA._ID=1 AND _IA._ID=132 AND ...)
no matches and this makes sense, but how to rewrite the statement to get correct matches?
UPDATE:
here is a sqlfiddle: http://sqlfiddle.com/#!9/0f8ebe/6
CREATE TABLE item
(`id` int, `pid` int, `name` varchar(55))
;
INSERT INTO item
(`id`, `pid`, `name`)
VALUES
(1, 2, 'A'),
(2, 2, 'B'),
(3, 2, 'C')
;
CREATE TABLE att
(`id` int, `pid` int, `name` varchar(55))
;
INSERT INTO att
(`id`, `pid`, `name`)
VALUES
(7, 1, 'red'),
(7, 3, 'red'),
(2, 1, '30cm'),
(1, 3, '40cm'),
(5, 2, 'blue'),
(1, 2, '40cm')
;
SELECT *
FROM item;
SELECT *
FROM att;
/* expected: items which are red AND 40cm, result should be then only item C (id=3)*/
SELECT _I.name
FROM item _I
INNER JOIN att _IA
ON (_I.id = _IA.pid AND (_IA.id=7 AND _IA.id=1))
WHERE _I.pid=2 GROUP BY _I.id;
SOLUTION http://sqlfiddle.com/#!9/0f8ebe/8 (using Drews Answer):
SELECT _I.name,count(_IA.id) as theCount
FROM item _I
INNER JOIN att _IA
ON (_I.id = _IA.pid) AND _IA.id in (7,1)
WHERE _I.pid=2
group by _I.id
having theCount=2
Upvotes: 3
Views: 61
Reputation: 4747
It should bring all the items that have 3 particular item attributes (red, 40cm, large).
SELECT kk.*
FROM item AS kk
INNER JOIN (
SELECT aa.id
FROM (
SELECT DISTINCT bb.id
FROM item AS bb
INNER JOIN att AS cc
ON bb.id = cc.pid
WHERE cc.name IN ('red', '40cm', 'large')
GROUP BY bb.id
HAVING COUNT(*) = 3
) AS aa
) AS _aa
ON kk.id = _aa.id;
Result:
id pid name
3 2 C
Upvotes: 1
Reputation: 24959
I think it is 7 lines of code, reading the tidbits from your question:
SELECT _I.col1,_I.col2,count(_IA._ID) as theCount
FROM item _I
INNER JOIN item_attribute _IA
ON (_I._ID = _IA._ITEM_ID) AND _IA._ID in (1,32,555)
WHERE _I._CAT_ID=? ORDER BY _I._LAST_UPDATE ASC
group by _I.col1,_I.col2
having theCount=3
Note that theCount
alias is allowable in a having
clause.
Also note I put in col1 and col2 in line one, expand accordingly. The point is to list them, so the group by
in line6 can mimic them for the non-aggregated columns. The value in line 7 must match the count of the values in the in clause
Upvotes: 1