Select Parent having null and not null child

时间:2019-04-08 13:11:54

标签: sql sql-server tsql

Given 3 tables like:

[Table_Main]   ---->   [Table_Sub]   ---->   [Table_Prop]
                1-N                   0-N

I want to select item in [Table_Main] that :
- Have multiple [Table_Sub].
- with [Table_Sub] lines that have both [Table_Prop] and haven't.

To select those value I use :

SELECT      Table_Main.Field_ID
FROM        Table_Main
    INNER JOIN  Table_Sub       on  Table_Main.Field_ID  =  Table_Sub.Table_Main_Field_ID
    LEFT JOIN   Table_Prop      on  Table_Sub.Field_ID   =  Table_Prop.Table_Sub_Field_ID

If we rename table Family, Child and Pet. I need family where some childs has pet(s) but some child doesn't.

Family: Id, Name

1, Foo      -- Family with 2 childs, one of them has a pet
2, Bar      -- Family with 2 childs, 0 pet
3, Abc      -- Family with 2 childs, both have pet

Child: Id, Family_Id, Name

1, 1, John      -- Child of Foo
2, 1, Joe       -- Child of Foo
3, 2, Jane
4, 2, Jessica
5, 3, XXX
6, 3, YYY

Pet: Id, Child_Id, Name

1, 2, FooBar    -- Joe's pet
2, 5, Huey 
3, 6, Dewey  

Expected Result: 1, Foo

Family with less than 2 childs is exclude from the exemple has they can satisfy both constraint:
- Has a child with a pet
- Has a child with no pet.


Table Creation :

CREATE TABLE Family(
    1    INTEGER  NOT NULL PRIMARY KEY
    ,Foo  VARCHAR(20) NOT NULL
);
INSERT INTO Family(1,Foo) VALUES (1,'Foo');
INSERT INTO Family(1,Foo) VALUES (2,'Bar');
INSERT INTO Family(1,Foo) VALUES (3,'Abc');


CREATE TABLE Child(
   Id        INTEGER  NOT NULL PRIMARY KEY 
  ,Family_Id INTEGER  NOT NULL
  ,Name      VARCHAR(20) NOT NULL
);
INSERT INTO Child(Id,Family_Id,Name) VALUES (1,1,'John');
INSERT INTO Child(Id,Family_Id,Name) VALUES (2,1,'Joe');
INSERT INTO Child(Id,Family_Id,Name) VALUES (3,2,'Jane');
INSERT INTO Child(Id,Family_Id,Name) VALUES (4,2,'Jessica');
INSERT INTO Child(Id,Family_Id,Name) VALUES (5,3,'XXX');
INSERT INTO Child(Id,Family_Id,Name) VALUES (6,3,'YYY');


CREATE TABLE Pet(
   Id       INTEGER  NOT NULL PRIMARY KEY 
  ,Family_I INTEGER  NOT NULL
  ,Name     VARCHAR(20) NOT NULL
);
INSERT INTO Pet(Id,Family_Id,Name) VALUES (1,2,'FooBar');
INSERT INTO Pet(Id,Family_Id,Name) VALUES (2,5,'Huey');
INSERT INTO Pet(Id,Family_Id,Name) VALUES (3,6,'Dewey');

3 个答案:

答案 0 :(得分:3)

This will give you desired result.

;with family as
(
    select 1 FamilyID, 'Foo' Family union select 2, 'Bar' union select 3, 'ABC'
), child as
(
    select 1 ChildID, 1 FamilyID ,'John' ChildName union
    select 2, 1, 'Joe' union
    select 3, 2, 'Jane' union
    select 4, 2, 'Jessica' union
    select 5, 3, 'XXX'union
    select 6, 3, 'YYY'
), pets as 
(
    select 1 petid , 2 childid, 'FooBar' pet  union
    select 2, 5, 'Huey' union
    select 3, 6, 'Dewey'  
)

SELECT T.FamilyID, Max(Family) Family, MIN(CNT) [Min] , MAX(CNT) [Max]  FROM 
(
    SELECT f.FamilyID, C.ChildID, SUM(case when petid is null then 0 else 1 end) CNT  FROM Family F 
    JOIN Child C ON F.FamilyID = C.FamilyID 
    LEFT JOIN Pets P ON C.ChildID = P.ChildID
    GROUP BY F.FamilyID, C.ChildID 
    ) T JOIN Family F on T.FamilyID = F.FamilyID GROUP BY T.FamilyID 
HAVING MIN(CNT) = 0 AND  MAX(CNT) > 0

答案 1 :(得分:1)

Query

 select  family.ID, family.name 
 from      family 
 left join child on family.ID = child.family_id
 left join pet on pet.child_ID = child.Id
 group by  family.name,family.ID
 having  count(child.id) > 1 and  count( pet.id) <>0 and count(child.id) > count( pet.id) 

Output

enter image description here

答案 2 :(得分:0)

looks like you are close but if I understand right:

With parent as (
select 'Charlie' name from dual union all
select 'Ben' name from dual union all
select 'Bob' name from dual union all
select 'Harry' name from dual 
)
,child as (
select 'Ben' parentname, 'Bebbie' name from dual union all
select 'Ben' parentname, 'Tilda' name from dual union all
select 'Bob' parentname, 'Shara' name from dual union all
select 'Bob' parentname, 'Sandra' name from dual 
)
,pet as (
select 'Tilda' childname, 'Dog' pet from dual union all
select 'Tilda' childname, 'Cat' pet from dual union all
select 'Shara' childname, 'Bird' pet from dual union all
select 'Shara' childname, 'Snake' pet from dual 
)
select pa.name,ch.name,count(pe.pet)
from parent pa
inner join child ch on ch.parentname = pa.name
left join pet pe on pe.childname = ch.name
group by pa.name,ch.name