2009-10-13 50 views
18

有两个SQL表:一个一对多的查询选择所有的父母和单顶子为每个父

Parents: 
+--+---------+ 
|id| text | 
+--+---------+ 
| 1| Blah | 
| 2| Blah2 | 
| 3| Blah3 | 
+--+---------+ 

Childs 
+--+------+-------+ 
|id|parent|feature| 
+--+------+-------+ 
| 1| 1 | 123 | 
| 2| 1 | 35 | 
| 3| 2 | 15 | 
+--+------+-------+ 

我想用单一的查询选择从父母表中的每一行和每一单排从Childs表格与关系“父母” - “ID”值和最大的“功能”列值。在这个例子的结果应该是:

+----+------+----+--------+---------+ 
|p.id|p.text|c.id|c.parent|c.feature| 
+----+------+----+--------+---------+ 
| 1 | Blah | 1 | 1 | 123 | 
| 2 | Blah2| 3 | 2 | 15 | 
| 3 | Blah3|null| null | null | 
+----+------+----+--------+---------+ 

其中P =父表和c =子表

我试图LEFT OUTER JOIN和GROUP BY但MSSQL快告诉我,GROUP BY该查询需要聚合函数在每个非分组字段上。而且我不想将它们全部分组,而是选择顶行(使用自定义顺序)。

我完全没了主意......

回答

18
select p.id, p.text, c.id, c.parent, c.feature 
from Parents p 
left join (select c1.id, c1.parent, c1.feature 
      from Childs c1 
      join (select p1.id, max(c2.feature) maxFeature 
        from Parents p1 
       left join Childs c2 on p1.id = c2.parent 
      group by p1.id) cf on c1.parent = cf.id 
           and c1.feature = cf.maxFeature) c 
on p.id = c.parent 
+0

这不会只返回顶级的孩子每次 –

+0

谢谢。修正了,现在它会。 – manji

+0

它的工作!精彩! – PiotrK

4

这应该工作:

SELECT p.id, p.text, c.id, c.parent,c.feature 
FROM parent p 
LEFT OUTER JOIN (SELECT TOP 1 child.id, 
           child.parent, 
           MAX(child.feature) 
        FROM child 
        WHERE child.parent = p.id 
        GROUP BY child.id, child.parent 
       ) c ON p.id = c.parent 
9

使用CTE(SQL服务器2005 +):

WITH max_feature AS (
    SELECT c.id, 
      c.parent, 
      MAX(c.feature) 'feature' 
    FROM CHILD c 
GROUP BY c.id, c.parent) 
    SELECT p.id, 
      p.text, 
      mf.id, 
      mf.parent, 
      mf.feature 
    FROM PARENT p 
LEFT JOIN max_feature mf ON mf.parent = p.id 

非相当于CTE :

SELECT p.id, 
      p.text, 
      mf.id, 
      mf.parent, 
      mf.feature 
    FROM PARENT p 
LEFT JOIN (SELECT c.id, 
        c.parent, 
        MAX(c.feature) 'feature' 
      FROM CHILD c 
     GROUP BY c.id, c.parent) mf ON mf.parent = p.id 

你的问题缺乏细节处理连接断路器(当2+ CHILD.id值具有相同的特征值)。 Agent_9191的回答使用TOP 1,但那会把第一个回到&并不一定是你想要的。

+1

我认为按(c.id,c.parent)分组就像返回原始表(Childs),因为父母不能拥有具有2个特征的同一个孩子。 – manji

2

满级的查询不处理领带断路器的最大特点。这里是我的方法,我测试过:

;WITH WithClause AS (SELECT p.id, p.text, 
     (SELECT TOP 1 c.id from childs c 
      where c.parent = p.id order by c.feature desc) 
     AS BestChildID 
    FROM Parents p) 
SELECT WithClause.id, WithClause.text, c.id, c.parent, c.feature 
FROM WithClause 
LEFT JOIN childs c on WithClause.BestChildID = c.id 
+0

OMG Ponies的方法也行不通,我测试过了,manji表示,他的片段中有很多行。 – AndyH

1

如果您需要从MAX列并通过嵌套选择关闭一组中描述的任何列加入不同的,你可以使用一个应用函数。 这是一个最简单的解决方案。您也可以使用WITH运算符。但是这看起来更难。

SELECT p.id, p.text, CHILD_ROW.ANY_COLLUMN 
FROM parent p 
OUTER APPLY (SELECT TOP 1 child.ANY_COLLUMN 
        FROM child 
        WHERE child.parent = p.id 
        ORDER BY child.feature DESC 
       ) CHILD_ROW 
相关问题