2011-11-28 14 views
0

によって返された結果のフィルタリングすべての午後にこれを処理するのに苦労しています。SQLクエリ

いくつかのデータを返すクエリがあります。返される列のうち2つは "PackageWeight"と "PackageGroup"です。基本的には、このデータをフィルタリングして、各 "PackageGroup"ごとに1行だけを表示する必要があります。これは、 "PackageWeight"列の値が最も高い行です。

これは単純ですが、TOP 1とGROUP BYの組み合わせを使用してSQL Serverで動作させることはできません。私は何かが欠けているに違いない!

SELECT VendorID, PackageID, PackageWeight, PackageGroup 
    FROM (SELECT VendorID, COUNT(*) AS qty 
      FROM VendorServices 
     GROUP BY VendorID 
     ) cs 
    JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
      FROM PackageServices 
      JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
      GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
     ) ps ON cs.qty >= ps.qty 
    WHERE (SELECT COUNT(*) 
      FROM VendorServices cs2 
      JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
     WHERE cs2.VendorID = cs.VendorID 
      AND ps2.PackageID = ps.PackageID 
     ) = ps.qty 

このクエリは、私がフィルタリングする必要がある完全なデータセットを返します。しかし、私の試みはこれまで失敗している:(

すべてのヘルプははるかに高く評価

EDIT - おかげで以下の貢献者に、これまでのところ私は持っている次のクエリ:!

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    RANK() over (partition by PackageGroup order by PackageWeight desc) as [rank] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
WHERE [rank] = 1 
ORDER BY VendorID 

これまでのところ、そうこれは私にとって新しくなっている@gbnで提案されているAPPLY演算子を見ていますが、このクエリが100%時間で動作することを確認するためにはまだテストを行う必要があります。

これまで貢献してくれたすべての人に感謝します。

EDIT 2 - 悲しいことに、より多くのサンプルデータをデータベースに入力した後、このクエリは機能しませんでした。それはいくつかのエントリを欠場するようです。

多分私はここで何が起こっているかについてもう少し説明する必要があります。元のクエリで返されるデータには、システム内のすべての顧客と、派生したPackageID(そのクエリで計算されたもの)と、そのパッケージに割り当てられたグループおよびグループがルックアップテーブルにリストされます。

元の結果テーブルをフィルタリングして、顧客ごとに各グループから複数のパッケージを取得する必要があります(各顧客は1つ以上のグループのパッケージを持つことができますが、

明日は私が「樹木のために木を見ることができない」状況にあるかもしれないと思うので、これをもっと先に見てみましょう!

ありがとうございます。

+1

可能重複(http://stackoverflow.com/questions/1450603/sql-server-select-top-5-rows -for-each-fk)またはhttp://stackoverflow.com/q/1164483/27535を参照してください。さらに多くの:http://stackoverflow.com/questions/tagged/greatest-n-per-group – gbn

+1

どのバージョンのSQL Serverを使用していますか? – Lamak

+0

@Lamak - SQL Server 2008. – JimmE

答えて

1

これを試すことができますか?あなたが同じグループに同じ重みを持つ複数のレコードを持っているならば、防弾ではありません。それを処理する他の方法があります。

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where result_cte.PackageWeight = (select top 1 highestweight.PackageWeight from result_cte highestweight 
           where highestweight.PackageGroup = result_cte.PackageGroup 
           order by highestweight.PackageWeight desc) 

それともあなたがこれを行うことができます:

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    ROW_NUMBER() over (partition by PackageGroup order by PackageWeight desc) as [row] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where [row] = 1 
+0

ROW_NUMBERまたはAPPLYベースのクエリと比較して、これは動作しても非常に乱雑です。 – gbn

+0

著者の問題を解決するつもりはありません。私は、望みの結果を得るためにさまざまなテクニックを見せたいだけです。私が提供したクエリは、正しい結果が得られるかどうかを検証する必要があります。 –

+0

@ Eric.K.Yung - 多くのありがとう - ROW_NUMBER()ではなくRANK()を使用するようにこれを少し修正しました.ROW_NUMBER()は顧客が各グループのパッケージを持たない行を返さないようです。更新されたクエリをOPの編集として貼り付けます。 – JimmE

0

あなたは複数のパッケージをグループで同じ最大の重みを持っている場合は、単一の任意のベンダーとPackageIDを受け入れて喜んでいますか? OK、ちょうどそれらに集計を置くだけでなく、PackageWeight場合:

SELECT max(VendorID), max(PackageID), max(PackageWeight), PackageGroup 
... 
GROUP BY PackageGroup 

そうしないと、E.Y.として行う必要があります提案し、ネストされたクエリを実行して、グループごとに最大の重みを見つけ、重複があれば処理します。

+0

ありがたいことに、アプリケーションの性質は、パッケージがそれぞれグループ内でユニークな重みを持つようなものです。これは実際には、重み付け/グループ化が最初に存在する理由です。つまり、顧客にパッケージを割り当てることに関するビジネスルールを強制することです。 – JimmE

0

あなたはMAX関数を使用できます。ポストへ

SELECT * FROM #one 
lbs groups 
5 0 
4 0 
1 0 
9 1 
2 1  

SELECT groups,MAX(lbs) 
FROM #one 
GROUP BY groups 

groups (No column name) 
0 5 
1 9 
0

感謝をEric.K.Yungで - 私は最終的に彼のクエリを使用して、これを解決したが一部「でパーティション」にベンダーID(効果的に得意先)を追加クエリのこれにより、すべての顧客に対してパッケージが返されました。

貢献したすべての方に感謝します。最後のクエリは次のとおりです。[SQL Serverの - それぞれのFKのためのTOP 5行を選択]の

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    ROW_NUMBER() over (partition by PackageGroup, VendorID order by PackageWeight desc) as [row] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where [row] = 1 
+0

最終的なクエリが、それが基礎としている回答と実際の回答がどのくらい違うかによって、実際には他の回答から、あなたの回答に追加することを検討するかもしれません。つまり、誰かがこのスレッドに投稿されている他の正しい解決策と同じくらい有用であると感じるかもしれません。 –

+0

@AndriyM - もちろん - 多くのありがとう。最終的な質問が私の答えに追加されました。 – JimmE