Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Select only rows where multiple relationships exist

Tags:

sql

select

mysql

Given a parent table 'parent'

╔═══════════╦══════════╗
║ PARENT_ID ║   NAME   ║
╠═══════════╬══════════╣
║         1 ║ bob      ║
║         2 ║ carol    ║
║         3 ║ stew     ║
╚═══════════╩══════════╝

and a many-many relationship table 'rel' between parent and a (here unspecified) property table

╔═══════════╦═══════════╗
║ PARENT_ID ║  PROP_ID  ║
╠═══════════╬═══════════╣
║         1 ║         5 ║
║         1 ║         1 ║
║         2 ║         5 ║
║         2 ║         4 ║
║         2 ║         1 ║
║         3 ║         1 ║
║         3 ║         3 ║
╚═══════════╩═══════════╝

How can I select all parents that have all of a specified set of relationships? E.g. with the sample data, how can I find all parents that have both property 5 and 1?


edit: Same question but with requirement for an exact match: SQL Select only rows where exact multiple relationships exist

like image 483
Laizer Avatar asked Dec 31 '12 06:12

Laizer


People also ask

How do I select one to many relationship in SQL?

How to implement one-to-many relationships when designing a database: Create two tables (table 1 and table 2) with their own primary keys. Add a foreign key on a column in table 1 based on the primary key of table 2. This will mean that table 1 can have one or more records related to a single record in table 2.

Can we use multiple values in WHERE clause in SQL?

The SQL IN OperatorThe IN operator allows you to specify multiple values in a WHERE clause.

How do I select all rows except one in SQL?

The SQL EXCEPT operator is used to return all rows in the first SELECT statement that are not returned by the second SELECT statement. Each SELECT statement will define a dataset. The EXCEPT operator will retrieve all records from the first dataset and then remove from the results all records from the second dataset.


3 Answers

This is called Relational Division

SELECT  a.name
FROM    parent a
        INNER JOIN rel b
            ON a.parent_ID = b.parent_ID
WHERE   b.prop_id IN (1,5)
GROUP BY a.name
HAVING COUNT(*) = 2
  • SQLFiddle Demo Link

UPDATE 1

if unique constraint was not enforce on prop_id for every parent_id, DISTINCT is needed on this case.

SELECT  a.name
FROM    parent a
        INNER JOIN rel b
            ON a.parent_ID = b.parent_ID
WHERE   b.prop_id IN (1,5)
GROUP BY a.name
HAVING COUNT(DISTINCT b.prop_id) = 2
like image 112
John Woo Avatar answered Nov 14 '22 03:11

John Woo


I just saw this solution to a different question that seems to fit this case:

 SELECT distinct parent_id
 FROM rel as T1
 INNER JOIN rel as T2
 ON T1.parent_id = T2.parent_id
 WHERE T1.prop_id = '1' and T2.prop_id = '5'
like image 22
Laizer Avatar answered Nov 14 '22 02:11

Laizer


I've written your table in to a CTE, let me know if you require assistance in adapting the code for your purposes.

;WITH MyTable AS
(
    SELECT   parent_id = 1
            ,prop_id = 5    UNION ALL
    SELECT 1,1              UNION ALL
    SELECT 2,5              UNION ALL
    SELECT 2,4              UNION ALL
    SELECT 2,1              UNION ALL
    SELECT 3,1              UNION ALL
    SELECT 3,3              
)
,Eval AS
(
    SELECT   parent_id
            ,PropEval   = SUM(CASE WHEN prop_id IN (1,5) THEN 1 ELSE 0 END)
    FROM MyTable
    GROUP BY parent_id
)
SELECT parent_id
FROM Eval
WHERE PropEval = 2
like image 35
MarkD Avatar answered Nov 14 '22 03:11

MarkD