2017-10-06 7 views
1

行のランキング時に、行の順序とその内部のデータ範囲の両方を考慮に入れて、どのような種類のクエリがサポートされますか?データは同一順序で処理する必要があり、範囲境界線を[Time] > 2 or [Time] < -2として定義します。オーダーとデータ範囲に基づくパーティション行

編集:つまり、行をリストとして扱い、ParitionIdが行のリストのインデックスであるリストのリストに分割したいとします。

編集2:[時間]値が希望の範囲外になるたびに、パーティションIDが1ずつ増えることを忘れてしまいました。この要件は、GROUP BYを使用して行をバケット化することはできないことを意味します。[時間]が範囲内または外にある場合は、trueまたはfalseを返すcase文を使用できます。

MS SQL Serverの2014スキーマのセットアップ

CREATE TABLE foobartable 
    ([ID] int Identity(1,1) NOT NULL, [Time] float, [X] float, [Y] float) 
; 

INSERT INTO foobartable 
    ([Time], [X], [Y]) 
VALUES 
    (0.0, 1, 1), 
    (1.0, 1, 1), 
    (2.0, 1, 1), 
    (3.0, 1, 1), 
    (2.0, 1, 1), 
    (1.0, 1, 1), 
    (-1.0, 1, 1), 
    (-2.0, 1, 1), 
    (-3.0, 1, 1), 
    (-2.0, 1, 1), 
    (-1.0, 1, 1), 
    (0.0, 1, 1), 
    (1.0, 1, 1), 
    (2.0, 1, 1), 
    (3.0, 1, 1), 
    (2.0, 1, 1) 
; 

望ましい結果

| Id | PartitionId | 
|----|-------------| 
| 1 |   0 | 
| 2 |   0 | 
| 3 |   0 | 
| 4 |   1 | 
| 5 |   2 | 
| 6 |   2 | 
| 7 |   2 | 
| 8 |   2 | 
| 9 |   3 | 
| 10 |   4 | 
| 11 |   4 | 
| 12 |   4 | 
| 13 |   4 | 
| 14 |   4 | 
| 15 |   5 | 
| 16 |   6 | 
+1

。 –

+0

@SeanLange私は、行の順番に基づいて行にランクを割り当て、その行内のデータに基づいて、ある範囲内にあるかどうかを判断したいと考えています。必要な結果は、行IDと目的のパーティション番号だけです。これは、リストをリストのリストに分割し、各リストのインデックスがパーティションIDであるようなものです。 – mortalapeman

+0

時間= 2または時間= -2の場合はどうですか? または[時間]> = 2または[時間] <= -2を意味しますか –

答えて

1

私はあなたがRecursive CTEを使用することができると思います。このような何か:

WITH cte AS 
(
    SELECT *, row_number() over(ORDER BY ID) rn 
     FROM #foobartable 
), 
cte2 as 
(
    SELECT cast(0 AS int) AS rn, NULL AS id, 
     cast(NULL AS float) AS time, 
     cast(NULL AS float) AS x, 
     cast(NULL AS float) AS y, 
     0 AS p 
    UNION all 
    SELECT cast(cte.rn AS int), cte.id, 
     cte.[Time], cte.x, cte.y, 
     iif(
       cte2.time <= 2.0 AND cte.time > 2.0 OR 
       cte2.time > 2.0 AND cte.time <= 2.0 OR 
       cte2.time >= -2.0 AND cte.time < -2.0 OR 
       cte2.time < -2.0 AND cte.time >= -2.0 
       ,p + 1 
       ,p 
      ) AS p 
     FROM cte2 
     JOIN cte ON cte2.rn + 1 = cte.rn 
) 
SELECT id, p AS PartitionId 
    FROM cte2 
    WHERE id IS NOT NULL 
    ORDER BY id; 

出力:

id   PartitionId 
----------- ----------- 
1   0 
2   0 
3   0 
4   1 
5   2 
6   2 
7   2 
8   2 
9   3 
10   4 
11   4 
12   4 
13   4 
14   4 
15   5 
16   6 
+0

優秀!これは私が思いついたのとほぼ同じことです。私が気づいていなかったかもしれない機能を使用して問題を解決するために、他の誰かが別の方法を知っているかどうかを知りたいと思っていました。 – mortalapeman

1

私が思いついた解決策:

SQL Fiddle

MS SQL Serverの2014スキーマのセットアップ

CREATE TABLE foobartable 
    ([ID] int Identity(1,1) NOT NULL, [Time] float, [X] float, [Y] float) 
; 

INSERT INTO foobartable 
    ([Time], [X], [Y]) 
VALUES 
    (0.0, 1, 1), 
    (1.0, 1, 1), 
    (2.0, 1, 1), 
    (3.0, 1, 1), 
    (2.0, 1, 1), 
    (1.0, 1, 1), 
    (-1.0, 1, 1), 
    (-2.0, 1, 1), 
    (-3.0, 1, 1), 
    (-2.0, 1, 1), 
    (-1.0, 1, 1), 
    (0.0, 1, 1), 
    (1.0, 1, 1), 
    (2.0, 1, 1), 
    (3.0, 1, 1), 
    (2.0, 1, 1) 
; 

クエリ1

with pairs as (
    select 
    t1.[ID] as [ID1], 
    t2.[ID] as [ID2] 
    from foobartable as t1 
    left outer join foobartable as t2 on (t1.[ID] + 1) = t2.[ID] 
), 

loop ([ID], [Level]) 
as (
    select top 1 
    t.[ID], 
    0 
    from foobartable as t 
    union all 
    select 
    p.[ID2], 
    (case when (case when t1.[Time] > 2 or t1.[Time] < -2 then 0 else 1 end) <> (case when t2.[Time] > 2 or t2.[Time] < -2 then 0 else 1 end) then [Level] + 1 else [Level] end) as [Level] 
    from loop 
    inner join pairs as p on p.[ID1] = loop.[ID] 
    inner join foobartable as t1 on p.[ID1] = t1.[ID] 
    inner join foobartable as t2 on p.[ID2] = t2.[ID] 
) 

select [Id], [Level] as [PartitionId] from loop 

Results:あなたは私はあなたがここでやろうとしているのか理解していないことをそんなに現実的な問題を難読化している

| Id | PartitionId | 
|----|-------------| 
| 1 |   0 | 
| 2 |   0 | 
| 3 |   0 | 
| 4 |   1 | 
| 5 |   2 | 
| 6 |   2 | 
| 7 |   2 | 
| 8 |   2 | 
| 9 |   3 | 
| 10 |   4 | 
| 11 |   4 | 
| 12 |   4 | 
| 13 |   4 | 
| 14 |   4 | 
| 15 |   5 | 
| 16 |   6 | 
関連する問題