SQL Count Группировка по последовательности чисел

у меня есть таблица SQL, как это:

id      pNum
-----   --------
100     12
100     13
100     15
100     16
100     17
200     18
200     19
300     20
300     21
300     25

и я хочу сгруппировать по идентификатору и последовательностям pNum и подсчитать количество строк. имея такой результат.

id      res
-----   --------
100     2
100     3
200     2
300     2
300     1

Любая идея о том, как это сделать?


person Thorgrim the Dwarf    schedule 07.02.2013    source источник
comment
какие rdbms вы используете?   -  person Taryn    schedule 07.02.2013
comment
что res представляет в сгруппированной таблице   -  person Saddam Abu Ghaida    schedule 07.02.2013
comment
Майкрософт SQL ------------------   -  person Thorgrim the Dwarf    schedule 07.02.2013
comment
О, вы группируете res как непрерывные последовательности, верно?   -  person Nick Vaccaro    schedule 07.02.2013
comment
res — это количество идентификаторов, сгруппированных последовательностями pnum.   -  person Thorgrim the Dwarf    schedule 07.02.2013
comment
ник прав, группировка по непрерывным последовательностям   -  person Thorgrim the Dwarf    schedule 07.02.2013
comment
пахнет рекурсией; ну и домашнее задание...   -  person Bogdan Gavril MSFT    schedule 07.02.2013


Ответы (2)


Если ваша СУБД поддерживает оконные функции (например, SQL Server 2005+)

SELECT id,
       count(*) AS res
FROM   (SELECT *,
               [pNum] - ROW_NUMBER() OVER (PARTITION BY [id] ORDER BY [pNum]) AS Grp
        FROM   YourTable) T
GROUP  BY id,
          Grp 

скрипт SQL

person Martin Smith    schedule 07.02.2013
comment
@ user2051336 - Этот тип требований часто называют поиском пробелов и островов. Подход в моем ответе приписывается Ицику Бен Гану AFAIK. Какая у вас версия SQL Server? - person Martin Smith; 07.02.2013
comment
@MartinSmith - это также может быть полезно для сервера MS SQL stackoverflow.com/a/4324654/247184 - person VoodooChild; 05.09.2014

Используя решение из этого вопроса:

declare @table table
(
    id int
    , pnum int
)


insert into @table
values (100,    12)
, (100,     13)
, (100,     15)
, (100,     16)
, (100,     17)
, (200,     18)
, (200,     19)
, (300,     20)
, (300,     21)
, (300,     25)

;WITH numbered AS (
  SELECT
    ID, pnum,
    SeqGroup = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY pnum) - pnum
  FROM @table
)
SELECT
  ID,
  COUNT(*) AS res
FROM numbered
GROUP BY ID, SeqGroup
ORDER BY id, MIN(pnum)
person Nick Vaccaro    schedule 07.02.2013
comment
Хороший трюк с row_number() - pnum. Что делает это задание SeqGroup = ? - person a_horse_with_no_name; 07.02.2013
comment
@a_horse_with_no_name - Как я подозреваю, вы, вероятно, знаете, что это специфичный для SQL Server способ присвоения псевдонимов столбцам. - person Martin Smith; 07.02.2013
comment
@MartinSmith: не совсем так. Есть ли разница со стандартным синтаксисом as foo? - person a_horse_with_no_name; 07.02.2013
comment
@a_horse_with_no_name - Не совсем так. Некоторые люди (такие как Аарон Бертран) предпочитают его, так как легче изменить псевдонимы столбцов. Плохие привычки, от которых следует избавиться: использование AS вместо = для псевдонимов столбцов - person Martin Smith; 07.02.2013