在MySQL问题中分组

时间:2014-09-09 15:16:55

标签: mysql sql group-by

我有这张桌子

ignicao   dh_evento
1         2014-09-03 15:08:12
1         2014-09-03 15:08:26
1         2014-09-03 15:08:36
1         2014-09-03 15:08:47
0         2014-09-03 15:09:05
0         2014-09-03 15:39:05
0         2014-09-03 16:09:05
0         2014-09-03 16:39:05
0         2014-09-03 17:09:05
1         2014-09-03 17:09:13
1         2014-09-03 17:09:16
1         2014-09-03 17:09:48
1         2014-09-03 17:09:51

我想得到这个结果:

ignicao   dh_evento
1         2014-09-03 15:08:12
0         2014-09-03 15:09:05
1         2014-09-03 17:09:13

我正在执行此查询,但我上面没有得到这个结果。这是我的疑问:

select ignicao, dh_evento from tb_rastreamento 
where id_veiculo = 4
and dh_evento between '2014-09-03 00:00:00' and '2014-09-03 23:59:59'
group by ignicao
order by dh_evento

我只得到这个结果:

Ignition  dt_event
1         2014-09-03 15:08:12
0         2014-09-03 15:09:05

如何获得超过2行的结果?

我在SQL方面不太好,而且我被困了。

5 个答案:

答案 0 :(得分:1)

请记住,SQL通过 value 处理数据,而不是 position 。行不应该有任何隐含的顺序。所以GROUP BY将所有行组合在一起,其值为ignicao = 1,即使它们没有物理存储在表中。

如果您想将第一批1作为一个单独的组处理,则需要引入一个新的枚举来区分它们。您可以向表中添加一列并存储新值,或者在查询中动态执行此操作:

SELECT ignicao, dh_evento, IF(@i=ignicao, @grp, @grp:=@grp+1) AS grp, @i:=ignicao
FROM (SELECT @i:=null, @grp:=0) AS _init, this_table
WHERE dh_evento BETWEEN '2014-09-03 00:00:00' and '2014-09-03 23:59:59'
ORDER BY dh_evento;

只有当ignicao不等于上一行保存的值时,才会增加@grp。

然后,您可以在GROUP BY中使用新列grp

SELECT grp, MAX(ignicao) AS ignicao, MAX(dh_evento) AS dh_evento
FROM (
    SELECT ignicao, dh_evento, IF(@i=ignicao, @grp, @grp:=@grp+1) AS grp, @i:=ignicao
    FROM (SELECT @i:=null, @grp:=0) AS _init, this_table
    WHERE dh_evento BETWEEN '2014-09-03 00:00:00' and '2014-09-03 23:59:59'
    ORDER BY dh_evento) AS t
GROUP BY grp;

答案 1 :(得分:1)

使用简单的group by无法做到这一点。一种方法使用变量:

select r.ignicao, min(dh_evento)
from (select r.ignicao, r.dh_evento,
             (@grp := if(@i = @ignicao, @grp,
                         if(@i := @ignicao, @grp + 1, @grp + 1)
                        )
             ) as grp
      from tb_rastreamento r cross join
           (select @grp := NULL, @i := 0) vars
      where id_veiculo = 4 and dh_evento between '2014-09-03 00:00:00' and '2014-09-03 23:59:59'
      order by r.ignicao, r.dh_evento
     ) r
group by grp, r.ignicao;

答案 2 :(得分:0)

select ignicao, min(dh_evento)
from (
    select ignicao, dh_evento,
    if(@prevIgnicao = ignicao, @groupNum, @groupNum := @groupNum + 1) groupNum,
    (@prevIgnicao := ignicao)
    from tb_rastreamento
    where id_veiculo = 4
    and dh_evento between '2014-09-03 00:00:00' and '2014-09-03 23:59:59'
    cross join (select @prevIgnicao := null, @groupNum := 0) t1
    order by dh_evento
) t1 group by ignicao, groupNum

答案 3 :(得分:0)

或者这个(较慢的)解决方案......为了清晰起见我遗漏了一点......

 SELECT a.*
      , b.ignicao
   FROM 
      ( SELECT x.* 
             , COUNT(*) rank 
          FROM my_table x 
          JOIN my_table y 
            ON y.dh_evento <= x.dh_evento 
         GROUP 
            BY x.dh_evento
      ) a
   LEFT
   JOIN 
      ( SELECT x.* 
             , COUNT(*) rank 
          FROM my_table x 
          JOIN my_table y 
            ON y.dh_evento <= x.dh_evento 
         GROUP 
            BY x.dh_evento
      ) b
     ON b.ignicao = a.ignicao
    AND b.rank = a.rank - 1

  +---------+---------------------+------+---------+
  | ignicao | dh_evento           | rank | ignicao |
  +---------+---------------------+------+---------+
  |       1 | 2014-09-03 15:08:12 |    1 |    NULL |
  |       1 | 2014-09-03 15:08:26 |    2 |       1 |
  |       1 | 2014-09-03 15:08:36 |    3 |       1 |
  |       1 | 2014-09-03 15:08:47 |    4 |       1 |
  |       0 | 2014-09-03 15:09:05 |    5 |    NULL |
  |       0 | 2014-09-03 15:39:05 |    6 |       0 |
  |       0 | 2014-09-03 16:09:05 |    7 |       0 |
  |       0 | 2014-09-03 16:39:05 |    8 |       0 |
  |       0 | 2014-09-03 17:09:05 |    9 |       0 |
  |       1 | 2014-09-03 17:09:13 |   10 |    NULL |
  |       1 | 2014-09-03 17:09:16 |   11 |       1 |
  |       1 | 2014-09-03 17:09:48 |   12 |       1 |
  |       1 | 2014-09-03 17:09:51 |   13 |       1 |
  +---------+---------------------+------+---------+

答案 4 :(得分:0)

这有效;唯一的问题是没有计算秒数;它们总是显示00.注意我确实为此工作添加了一个唯一的ID列

CREATE TABLE #TEST
(
    ID  INT,
    A   INT,
    B   SMALLDATETIME,
)

INSERT INTO #TEST VALUES(1,1,'2014-09-03 15:08:12')
INSERT INTO #TEST VALUES(2,1,'2014-09-03 15:08:26')
INSERT INTO #TEST VALUES(3,1,'2014-09-03 15:08:36')
INSERT INTO #TEST VALUES(4,1,'2014-09-03 15:08:47')
INSERT INTO #TEST VALUES(5,0,'2014-09-03 15:09:05')
INSERT INTO #TEST VALUES(6,0,'2014-09-03 15:39:05')
INSERT INTO #TEST VALUES(7,0,'2014-09-03 16:09:05')
INSERT INTO #TEST VALUES(8,0,'2014-09-03 16:39:05')
INSERT INTO #TEST VALUES(9,0,'2014-09-03 17:09:05')
INSERT INTO #TEST VALUES(10,1,'2014-09-03 17:09:13')
INSERT INTO #TEST VALUES(11,1,'2014-09-03 17:09:16')
INSERT INTO #TEST VALUES(12,1,'2014-09-03 17:09:48')
INSERT INTO #TEST VALUES(13,1,'2014-09-03 17:09:51')


CREATE TABLE #Test2
(
    ID    INT,
    A     INT,
    B     SMALLDATETIME,
    PrevA INT
)
INSERT INTO #Test2
(
    ID,
    A,
    B,
    PrevA
)
select 
    ID,
    A,
    B,
    LAG(A)  OVER (ORDER BY ID) AS 'PrevA'
from #TEST
order by B asc

select 
    A,
    B
from #Test2
Where A != PrevA OR PrevA IS NULL