web-dev-qa-db-ja.com

値をバケットにグループ化する

私はクエリを使用していますが、私の現在のアプローチが「最良の」アプローチであるかどうかはわかりませんでした。値で満たされたテーブルと、それらの値をグループ化するために使用するバケットを持つテーブルを取得しました。

バケットには次の2つのタイプがあります。

  • 優先バケット、アイテムが条件に該当する場合、アイテムはこのバケットに分類され、後続のバケットから除外されます。
  • 単純な範囲バケット、値は範囲内にある必要があります。

テストに使用できる簡易バージョンをセットアップしました。 [Filter]列の#tempBUcketここは優先バケットに使用されます

テーブルの定義

create table #TempData([Id] int, [value] int);
create table #TempBucket([Id] int, [FromVal] int,[ToVal] int,[Filter] int);

いくつかのテストデータ

INSERT INTO #TempData (Id,value)
    VALUES  (1,1),(2,2),(3,3),(4,4),(5,5),
            (6,6),(7,7),(8,8),(9,9),(10,1),
            (11,2),(12,3),(13,4),(14,5),(15,6),
            (16,7),(17,8),(18,9),(19,10),(20,11);
INSERT INTO #TempBucket(Id,FromVal,ToVal,Filter)
    VALUES  (1,0,3,0),(2,3,6,0),
            (3,6,9,0),(4,9,12,0),
            (5,NULL,NULL,1),(6,NULL,NULL,2);

現在、私はこのクエリが機能し、必要な結果を提供していますが、これをより効率よく実行できると感じています。

WITH filteredData as 
    (SELECT tv.*,COALESCE(tb1.Id,tb2.Id) as BucketId FROM #TempData tv
    LEFT JOIN #TempBucket tb1 --prio bucket join
        ON tb1.Filter IS NOT NULL AND tb1.Filter = tv.Value
    LEFT JOIN #TempBucket tb2 --range bucket join
        ON tb2.Fromval < tv.value AND tv.value <= tb2.ToVal
    )
SELECT Count(fd.value) as count ,BucketId FROM filteredData fd GROUP BY BucketId;

dbfiddle.uk

3
Joost K

私のソリューションは#TempBucketのうちscanを1つだけ実行しますが、追加のsortを追加します。効率的かどうかはわかりません。データ量でテストする必要があります。

;with cte as
(
select t.*, tb.id as BucketId,
       row_number() over(partition by t.id order by tb.FromVal) as rn
from #TempData t
     join #TempBucket tb 
         on (t.value = tb.filter)  
         or (tb.Fromval < t.value AND t.value <= tb.ToVal)
)
select count(id) as cnt, BucketId
from cte
where rn = 1
group by BucketId;

priority bucketの行に優先順位を付けるには、優先バケットの場合はnullであるtb.FromValで並べ替えます。または、tb.Filter descで並べ替えることもできますが、正確な基準がわかりませんof priority bucketFromVal,ToValnullまたはFilter = 0であるかどうか

2
sepupic