MS SQL Server:多个表之间的复杂JOIN查询

时间:2014-10-24 14:34:06

标签: sql sql-server join

我通常使用Ruby on Rails并通过Ruby适配器接口编写大部分数据库查询。

但是,这一次,我实际上是在创建一个数据库视图,需要编写SQL本身,以便可以查询此视图(使用旧系统)。

我试图让这些例子比系统更简单但仍能解决特定问题。

在伪代码中,以下是关系:

  • parents has_many children belongs_to parents
  • children has_many pets belongs_to children
  • pets belongs_to pet_types
  • pet_types has_many pets

这是通过标准的foreign_key关系完成的(即children表有一个parent_id列。

目标

我想要完成的是列出所有父母和最后一个孩子(通过created_at)最后一只宠物猫(通过created_at)。如果parent没有任何子女,则null将其他字段删除。

我对SQL的尝试基本上是一堆没有正确过滤的LEFT OUTER JOINs

-------------------------------------------------------------
| id | parent_name | child_name | pet_name | pet_type_value |
-------------------------------------------------------------
|  1 | Bob         | Jeremy     | Wildfire | cat            |
-------------------------------------------------------------
...more records...

表格

parents
--------------------------
| id | name | created_at |
--------------------------
| 1  | Bob  | 2014-10... |
| 2  | John | 2014-10... |
| 3  | Suzy | 2014-10... |
--------------------------

children
----------------------------------------
| id | parent_id | name   | created_at |
----------------------------------------
| 1  |         1 | Jeremy | 2014-10... |      
| 2  |         1 | Katy   | 2014-10... |
| 3  |         2 | Garet  | 2014-10... |
----------------------------------------

pets
-------------------------------------------------------
| id | child_id | name     | pet_type_id | created_at |
-------------------------------------------------------
| 1  |        1 | Wildfire |           1 | 2014-10... |       
| 2  |        1 | Ninja    |           1 | 2014-10... |
| 3  |        2 | Grumpy   |           2 | 2014-10... |
-------------------------------------------------------

pet_types
--------------
| id | value |
--------------
| 1  | cat   |
| 2  | dog   |
--------------

原创尝试

这是我最初想出的那些没有用的东西......我不是一个SQL开发人员/编码员,你可以明白地说。请注意,我已将其从原始表/列中稍微清理一下并将其转换为示例表:

  SELECT
    parents.id as id,
    parents.name as name,
    parents.created_at as created_at,
    pet_types.value as pet_type_value,
    children.id as child_id,
    children.name as child_name
  FROM
    parents
      LEFT OUTER JOIN (
          SELECT
            pet_types.value as pet_type_value,
            children.parent_id as parent_id
          FROM children
            LEFT OUTER JOIN pets
              ON pets.child_id = children.id
            LEFT OUTER JOIN pet_types
              ON (
                pets.pet_type_id = pet_types.id
                AND pet_types.name = 'cat'
              )
          ) AS children
        ON (children.parent_id = parents.id)
  WHERE
    children.parent_id = parents.id
  ORDER BY parents.id

5 个答案:

答案 0 :(得分:1)

您可以尝试外部应用,如下所示

select  * from parent par
outer apply 
   ( select top 1 * from children child
         outer apply
            ( select top 1 * from pets left join pet_types where child.id=pets.child_id
                order by created_at desc) pet
 where par.id=child.parent_id
  order by created_at desc) child

答案 1 :(得分:0)

可能你看起来像这样:

select par.name as parent_name,child.name as child_name,
pet.name as pet_name,ptype.value as pet_type_value from Parents par
left join children child 
on par.id=child.parent_id
left join pets pet
on child.id=pet.child_id
left join pet_types ptype
on pet.pet_type_id=ptype.id

答案 2 :(得分:0)

with cte 
as (
     select p.id
    , p.name
    , c.name
    , ps.name
    ,pt.name,
    Row_Number() over(partition by c.parent_id order 
     order by ps.created_at desc, c.created_at desc) as rn
    from Parent p left outer join child c on p.id = c.parent_id
    inner join pets ps on ps.child_id = c.id
    inner join pet_types pt on ps.pet_type_id = pt.id
    where pt.value = 'cat')

select c.* from
cte c
where c.rn = 1

答案 3 :(得分:0)

试试这个:

SELECT 
  t0.ParentName, 
  t0.ChildName, 
  t0.PetName, 
  t0.PetValue 
FROM 
    (SELECT
       t1.name as ParentName,
       t2.name as ChildName,
       t3.name as PetName,
       t4.value as PetTypeValue,
       MAX(t2.created_at) as MaxDateChild, 
       MAX(t3.created_at) as MaxDatePet
   FROM
       Parents t1
       LEFT OUTER JOIN 
       children t2
       ON t1.id = t2.parent_id
       LEFT OUTER JOIN 
       pets t3
       ON t2.id = t3.child_id
       LEFT OUTER JOIN 
       pet_types t4
       ON t3.pet_type_id= t4.id
    GROUP BY 
       t1.name,
       t2.name,
       t3.name,
       t4.value
    ) t0

答案 4 :(得分:0)

试试这个:


    select p.ID,p.name as parent_name,c.name as child_name,c.pet_name, c.pet_type_value
    from parents p
    left join (
       select c1.id,c1.parent_id,c1.name,c1.created_at,p.name as pet_name, p.pet_type_value from children c1
       inner join (select parent_id,MAX(created_at) as created_at from children group by parent_id) c2 on c1.parent_id=c2.parent_id and c1.created_at=c2.created_at
       left join (
          select p1.id,p1.child_id,p1.name,p1.created_at,pt.value as pet_type_value from pets p1
          inner join (select child_id,MAX(created_at) as created_at from pets group by child_id) p2 on p1.child_id=p2.child_id and p1.created_at=p2.created_at
          inner join pet_types pt on p1.pet_type_id=pt.id
          group by p1.id,p1.child_id,p1.name,p1.created_at ,pt.value
       ) p on c1.id=p.child_id
       group by c1.id,c1.parent_id,c1.name,c1.created_at ,p.pet_type_value,p.name
    ) c on p.id=c.parent_id