1

私はこれを行うためのより良い方法があるに違いないことを知っています、そして私は今日脳死しています。

私は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)が同じグループにマップされるようにします。それはいいです。

もう1つの部分は、特定のP1、P2ペアに対して大きなsum(qty)を持つラベルを取得したいということです。つまり、結果セットを次のようにしたいのです。

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

私が思いつくことができるのは、このひどい混乱だけです。

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行程度)で実行されるため、このアプローチは好きではありません。「他の列が最大化されているこの列の値を使用する」を表現する簡単な方法はありますか? m完全にブランキング?

(ちなみにSQL Server 2008 R2)

4

1 に答える 1

1

P1 と P2 の BINARY_CHECKSUM の合計を使用して、各グループを一意に識別します。この 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

結果:

ここに画像の説明を入力

EDIT各 BINARY_CHECKSUM を ABS でラップして、各グループの BINARY_CHECKSUM の合計のエントロピーを最大化します。BINARY_CHECKSUM は符号付き BIGINT であるため、正の BINARY_CHECKSUM が負の BINARY_CHECKSUM と合計される 2 つの異なるグループ間の衝突の可能性が減少します。

于 2012-04-28T22:48:06.193 に答える