2009-10-13 7 views
18

2つのSQLのテーブルがあります。1対多の各親のためのすべての親とシングルトップ子を選択するクエリ

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

Childs 
+--+------+-------+ 
|id|parent|feature| 
+--+------+-------+ 
| 1| 1 | 123 | 
| 2| 1 | 35 | 
| 3| 2 | 15 | 
+--+------+-------+ 
私は、単一のクエリを持つ親テーブルからすべての行を選択したい

とそれぞれ1つの行については、リレーション「親」 - 「id」値と最大「フィーチャ」列の値を持つチャイルドテーブルから取得します。私はJOINをLEFT OUTERしようとした

+----+------+----+--------+---------+ 
|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 =子テーブル

とGROUP BYが、MSSQL Expressは、GROUP BYでそのクエリが集約関数を必要と私に言った:この例では、結果がでなければなりませんGroupped以外のすべてのフィールドに表示されます。そして、私はそれらをすべてグループ化するのではなく、一番上の行を(カスタム注文で)選択します。私は完全にアイデアをしています

...

答えて

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

これは動作するはずです:

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相当:CTE(SQL Serverを2005+)を使用して

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

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

manjiのクエリは、最大機能のタイブレーカーを処理しません。ここで私がテストしてみた私の方法は、次のとおりです。

;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の方法もうまくいきません。私はテストしました。マンジが示すように、両方のスニペットで多すぎる行があります。 – 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 
関連する問題