MS SQL Set Group ID без зацикливания

Я хотел бы создать запрос в MS-SQL, чтобы создать столбец, содержащий увеличивающийся номер группы.

Вот как я хочу, чтобы мои данные возвращались:

Column 1 | Column 2 | Column 3
------------------------------
    I    |     1    |     1
    O    |     2    |     2
    O    |     2    |     3
    I    |     3    |     4
    O    |     4    |     5
    O    |     4    |     6
    O    |     4    |     7
    O    |     4    |     8
    I    |     5    |     9
    O    |     6    |    10
  • Column 1 — это I и O, означающие вход и выход.
  • Column 2 — это группа строк (должна увеличиваться при изменении Column 1).
  • Column 3 — это номер строки.

Итак, как я могу написать свой запрос, чтобы Column 2 увеличивалось каждый раз, когда изменяется Column 1?


person jankenshin2004    schedule 25.03.2015    source источник
comment
У вас есть другой столбец, чтобы найти заказ   -  person Pரதீப்    schedule 25.03.2015
comment
твой вопрос не имеет смысла   -  person t-clausen.dk    schedule 25.03.2015
comment
Что-нибудь пробовали до сих пор?   -  person stb    schedule 25.03.2015
comment
Я пробовал зацикливать, это работает, но для 30K записей требуется 30 минут.   -  person jankenshin2004    schedule 25.03.2015
comment
почему вы снова и снова удаляете форматирование?   -  person A ツ    schedule 25.03.2015


Ответы (2)


Во-первых, для выполнения такого рода операций вам нужен столбец, который может определять порядок строк. Если у вас есть столбец, который определяет этот порядок, например, столбец идентификаторов, его можно использовать, чтобы сделать что-то вроде этого:

Запускаемый образец:

CREATE TABLE #Groups
    (
      id INT IDENTITY(1, 1) , -- added identity to provide order
      Column1 VARCHAR(1)
    )

INSERT  INTO #Groups
        ( Column1 )
VALUES  ( 'I' ),
        ( 'O' ),
        ( 'O' ),
        ( 'I' ),
        ( 'O' ),
        ( 'O' ),
        ( 'O' ),
        ( 'O' ),
        ( 'I' ),
        ( 'O' );

;
WITH    cte
          AS ( SELECT   id ,
                        Column1 ,
                        1 AS Column2
               FROM     #Groups
               WHERE    id = 1
               UNION ALL
               SELECT   g.id ,
                        g.Column1 ,
                        CASE WHEN g.Column1 = cte.Column1 THEN cte.Column2
                             ELSE cte.Column2 + 1
                        END AS Column2
               FROM     #Groups g
                        INNER JOIN cte ON cte.id + 1 = g.id
             )
    SELECT  *
    FROM    cte
    OPTION (MAXRECURSION 0) -- required to allow for more than 100 recursions

DROP TABLE #Groups

Этот код эффективно перебирает записи, сравнивая каждую строку со следующей и увеличивая значение Column2, если значение в Column1 изменяется.

Если у вас нет столбца идентификаторов, вы можете добавить его.

Источник @AeroX:

При 30K записях последняя строка: OPTION (MAXRECURSION 0) требуется для переопределения 100 рекурсий по умолчанию при использовании Общее табличное выражение (CTE). Установка его на 0 означает, что он не ограничен.

person Tanner    schedule 25.03.2015
comment
С OP, имеющим 30 тыс. строк, им нужно будет установить уровень MAXRECURSION выше при использовании этого метода. - person AeroX; 25.03.2015

Это будет работать, если у вас есть sqlserver 2012+.

DECLARE @t table(col1 char(1), col3 int identity(1,1))

INSERT @t values
('I'), ('O'), ('O'), ('I'), ('O'), ('O'), ('O'), ('O'), ('I'), ('O')

;WITH CTE AS
(
  SELECT 
    case when lag(col1) over (order by col3) = col1 
         then 0 else 1 end increase, 
    col1,
    col3
  FROM @t
)
SELECT
  col1,
  sum(increase) over (order by col3) col2,
  col3
FROM CTE

Результат:

col1  col2  col3
I     1     1
O     2     2
O     2     3
I     3     4
O     4     5
O     4     6
O     4     7
O     4     8
I     5     9
O     6     10
person t-clausen.dk    schedule 25.03.2015