Reputation: 386
I'm currently working on an inventory system. Of course, we want a search function that can lookup items with multiple properties where all search terms match in a single item (but maybe not on a single property).
Items contain multiple properties (joined by the item ID on each property) and properties contain value (see tables at the end). I also cannot change the database.
For now, I tried that:
SELECT
i0_.itm_id AS itm_id_0,
i0_.itm_inventory_num AS itm_inventory_num_1,
i0_.itm_datetime AS itm_datetime_2,
i0_.itm_locked_by AS itm_locked_by_3,
i0_.stp_id AS stp_id_5
FROM item i0_
INNER JOIN property p1_
ON i0_.itm_id = p1_.itm_id
WHERE
p1_.par_value LIKE '%hP Dc5800%' AND
p1_.par_value LIKE '%coopsco%'
GROUP BY
i0_.itm_id,
i0_.itm_inventory_num,
i0_.itm_datetime,
i0_.itm_locked_by,
i0_.stp_id
But I know the AND
between the two LIKE
is not the right thing to do, because that means a property needs to match both keywords. And if I use an OR
, only one property needs to match for that item to be returned, which wouldn't really make sense for search function.
The guy that tried it before me was storing all the property values inside a "keywords" field on each items, but I really don't like that since when updating a property, you also have to update the keywords. It also doesn't really make sense when the information is already available in the properties.
So, how would I make that work? As a reminder, I need to get items with properties that match all the search keywords, but not all keywords in one parameters.
Item
----------
itm_id INT
itm_datetime DATETIME
stp_id INT
itm_locked_by NVARCHAR(15)
itm_deleted_at DATETIME
itm_inventory_num NVARCHAR(12)
Property
----------
par_id INT
itm_id INT
ptl_id INT
par_value NVARCHAR(200)
par_deleted_at DATETIME
Upvotes: 0
Views: 637
Reputation: 164089
Maybe you need to join property
twice:
SELECT DISTINCT
i0_.itm_id AS itm_id_0,
i0_.itm_inventory_num AS itm_inventory_num_1,
i0_.itm_datetime AS itm_datetime_2,
i0_.itm_locked_by AS itm_locked_by_3,
i0_.stp_id AS stp_id_5
FROM item i0_
INNER JOIN property p1_ ON i0_.itm_id = p1_.itm_id AND p1_.par_value LIKE '%hP Dc5800%'
INNER JOIN property p2_ ON i0_.itm_id = p2_.itm_id AND p2_.par_value LIKE '%coopsco%'
I used DISTINCT
instead of GROUP BY
because aggregation is not needed in this case.
Or with EXISTS
:
SELECT
i0_.itm_id AS itm_id_0,
i0_.itm_inventory_num AS itm_inventory_num_1,
i0_.itm_datetime AS itm_datetime_2,
i0_.itm_locked_by AS itm_locked_by_3,
i0_.stp_id AS stp_id_5
FROM item i0_
WHERE
EXISTS (SELECT 1 FROM property p WHERE i0_.itm_id = p.itm_id AND p.par_value LIKE '%hP Dc5800%')
AND
EXISTS (SELECT 1 FROM property p WHERE i0_.itm_id = p.itm_id AND p.par_value LIKE '%coopsco%')
Upvotes: 2
Reputation: 1269693
I think you want or
and then a having
clause:
WHERE p1_.par_value LIKE '%hP Dc5800%' OR p1_.par_value LIKE '%coopsco%'
. . .
GROUP BY . . .
HAVING SUM(CASE WHEN p1_.par_value LIKE '%hP Dc5800%' THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN p1_.par_value LIKE '%coopsco%' THEN 1 ELSE 0 END) > 0
Upvotes: 1