与特殊条件的组相关

时间:2019-12-11 21:03:56

标签: sql sql-server sql-server-2008 sql-server-2008-r2

我们需要获取列NEED的结果,需要按ORDER列的顺序按GROUP列进行相关分组,并且随着FLAG列的更改而增加。

GROUP   ORDER   FLAG    NEED
1111    1       0       1
1111    2       0       1
1111    3       1       2
1111    4       1       2
1111    5       1       2
1111    6       1       2
1111    7       1       2
1111    8       0       3
1111    9       1       4
1111    10      1       4
1111    11      0       5
1111    12      0       5
1111    13      0       5
6666    1       0       1
6666    2       0       1
6666    3       1       2
6666    4       1       2

我们尝试下面的代码,但是我们需要更干净的支持SQL Server 2008的

if object_id('tempdb..#temp2','u') is not NULL
drop table #temp2
SELECT *
    ,ROW_NUMBER() OVER(oRDER BY (SELECT NULL)) RN
INTO #temp2
FROM DBO.PRUEBA​

SELECT T1.*
    ,SUM(CASE WHEN T1.NUM_GROUP = T2.NUM_GROUP and t1.NUM_FLAG = t2.NUM_FLAG THEN 0 ELSE 1 END) OVER (PARTITION BY T1.NUM_GROUP ORDER BY T1.rn)[Rank]
FROM #temp2 T1
LEFT JOIN #temp2 T2 ON T1.rn = T2.rn+1
order by t1.NUM_GROUP, t1.NUM_ORDER

我分享表和记录的创建

CREATE TABLE DBO.PRUEBA
(
    NUM_GROUP INT,
    NUM_ORDER INT,
    NUM_FLAG INT
)

INSERT INTO DBO.PRUEBA VALUES (1111, 1, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 2, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 3, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 4, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 5, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 6, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 7, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 8, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 9, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 10, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 11, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 12, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 13, 0)
INSERT INTO DBO.PRUEBA VALUES (6666, 1, 0)
INSERT INTO DBO.PRUEBA VALUES (6666, 2, 0)
INSERT INTO DBO.PRUEBA VALUES (6666, 3, 1)
INSERT INTO DBO.PRUEBA VALUES (6666, 4, 1)

SELECT * FROM DBO.PRUEBA

1 个答案:

答案 0 :(得分:0)

可能的优化方法是首先创建临时表。

代替使用SELECT INTO

并带有一个主键,该主键有益于用于获取以前的NUM_FLAG的自联接。

CREATE TABLE DBO.PRUEBA
(
    NUM_GROUP INT NOT NULL,
    NUM_ORDER INT NOT NULL,
    NUM_FLAG INT NOT NULL,
    PRIMARY KEY (NUM_GROUP, NUM_ORDER)
);
GO
INSERT INTO DBO.PRUEBA 
(NUM_GROUP, NUM_ORDER, NUM_FLAG)
VALUES
  (1111, 1, 0)
 ,(1111, 2, 0)
 ,(1111, 3, 1)
 ,(1111, 4, 1)
 ,(1111, 5, 1)
 ,(1111, 6, 1)
 ,(1111, 7, 1)
 ,(1111, 8, 0)
 ,(1111, 9, 1)
 ,(1111, 10, 1)
 ,(1111, 11, 0)
 ,(1111, 12, 0)
 ,(1111, 13, 0)
 ,(6666, 1, 0)
 ,(6666, 2, 0)
 ,(6666, 3, 1)
 ,(6666, 4, 1)
IF OBJECT_ID('tempdb..#tmpPRUEBA', 'U') IS NOT NULL
    DROP TABLE #tmpPRUEBA; 

CREATE TABLE #tmpPRUEBA
(
    NUM_GROUP INT NOT NULL,
    RN_GROUP INT NOT NULL,
    NUM_ORDER INT NOT NULL,
    NUM_FLAG INT NOT NULL,
    PRIMARY KEY (NUM_GROUP, RN_GROUP)
);
GO
INSERT INTO #tmpPRUEBA
(NUM_GROUP, NUM_ORDER, NUM_FLAG, RN_GROUP)
SELECT NUM_GROUP, NUM_ORDER, NUM_FLAG
, ROW_NUMBER() OVER (
      PARTITION BY NUM_GROUP 
      ORDER BY NUM_ORDER) AS RN_GROUP
FROM DBO.PRUEBA;
GO
SELECT 
t1.NUM_GROUP, 
t1.NUM_ORDER, 
t1.NUM_FLAG,
SUM(CASE 
    WHEN t1.NUM_FLAG = t2.NUM_FLAG 
    THEN 0 
    ELSE 1 
    END)
    OVER (PARTITION BY t1.NUM_GROUP 
          ORDER BY t1.RN_GROUP) AS [Rank]
FROM #tmpPRUEBA t1
LEFT JOIN #tmpPRUEBA t2
  ON t2.NUM_GROUP = t1.NUM_GROUP
 AND t2.RN_GROUP = t1.RN_GROUP - 1;
GO
NUM_GROUP | NUM_ORDER | NUM_FLAG | Rank
--------: | --------: | -------: | ---:
     1111 |         1 |        0 |    1
     1111 |         2 |        0 |    1
     1111 |         3 |        1 |    2
     1111 |         4 |        1 |    2
     1111 |         5 |        1 |    2
     1111 |         6 |        1 |    2
     1111 |         7 |        1 |    2
     1111 |         8 |        0 |    3
     1111 |         9 |        1 |    4
     1111 |        10 |        1 |    4
     1111 |        11 |        0 |    5
     1111 |        12 |        0 |    5
     1111 |        13 |        0 |    5
     6666 |         1 |        0 |    1
     6666 |         2 |        0 |    1
     6666 |         3 |        1 |    2
     6666 |         4 |        1 |    2

db <>提琴here