2012-04-27 8 views
1

これを行うにはより良い方法が必要であり、私は今日脳死です。パーティション上の最大値に関連付けられたラベルを取得する(SQL)

私は2つのテーブルがあります。私はグループ化する

Reference 
Id   Label 
1   Apple 
2   Banana 
3   Cherry 

Elements 
Id ReferenceId P1 P2 Qty 
1  1    1 2 8 
2  2    2 3 14 
3  1    3 2 1 
4  3    2 1 6 
5  3    1 2 3 

をこれらのアップ主に(P1、P2)によるが、P1とP2の順序とは無関係に - 、(1,2)となるように(2 1)は同じグループにマッピングされます。それはいいです。

P1 P2 TotalQty MostRepresentativeLabel 
1 2 17  Cherry 
2 3 15  Banana 

すべて:私がする結果セットをしたい、他の言葉で -

他の部分は、私が与えられたP1、P2のペアのために大金(数量)を持つラベルを取得したいです私はこのひどい混乱が出てくる可能性があります:

select endpoint1, endpoint2, totalTotal, mostRepresentativeLabelByQty from 
(
select SUM(qty)as total 
,case when (p1<p2) then p1 else p2 end as endpoint1 
,case when (p1<p2) then p2 else p1 end as endpoint2 
,reference.label as mostRepresentativeLabelByQty 

from elements inner join reference on elements.fkId = reference.id 
group by case when (p1<p2) then p1 else p2 end 
,case when (p1<p2) then p2 else p1 end 
,label 
) a inner join 
(
select MAX(total) as highestTotal, SUM(total) as totalTotal from 
(
select SUM(qty)as total 
,case when (p1<p2) then p1 else p2 end as endpoint1 
,case when (p1<p2) then p2 else p1 end as endpoint2 
,reference.label as mostRepresentativeLabelByQty 

from elements inner join reference on elements.fkId = reference.id 
group by case when (p1<p2) then p1 else p2 end 
,case when (p1<p2) then p2 else p1 end 
,label 
) byLabel 
group by endpoint1, endpoint2 
) b 
on a.total = b.highestTotal 

どちらがうまくいくのですか...私は確信していません。これは最終的にはもっと大きなデータセット(200,000行程度)で実行されるので、私はこのアプローチが好きではありません。「他の列が最大化されているところでこの列の値を使用する」という簡単な方法があります。完全にブランキングしていますか?

(方法によってSQL Server 2008のR2)

+0

(1,2)と(2,1)が同じペアにマッピングされている場合、なぜチェリーが一番多いのですか?アップルではないでしょうか? –

+0

(1,2)のために6 + 3のチェリー、わずか8つのリンゴがあります。 – Mikeb

答えて

1

I一意各グループを識別するためにBINARY_CHECKSUMのP1とP2の和を使用します。このSUMは、BCエイリアスによって と識別され、最大のグループラベルを見つけるために必要なグループ化を許可します。

DECLARE @Reference TABLE(ID INT, Label VARCHAR(10)); 
DECLARE @Elements TABLE(ID INT, ReferenceID INT, P1 INT, P2 INT, Qty INT); 

INSERT INTO @Reference VALUES 
(1,'Apple') 
, (2,'Banana') 
, (3,'Cherry'); 

INSERT INTO @Elements VALUES 
(1,1,1,2,8) 
, (2,2,2,3,14) 
, (3,1,3,2,1) 
, (4,3,2,1,6) 
, (5,3,1,2,3); 

; WITH a AS (
    SELECT 
    P1, P2=P2, Qty, BC=ABS(BINARY_CHECKSUM(CAST(P1 AS VARCHAR(10))))+ABS(BINARY_CHECKSUM(CAST(P2 AS VARCHAR(10)))) 
    , Label 
    , LabelSum=SUM(Qty)OVER(PARTITION BY ABS(BINARY_CHECKSUM(CAST(P1 AS VARCHAR(10))))+ABS(BINARY_CHECKSUM(CAST(P2 AS VARCHAR(10)))),Label) 
    , GroupSum=SUM(Qty)OVER(PARTITION BY ABS(BINARY_CHECKSUM(CAST(P1 AS VARCHAR(10))))+ABS(BINARY_CHECKSUM(CAST(P2 AS VARCHAR(10))))) 
    FROM @Elements e 
    INNER JOIN @Reference r on r.ID=e.ReferenceID 
) 
, r AS (
    SELECT *, rnk=RANK()OVER(PARTITION BY BC ORDER BY LabelSum DESC) 
    FROM a 
) 
SELECT P1=MIN(P1) 
, P2=MAX(P2) 
, TotalQty=GroupSum 
, MostRepresentativeLabel=Label 
FROM r 
WHERE rnk=1 
GROUP BY GroupSum,Label 
ORDER BY GroupSum DESC; 
GO 

結果:

enter image description here

EDITラップ各グループのBINARY_CHECKSUMの和のエントロピーを最大化するためにABSの各BINARY_CHECKSUM。 BINARY_CHECKSUMは符号付きのBIGINTなので、正のBINARY_CHECKSUMには の負のBINARY_CHECKSUMが加算された2つの異なるグループ間の衝突の確率が に減少します。

+0

それは賢いです。実行計画はもう少し複雑です - 実際のデータセットに対してプロファイルを作成します。私はチェックサム機能で遊んでいたが、私はそれをそうした方法で使うつもりはなかった。 – Mikeb

関連する問題