How to limit query results to exact group match

最后都变了- 提交于 2019-12-10 18:07:50

问题


I have a table like the following:

user  | item
-------------
   X  | Apple
   X  | Orange
   X  | Pear
   Y  | Orange
   Y  | Pear
   Z  | Apple
   Z  | Orange

My goal is to have 3 search options: ANY, ALL (At Least), EXACT

Where

  • ANY returns a list of users who have at least one item searched for, so searching for "Apple" - ANY would return X,Z, searching for "Apple, Orange" - ANY would return X,Y,Z

  • ALL returns a list of users who have all items searched for, so searching for "Apple" - ALL would return X,Z, searching for "Apple, Orange" - ALL would return X,Z

  • EXACT returns a list of users who have all items searched for and no other items, , so searching for "Apple" - EXACT would return no results, searching for "Apple, Orange" - EXACT would return Z

I have the first two worked out:

ANY

SELECT user FROM users_items WHERE item IN ($item_array);

ALL

SELECT user FROM users_items WHERE item IN ($item_array) 
GROUP BY user HAVING COUNT(DISTINCT item) = $item_search_count;

But I can't figure out how to do the exact search. The best I can come up with is:

SELECT user FROM users_items WHERE item IN ($item_array) AND
user NOT IN (
     SELECT user FROM users_items WHERE item NOT IN ($item_array)
)
GROUP BY user HAVING COUNT(DISTINCT item) = $item_search_count;

This didn't work at first because in the real data set, either user or item could be null but when I updated it to:

SELECT user FROM users_items WHERE item IN ($item_array) AND
user NOT IN (
     SELECT user FROM users_items WHERE item NOT IN ($item_array) 
     AND user IS NOT NULL AND item IS NOT NULL
)
GROUP BY user HAVING COUNT(DISTINCT item) = $item_search_count;

This worked, but the query is really slow.

Is there a better way to query for "all items that match set, exclude items that don't match set"?


回答1:


Use the magic group_concat function:

SELECT user
FROM (
    SELECT user, group_concat(item) as items
    from user_items
    group by 1) x
WHERE items = 'Apple,Orange';

Note: The list of items you're searching for (eg 'Apple,Orange') must be in alphabetic order




回答2:


The following works, and should solve your size problem. But it could be slow, just try it with your real data.

Select 
    User 
FROM 
    users_items 
WHERE 
    User NOT IN
    (
        SELECT
            users.User
        FROM 
            users_items AS users
        JOIN 
            users_items AS users2 ON users.User = users2.User
        WHERE
            users2.Item NOT IN ('Apple','Orange')
        GROUP BY 
            users.User
    )
GROUP BY 
    User


来源:https://stackoverflow.com/questions/8468117/how-to-limit-query-results-to-exact-group-match

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!