Find groups with matching rows

前端 未结 5 581
庸人自扰
庸人自扰 2020-12-22 01:11

I have a table of people (CarOwners) and the types of cars they own

+-------+-------+
| Name  | Model |
+-------+-------+
| Bob   | Camry |
| Bo         


        
5条回答
  •  北海茫月
    2020-12-22 02:02

    This counts the number of rows for each name using a common table expression(cte) with count() over().

    Then the matches cte uses a self-join where the names do not match, the models match, the count of models for each name match, and one of those names is 'Lisa'. The having clause ensures that count of matched rows (count(*)) matches the number of models that name has.

    matches itself would only return the name of each person, so we join back to the source table t to get the full list of models for each match.

    ;with cte as (
      select *
        , cnt = count(*) over (partition by name)
      from t
    )
    , matches as (
      select x2.name
      from cte as x 
        inner join cte as x2
           on x.name <> x2.name
          and x.model = x2.model
          and x.cnt   = x2.cnt 
          and x.name  = 'Lisa'
      group by x2.name, x.cnt
      having count(*) = x.cnt
    )
    select t.* 
    from t
      inner join matches m
        on t.name = m.name
    

    rextester demo: http://rextester.com/SUKP78304

    returns:

    +-------+-------+
    | name  | model |
    +-------+-------+
    | Kevin | Civic |
    | Kevin | Focus |
    +-------+-------+
    

    We could also write it without the ctes, but it makes it a little harder to follow:

    select t.*
    from t 
      inner join (
        select x2.Name
        from (
          select *, cnt = count(*) over (partition by name) 
          from t 
          where name='Lisa'
          ) as x
          inner join (
          select *, cnt = count(*) over (partition by name) 
          from t
          ) as x2
            on x.name <> x2.name
           and x.model = x2.model
           and x.cnt   = x2.cnt 
        group by x2.name, x.cnt
        having count(*) = x.cnt
      ) as m 
        on t.name = m.name
    

提交回复
热议问题