SQL首先执行,然后在over子句中进行分区

时间:2018-06-28 08:23:10

标签: sql sql-server tsql row-number gaps-and-islands

我有一个问题,我想对已排序的表进行分区。有办法吗?

我正在使用SQL Server 2016。

输入表:

|---------|-----------------|-----------|------------|
|  prod   |   sortcolumn    |    type   |    value   |
|---------|-----------------|-----------|------------|
|    X    |        1        |     P     |     12     |
|    X    |        2        |     P     |     23     |
|    X    |        3        |     E     |     34     |
|    X    |        4        |     P     |     45     |
|    X    |        5        |     E     |     56     |
|    X    |        6        |     E     |     67     |
|    Y    |        1        |     P     |     78     |
|---------|-----------------|-----------|------------|

所需的输出

|---------|-----------------|-----------|------------|------------|
|  prod   |   sortcolumn    |    type   |    value   |    rowNr   |
|---------|-----------------|-----------|------------|------------|
|    X    |        1        |     P     |     12     |      1     |
|    X    |        2        |     P     |     23     |      2     |
|    X    |        3        |     E     |     34     |      1     |
|    X    |        4        |     P     |     45     |      1     |
|    X    |        5        |     E     |     56     |      1     |
|    X    |        6        |     E     |     67     |      2     |
|    Y    |        1        |     P     |     78     |      1     |
|---------|-----------------|-----------|------------|------------|

我到此为止:

SELECT
  table.*,
  ROW_NUMBER() OVER(PARTITION BY table.prod, table.type ORDER BY table.sortColumn) rowNr
FROM table

但这不会重新开始第4行的行号,因为它的prod和类型相同。 即使类型改回到以前的状态,我又如何才能基于排序标准重新启动每个产品以及每个类型的更改?甚至可以通过ROW_NUMBER函数来实现,还是我必须使用LEAD,LAG和CASES(这可能会使它非常慢,对吧?)

谢谢!

3 个答案:

答案 0 :(得分:5)

这是一个空白和孤岛的问题。您可以使用以下查询:

SELECT t.*, 
       ROW_NUMBER() OVER (PARTITION BY prod ORDER BY sortcolumn)
       -
       ROW_NUMBER() OVER (PARTITION BY prod, type ORDER BY sortcolumn) AS grp
FROM mytable t

获得:

prod    sortcolumn  type    value   grp
----------------------------------------
X       1           P       12      0
X       2           P       23      0
X       3           E       34      2
X       4           P       45      1
X       5           E       56      3
X       6           E       67      3
Y       1           P       78      0

现在,字段grp可用于分区:

;WITH IslandsCTE AS (
    SELECT t.*, 
           ROW_NUMBER() OVER (PARTITION BY prod ORDER BY sortcolumn)
           -
           ROW_NUMBER() OVER (PARTITION BY prod, type ORDER BY sortcolumn) AS grp
    FROM mytable t  
)
SELECT prod, sortcolumn, type, value,
       ROW_NUMBER() OVER (PARTITION BY prod, type, grp ORDER BY sortcolumn) AS rowNr
FROM IslandsCTE
ORDER BY prod, sortcolumn

Demo here

答案 1 :(得分:3)

这是一个经典的“岛屿”问题,因为您需要找到与{{ object.subtotal or 0 }} prod相关的记录的“岛屿”,但没有将所有分组在一起记录在typeprod上匹配的内容。

这是通常可以解决的一种方法。设置:

type

获取一些行号:

DECLARE @t TABLE (
    prod varchar(1),
    sortcolumn int,
    type varchar(1),
    value int
);

INSERT @t VALUES
('X', 1, 'P', 12),
('X', 2, 'P', 23),
('X', 3, 'E', 34),
('X', 4, 'P', 45),
('X', 5, 'E', 56),
('X', 6, 'E', 67),
('Y', 1, 'P', 78)
;

;WITH numbered AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY prod, type ORDER BY sortcolumn) as rnX, ROW_NUMBER() OVER (PARTITION BY prod ORDER BY sortcolumn) as rn FROM @t ) 现在看起来像这样:

numbered

这为什么有用?好吧,看看prod sortcolumn type value rnX rn ---- ----------- ---- ----------- -------------------- -------------------- X 1 P 12 1 1 X 2 P 23 2 2 X 3 E 34 1 3 X 4 P 45 3 4 X 5 E 56 2 5 X 6 E 67 3 6 Y 1 P 78 1 1 rnX之间的差异

rn

如您所见,每个“组”共享一个prod sortcolumn type value rnX rn rn - rnX ---- ----------- ---- ----------- -------------------- -------------------- -------------------- X 1 P 12 1 1 0 X 2 P 23 2 2 0 X 3 E 34 1 3 2 X 4 P 45 3 4 1 X 5 E 56 2 5 3 X 6 E 67 3 6 3 Y 1 P 78 1 1 0 值,并且从一个组变为另一个组。

现在,如果我们按rn - rnXprod和组号进行分区,然后在其中编号

type

我们完成了:

SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY prod, type, rn - rnX ORDER BY sortcolumn) rowNr
FROM
    numbered
ORDER BY 
    prod, sortcolumn

相关阅读:Things SQL needs: SERIES()

答案 2 :(得分:-2)

尝试一下

select prod, sortcolumn, type, value, row_number() over (partition by prod, sortcolumn, type order by value) rowNr    
from table_name