简体   繁体   中英

In SQL Query a one-to-many relationship with condition

I have the following tables:

event_tbl

| event_id (PK) | event_date | event_location |
|---------------|------------|----------------|
| 1             | 01/01/2018 | Miami          |                
| 2             | 02/04/2018 | Tampa          |                    

performer_tbl

| performer_id (PK) | event_id (FK) | genre |
|-------------------|---------------|-------|
| 1                 | 1             |  A    |
| 2                 | 1             |  B    |
| 3                 | 2             |  A    |
| 4                 | 2             |  C    |

I want to find events that have both genre A and genre B (should just return event 1), and I'm lost on writing the query. Maybe I just haven't had enough coffee, but all I can come up with is doing two derived columns with a case statement that count either genre and group by the event_id, then filtering both to >0. It just doesn't seem very elegant.

This should work in any SQL database (at least in mysql, sql server, postgres or oracle)

    select event_tbl.* FROM (
    select event_id
    from performer_tbl
    where genre = 'A'
    GROUP BY event_id) a_t
    INNER JOIN (select event_id
    from performer_tbl
    where genre = 'B'
    GROUP BY event_id) b_t
    ON a_t.event_id = b_t.event_id
    INNER JOIN event_tbl
    ON event_tbl.event_id = a_t.event_id

if you are using sql server, check below:

  Select * From 
  event_tbl 
  where event_id 
  IN
  (
  select event_id 
   from performer_tbl as A
  where exists (select 1 
                from perfoermer_tbl as B 
                where B.event_id = A.event_id and B.genre = 'A')
        and
        exists (select 1 
                from perfoermer_tbl as B 
                where B.event_id = A.event_id and B.genre = 'B')
  )

This should do the job (in MySQL, for other DBMS the syntax can be varied easily):

SELECT
e.event_id
FROM
event_tbl e
JOIN performer_tbl p USING(event_id)
GROUP BY e.event_id
HAVING SUM(IF(p.genre = 'A', 1, 0)) >= 1 AND SUM(IF(p.genre = 'B', 1, 0)) >= 1;

This also works using left joins: (Since there are no function calls or sub-selects, it is fast. Also, it's usable in most SQL engines.)

SELECT DISTINCT
   p1.event_id
   ,e.event_date
   ,e.event_location
FROM
   performer_tbl as p1
   inner join event_tbl as e on
      p1.event_id = e.event_id 
   left outer join performer_tbl as p2 on
      p1.event_id = p2.event_id 
      AND p2.genre = 'A'
   left outer join performer_tbl as p3 on
      p1.event_id = p3.event_id 
      AND p3.genre = 'B'
WHERE
    p2.genre IS NOT NULL
    AND p3.genre IS NOT NULL;

If I correctly understand what you need, you can try this:

Select *
  from event_tbl e
 where exists (select *
                 from performer_tbl p
                where p.event_id = e.event_id
                  and p.genre in ('A', 'B'))

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