简体   繁体   中英

MySQL query issue - matching multiple id's on a joined table

I've got 3 tables:

activities , tools and as these share an:m relation a table activities_tools .

Users on my website can select available tools on a filter. I'm now trying to get all activities, where the according tools are available.

So eg if I'm selecting tools with the id's 1 and 2 as available, I should be getting activities requiring either no tools, tool 1, tool 2 as well as activities that require both. Activities requiring other tools should be therefore excluded.

My query I have tried with so far looks like this:

SELECT activities.*, GROUP_CONCAT(tool) AS tools

FROM activities

LEFT JOIN activities_tools ON activities_tools.activity = activities.id

WHERE ISNULL(tool) OR tool IN (1,2)

GROUP BY activities.id

The (1,2) is the list of id's selected by the user.

The ISNULL part solves the problem of getting activities which have no tools applied. My issue now it though, that eg a tool having tools 1 AND 2 as required is getting returned when only one of them is available.

How can I check it against multiple values at once? I have tried fiddling with GROUP_CONCAT + HAVING + FIND_IN_SET and more.. but I can't come up with a solution.

Any help is appreciated.

I think you can use an extra NOT IN check:

SELECT activities.*, GROUP_CONCAT(tool) AS tools

FROM activities

LEFT JOIN activities_tools ON activities_tools.activity = activities.id

WHERE ISNULL(tool) OR (tool IN (1,2) AND activities.id NOT IN (SELECT activity FROM activities_tools WHERE tool NOT IN (1,2)))

GROUP BY activities.id

After trying some more things out and considering the input from here I've found my solution :)

SELECT activities.*, GROUP_CONCAT(tool) AS tools
FROM activities
LEFT JOIN activities_tools ON activities_tools.activity = activities.id
GROUP BY activities.id
HAVING ISNULL(tool) OR FIND_IN_SET(1, tools) = 0 OR FIND_IN_SET(2, tools) = 0 etc.

The "OR FIND_IN_SET(1, tools) = 1" parts are the id's to exclude. This part of the query is generated dynamically in PHP.

EDIT:

After reading a super cool trick here:

MySQL find_in_set with multiple search string

I have adjusted my solution to this:

SELECT activities.*, GROUP_CONCAT(tool) AS tools
FROM activities
LEFT JOIN activities_tools ON activities_tools.activity = activities.id
GROUP BY activities.id
HAVING CONCAT(",", toys, ",") NOT REGEXP ",(x|y|z)," 

Where x , y and z equal to the exclusion id's. That way the query is way shorter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM