2009-10-13 49 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 
相關問題