2009-07-16 5 views
3

Учитывая следующую таблицу:GROUP BY для непрерывного строк в SQL

 
ID State Date 
12 1  2009-07-16 10:00 
45 2  2009-07-16 13:00 
67 2  2009-07-16 14:40 
77 1  2009-07-16 15:00 
89 1  2009-07-16 15:30 
99 1  2009-07-16 16:00 

Вопрос:
Как я GROUP полем «государство», сохраняя при этом границы между изменениями состояния?

SELECT MIN(ID) AS ID, State, MIN(Date) AS Date, COUNT(ID) AS Count 
FROM table GROUP BY State 

приводит следующее:

 
ID State Date    Count 
12 1  2009-07-16 10:00 4 
45 2  2009-07-16 13:00 2 


, но это, как ожидается:

 
ID State Date    Count 
12 1  2009-07-16 10:00 1 
45 2  2009-07-16 13:00 2 
77 1  2009-07-16 15:00 3 


Возможно ли это в SQL? Я не нашел решение до сих пор ...

ответ

8
SELECT MIN(id) AS id, MIN(ts) AS ts, MIN(state) AS state, COUNT(*) cnt 
FROM (
     SELECT @r := @r + (@state != state) AS gn, 
       @state := state AS sn, 
       s.* 
     FROM (
       SELECT @r := 0, 
         @state := 0 
       ) vars, 
       t_state s 
     ORDER BY 
       ts 
     ) q 
GROUP BY 
     gn 

создание Таблица сценариев для тестирования:

CREATE TABLE t_state (id INT NOT NULL PRIMARY KEY, state INT NOT NULL, ts DATETIME NOT NULL); 

INSERT 
INTO t_state 
VALUES 
(12, 1,  '2009-07-16 10:00'), 
(45, 2,  '2009-07-16 13:00'), 
(67, 2,  '2009-07-16 14:40'), 
(77, 1,  '2009-07-16 15:00'), 
(89, 1,  '2009-07-16 15:30'), 
(99, 1,  '2009-07-16 16:00'); 
+0

удивительным, он просто работает. – Kaii

0

я мог бы заявлять очевидное, но если вы готовы использовать Transact-SQL, вы можете перебирать строки таблицы и строить свой собственный набор результатов, что, вероятно, кажется хлопотным, но это определенно будет работать. Итерация может быть выполнена without the use of cursors.

2

Это, как сделать это с КТР на MSSQL сервере

-- DROP TABLE MyLog 
CREATE TABLE MyLog(
     ID   INT PRIMARY KEY 
     , State  INT 
     , Date  DATETIME 
     ) 
INSERT MyLog 
SELECT 12, 1, '2009-07-16 10:00' UNION ALL 
SELECT 45, 2, '2009-07-16 13:00' UNION ALL 
SELECT 67, 2, '2009-07-16 14:40' UNION ALL 
SELECT 77, 1, '2009-07-16 15:00' UNION ALL 
SELECT 89, 1, '2009-07-16 15:30' UNION ALL 
SELECT 99, 1, '2009-07-16 16:00' 

;WITH CTE 
AS  (
     SELECT ROW_NUMBER() OVER(ORDER BY ID) AS RowNo 
       , * 
     FROM MyLog 
     ) 
, MyLogGroup 
AS  (
     SELECT l.* 
       , (SELECT MAX(ID) 
        FROM CTE c 
        WHERE NOT EXISTS (SELECT * FROM CTE 
             WHERE RowNo = c.RowNo-1 AND State = c.State) 
          AND c.ID <= l.ID) AS GroupID 
     FROM MyLog l 
     ) 
SELECT * 
FROM MyLogGroup 
+0

как это связано с mysql, и у меня нет сервера MS SQL, я не могу проверить ваш код. в любом случае .. спасибо за усилия и ваш вклад, это поможет другим людям с аналогичными проблемами. – Kaii

1

Here является длительная описание того, как решения, как то, что предлагает Quassnoi работать

 Смежные вопросы

  • Нет связанных вопросов^_^