2016-06-02 1 views
2

Я хочу ранжировать последовательное нулевое значение для моих записей. Каждая запись будет иметь ранг как 1. Для нулевого значения, которое появляется только один раз, ранг будет также равен 1. Но для нулевых значений, которые появляются последовательным образом, ранг будет 1 для первой записи, а второй для второго запись и т. д. Вот мой код.Ранг последовательных нулевых значений

CREATE TABLE #my_table 
(
    id BIGINT      IDENTITY PRIMARY KEY 
    ,fruit       varchar(100) 
); 

INSERT INTO #my_table 
      SELECT 'apple' 
UNION ALL SELECT 'apple' 
UNION ALL SELECT NULL 
UNION ALL SELECT 'pineapple' 
UNION ALL SELECT 'banana' 
UNION ALL SELECT NULL 
UNION ALL SELECT NULL 
UNION ALL SELECT 'orange' 

select * from #my_table 

Предназначенный результат

+----+-----------+------+ 
| id | fruit  | rank | 
+----+-----------+------+ 
| 1 | apple  | 1 | 
| 2 | apple  | 1 | 
| 3 | NULL  | 1 | 
| 4 | pineapple | 1 | 
| 5 | banana | 1 | 
| 6 | NULL  | 1 | 
| 7 | NULL  | 2 | 
| 8 | orange | 1 | 
+----+-----------+------+ 

Как я должен запросить его?

Пожалуйста, помогите!

+0

Какая версия SQL Server? –

+0

Привет! Его SQL-сервер 2014 – eric

ответ

1

Вы можете использовать разницу ROW_NUMBER, чтобы получить группировку последовательных NULL значений:

WITH Cte AS(
    SELECT *, 
     g = ROW_NUMBER() OVER(ORDER BY id) 
       - ROW_NUMBER() OVER(PARTITION BY fruit ORDER BY id) 
    FROM #my_table 
) 
SELECT 
    id, 
    fruit, 
    CASE 
     WHEN fruit IS NULL THEN ROW_NUMBER() OVER(PARTITION BY fruit, g ORDER BY id) 
     ELSE 1 
    END AS rank 
FROM Cte 
ORDER BY id; 

ONLINE DEMO

1
CREATE TABLE #my_table 
(
    id BIGINT      IDENTITY PRIMARY KEY 
    ,fruit       varchar(100) 
); 

INSERT INTO #my_table 
      SELECT 'apple' 
UNION ALL SELECT 'apple' 
UNION ALL SELECT NULL 
UNION ALL SELECT 'pineapple' 
UNION ALL SELECT 'banana' 
UNION ALL SELECT NULL 
UNION ALL SELECT NULL 
UNION ALL SELECT 'orange' 

; 
WITH REC_CTE (id,fruit,ranks) 
    AS (
     -- Anchor definition 
     SELECT id, 
       fruit, 
       1 as ranks 
     FROM #my_table 
     WHERE fruit is not null 

      -- Recursive definition 
     UNION ALL 
     SELECT son.id, 
       son.fruit, 
       case when son.fruit is null AND father.fruit is null then 
        father.ranks + 1 
        else 
        1 
       end as ranks 
     FROM #my_table son INNER JOIN 
       REC_CTE father 
     on son.id = father.id +1 
     WHERE son.fruit is null 
      --AND father.fruit is null 
    ) 

    SELECT * from REC_CTE order by id 

    DROP TABLE #my_table 
0

После решения не использует рекурсию (ограниченный 32767 уровень = ~ строки в зависимости от решения), а также использует только две функции агрегирования/ранжирования (SUM и DENSE_RANK):

;WITH Base 
AS (
    SELECT *, IIF(fruit IS NULL, SUM(IIF(fruit IS NOT NULL, 1, 0)) OVER(ORDER BY id), NULL) AS group_num 
    FROM @my_table t 
) 
SELECT *, IIF(fruit IS NULL, DENSE_RANK() OVER(PARTITION BY group_num ORDER BY id), 1) rnk 
FROM Base b 
ORDER BY id 

Результаты:

id fruit  group_num rnk 
--- --------- --------- --- 
100 apple  NULL  1 
125 apple  NULL  1 
150 NULL  2   1 
175 pineapple NULL  1 
200 banana NULL  1 
225 NULL  4   1 
250 NULL  4   2 
275 orange NULL  1 
300 NULL  5   1 
325 NULL  5   2 
350 NULL  5   3