2017-10-06 34 views
1

什麼樣的查詢支持在排列行時考慮我的行的順序以及它們中的數據範圍?數據應按身份順序處理,我希望範圍邊界定義爲[Time] > 2 or [Time] < -2基於訂單和數據範圍的分區行

編輯:換句話說,我想將行視爲一個列表,並將它們分成列表列表,其中ParitionId是行列表的索引。

編輯2:我忘了說清楚,每當[時間]值超出所需範圍時,分區ID應該加1。這個要求意味着我們不能僅僅使用GROUP BY來存儲行,如果[時間]落在範圍內或外部,case語句返回true或false。

MS SQL服務器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和所需的分區號。這就像將列表分成列表列表,其中每個列表的索引是分區標識。 – 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服務器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 |