Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Contar o número de linhas em compartimentos de 30 dias


Sem procedimentos armazenados, tabelas temporárias, apenas uma consulta e um plano de execução eficiente com um índice na coluna de data:
select

  subdate(
    '2012-12-31',
    floor(dateDiff('2012-12-31', dateStampColumn) / 30) * 30 + 30 - 1
  ) as "period starting",

  subdate(
    '2012-12-31',
    floor(dateDiff('2012-12-31', dateStampColumn) / 30) * 30
  ) as "period ending",

  count(*)

from
  YOURTABLE
group by floor(dateDiff('2012-12-31', dateStampColumn) / 30);

Deve ser bastante óbvio o que está acontecendo aqui, exceto por este encantamento:
floor(dateDiff('2012-12-31', dateStampColumn) / 30)

Essa expressão aparece várias vezes e é avaliada como o número de períodos de 30 dias atrás dateStampColumn é. dateDiff retorna a diferença em dias, divide por 30 para obter em períodos de 30 dias e alimenta tudo para floor() para arredondar para um número inteiro. Assim que tivermos esse número, podemos GROUP BY e, além disso, fazemos um pouco de matemática para traduzir esse número de volta para as datas inicial e final do período.

Substituir '2012-12-31' com now() se você preferir. Aqui estão alguns dados de exemplo:
CREATE TABLE YOURTABLE
    (`Id` int, `dateStampColumn` datetime);

INSERT INTO YOURTABLE
    (`Id`, `dateStampColumn`)
VALUES
    (1, '2012-10-15 02:00:00'),
    (1, '2012-10-17 02:00:00'),
    (1, '2012-10-30 02:00:00'),
    (1, '2012-10-31 02:00:00'),
    (1, '2012-11-01 02:00:00'),
    (1, '2012-11-02 02:00:00'),
    (1, '2012-11-18 02:00:00'),
    (1, '2012-11-19 02:00:00'),
    (1, '2012-11-21 02:00:00'),
    (1, '2012-11-25 02:00:00'),
    (1, '2012-11-25 02:00:00'),
    (1, '2012-11-26 02:00:00'),
    (1, '2012-11-26 02:00:00'),
    (1, '2012-11-24 02:00:00'),
    (1, '2012-11-23 02:00:00'),
    (1, '2012-11-28 02:00:00'),
    (1, '2012-11-29 02:00:00'),
    (1, '2012-11-30 02:00:00'),
    (1, '2012-12-01 02:00:00'),
    (1, '2012-12-02 02:00:00'),
    (1, '2012-12-15 02:00:00'),
    (1, '2012-12-17 02:00:00'),
    (1, '2012-12-18 02:00:00'),
    (1, '2012-12-19 02:00:00'),
    (1, '2012-12-21 02:00:00'),
    (1, '2012-12-25 02:00:00'),
    (1, '2012-12-25 02:00:00'),
    (1, '2012-12-26 02:00:00'),
    (1, '2012-12-26 02:00:00'),
    (1, '2012-12-24 02:00:00'),
    (1, '2012-12-23 02:00:00'),
    (1, '2012-12-31 02:00:00'),
    (1, '2012-12-30 02:00:00'),
    (1, '2012-12-28 02:00:00'),
    (1, '2012-12-28 02:00:00'),
    (1, '2012-12-30 02:00:00');

E o resultado:
period starting     period ending   count(*)
2012-12-02          2012-12-31      17
2012-11-02          2012-12-01      14
2012-10-03          2012-11-01      5

os pontos finais do período são inclusivos.

Brinque com isso em SQL Fiddle .

Há um pouco de bobagem em potencial, pois qualquer período de 30 dias com zero linhas correspondentes não será incluído no resultado. Se você pudesse juntar isso contra uma tabela de períodos, isso poderia ser eliminado. No entanto, o MySQL não tem nada parecido com o generate_series() , então você teria que lidar com isso em seu aplicativo ou tentar este truque inteligente .