简体   繁体   中英

SQL select one row from table 1 joining on multiple rows in table 2

So I have two tables, the first would be users_

Name
------
Carol
Sue

and the second would be interests_

Name        Interest
----------------------
Carol       Books
Carol       Dancing
Carol       Sports    
Sue         Books
Sue         Dancing

The user will be presented with checkboxes to select a match based on criteria for similar interests like this

在此处输入图片说明

So if the user selected Books and Dancing as interests for their match, what type of sql query would I build to combine multiple rows in interests and ensure that the result is Sue, since she had Books and Dancing as interests but NOT Sports?

any help will go a long way thanks!

so basically to do this build a negative list of users that have more than those two and then select the others

SELECT u.name 
FROM users_ u     
JOIN interests_ i ON i.name = u.name
JOIN
(   SELECT u.name 
    FROM users_ u
    JOIN interests_ i ON i.name = u.name
    WHERE i.interest NOT IN('Books', 'Dancing')
) t
WHERE u.name <> t.name 
  AND i.interest IN('Books', 'Dancing')
GROUP BY u.name
HAVING COUNT(u.name) = 2;

DEMO

Here is the simple way to do it

select
i.name 
from interests i
where i.interest in ('Books','Dancing')
and not exists
(
  select 1 from interests i1
  where interest not in ('Books','Dancing')
  AND i.name = i1.name
)
group by i.name
having count(*) = 2

DEMO

One way to achieve this result:

SELECT u.name
  FROM users_ u
  JOIN interests_ n01 ON n01.name = u.name AND n01.interest = 'Books'
  JOIN interests_ n02 ON n02.name = u.name AND n02.interest = 'Dancing'
  LEFT JOIN interests_ x01 ON x01.name = u.name AND x01.interest = 'Sports'
  LEFT JOIN interests_ x02 ON x02.name = u.name AND x01.interest = 'Wine'
 WHERE x01.name IS NULL
   AND x02.name IS NULL

This approach requires a JOIN for each interest to be "included", and an anti-join to each interest to be "excluded". This approach is flexible, but can become unwieldy for a large number of interests.

To look for matches for ONLY the specified interests, without having to list out all the interests not to match, we could use an anti-join to find rows in interests that don't match:

SELECT u.name
  FROM users_ u
  JOIN interests_ n01 ON n01.name = u.name AND n01.interest = 'Books'
  JOIN interests_ n02 ON n02.name = u.name AND n02.interest = 'Dancing'
  LEFT
  JOIN interests_ o 
    ON o.name = u.name
   AND o.interest NOT IN ('Books','Dancing')
 WHERE o.name IS NULL

Another approach would be to make use of JOIN operations and a COUNT() aggregate, eg

SELECT u.name
  FROM users_ u
  JOIN interests_ n 
    ON n.name = u.name 
   AND n.interest IN ('Books','Dancing')
  LEFT
  JOIN interests_ o
    ON o.name = u.name
   AND o.interest NOT IN ('Books','Dancing')
 WHERE o.name IS NULL
 GROUP BY u.name
HAVING COUNT(DISTINCT n.interest) = 2

There are some other approaches (these are just some examples).

Make it use of SQL in operator

select * from  interests_ where Interest in ('Books', 'Dancing') and Interest not in ('Sports');

EDIT 1

This worked for me

SELECT * FROM user_ WHERE EXISTS ( 
    SELECT i.Name, count(distinct i.Interest) FROM interests_ as i
    WHERE i.Name=user_.Name
    AND i.Interest IN ('Books','Dancing')
    GROUP BY i.Name
    HAVING count(distinct i.Interest) = 2
);

REF : SQL equivalent of IN operator that acts as AND instead of OR?

Left Joins can be very useful. You could try this.

SELECT users_.*
FROM users_
    LEFT JOIN interests_
    ON users_.Name = Interests_.Name
            WHERE interests_.Interests = 'Books'
            AND interests_.Interests = 'Dancing'

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