Получить список дат между двумя датами - PullRequest
85 голосов
/ 04 февраля 2009

Используя стандартные функции mysql, можно написать запрос, который будет возвращать список дней между двумя датами.

например, учитывая 2009-01-01 и 2009-01-13, он вернет таблицу из одного столбца со значениями:

 2009-01-01 
 2009-01-02 
 2009-01-03
 2009-01-04 
 2009-01-05
 2009-01-06
 2009-01-07
 2009-01-08 
 2009-01-09
 2009-01-10
 2009-01-11
 2009-01-12
 2009-01-13

Редактировать: Похоже, я не был ясно. Я хочу создать этот список. У меня есть значения, хранящиеся в базе данных (по дате и времени), но я хочу, чтобы они агрегировались при левом внешнем соединении со списком дат, как указано выше (я ожидаю нулевое значение с правой стороны некоторых из этого объединения в течение нескольких дней и буду обрабатывать ).

Ответы [ 19 ]

1 голос
/ 04 августа 2011

Это решение работает с MySQL 5.0
Создать таблицу - mytable.
Схема не материальная. Что имеет значение, так это количество строк в нем.
Таким образом, вы можете хранить только один столбец типа INT с 10 строками, значения - от 1 до 10.

SQL:

set @tempDate=date('2011-07-01') - interval 1 day;
select
date(@tempDate := (date(@tempDate) + interval 1 day)) as theDate
from mytable x,mytable y
group by theDate
having theDate <= '2011-07-31';

Ограничение: Максимальное количество дат, возвращаемых вышеуказанным запросом, будет
(rows in mytable)*(rows in mytable) = 10*10 = 100.

Вы можете увеличить этот диапазон, изменив часть формы в sql:
из mytable x, mytable y, mytable z
Итак, диапазон будет 10*10*10 =1000 и т. Д.

0 голосов
/ 31 августа 2016

Мне нужен список со всеми месяцами между 2 датами для статистики. 2 даты - начало и конец подписки. Таким образом, в списке отображаются все месяцы и количество подписок в месяц.

MYSQL

CREATE PROCEDURE `get_amount_subscription_per_month`()
BEGIN
   -- Select the ultimate start and enddate from subscribers
   select @startdate := min(DATE_FORMAT(a.startdate, "%Y-%m-01")), 
          @enddate := max(DATE_FORMAT(a.enddate, "%Y-%m-01")) + interval 1 MONTH
   from subscription a;

   -- Tmp table with all months (dates), you can always format them with DATE_FORMAT) 
   DROP TABLE IF EXISTS tmp_months;
   create temporary table tmp_months (
      year_month date,
      PRIMARY KEY (year_month)
   );


   set @tempDate=@startdate;  #- interval 1 MONTH;

   -- Insert every month in tmp table
   WHILE @tempDate <= @enddate DO
     insert into tmp_months (year_month) values (@tempDate);
     set @tempDate = (date(@tempDate) + interval 1 MONTH);
   END WHILE;

   -- All months
   select year_month from tmp_months;

   -- If you want the amount of subscription per month else leave it out
   select mnd.year_month, sum(subscription.amount) as subscription_amount
   from tmp_months mnd
   LEFT JOIN subscription ON mnd.year_month >= DATE_FORMAT(subscription.startdate, "%Y-%m-01") and mnd.year_month <= DATE_FORMAT(subscription.enddate, "%Y-%m-01")
   GROUP BY mnd.year_month;

 END
0 голосов
/ 11 июля 2014
DELIMITER $$  
CREATE PROCEDURE popula_calendario_controle()
   BEGIN
      DECLARE a INT Default 0;
      DECLARE first_day_of_year DATE;
      set first_day_of_year = CONCAT(DATE_FORMAT(curdate(),'%Y'),'-01-01');
      one_by_one: LOOP
         IF dayofweek(adddate(first_day_of_year,a)) <> 1 THEN
            INSERT INTO calendario.controle VALUES(null,150,adddate(first_day_of_year,a),adddate(first_day_of_year,a),1);
         END IF;
         SET a=a+1;
         IF a=365 THEN
            LEAVE one_by_one;
         END IF;
      END LOOP one_by_one;
END $$

эта процедура вставит все даты с начала года по настоящее время, просто замените дни «начала» и «конца», и вы готовы к работе!

0 голосов
/ 15 августа 2013
select * from table_name where col_Date between '2011/02/25' AND DATEADD(s,-1,DATEADD(d,1,'2011/02/27'))

Здесь сначала добавьте день к текущей конечной дате, это будет 2011-02-28 00:00:00, затем вычтите одну секунду, чтобы сделать конечную дату 2011-02-27 23:59:59. Делая это, вы можете получить все даты между заданными интервалами.

выход:
2011/02/25
2011/02/26
2011/02/27

0 голосов
/ 06 апреля 2012

Я давно с этим борюсь. Поскольку это первое попадание в Google, когда я искал решение, позвольте мне опубликовать информацию о том, где я до сих пор находился.

SET @d := '2011-09-01';
SELECT @d AS d, cast( @d := DATE_ADD( @d , INTERVAL 1 DAY ) AS DATE ) AS new_d
  FROM [yourTable]
  WHERE @d <= '2012-05-01';

Замените [yourTable] таблицей из вашей базы данных. Хитрость заключается в том, что количество строк в выбранной вами таблице должно быть> = количество дат, которые вы хотите вернуть. Я попытался использовать табличный заполнитель DUAL, но он вернул бы только одну строку.

0 голосов
/ 19 августа 2010

Я бы использовал что-то похожее на это:

DECLARE @DATEFROM AS DATETIME
DECLARE @DATETO AS DATETIME
DECLARE @HOLDER TABLE(DATE DATETIME)

SET @DATEFROM = '2010-08-10'
SET @DATETO = '2010-09-11'

INSERT INTO
    @HOLDER
        (DATE)
VALUES
    (@DATEFROM)

WHILE @DATEFROM < @DATETO
BEGIN

    SELECT @DATEFROM = DATEADD(D, 1, @DATEFROM)
    INSERT 
    INTO
        @HOLDER
            (DATE)
    VALUES
        (@DATEFROM)
END

SELECT 
    DATE
FROM
    @HOLDER

Тогда таблица переменных @HOLDER содержит все даты, увеличенные на один день между этими двумя датами, готовые присоединиться к вашему сердцу.

0 голосов
/ 19 апреля 2018

Я использую Server version: 5.7.11-log MySQL Community Server (GPL)

Теперь мы решим это простым способом.

Я создал таблицу с именем "datetable"

mysql> describe datetable;
+---------+---------+------+-----+---------+-------+
| Field   | Type    | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| colid   | int(11) | NO   | PRI | NULL    |       |
| coldate | date    | YES  |     | NULL    |       |
+---------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)

Теперь мы увидим вставленные записи.

mysql> select * from datetable;
+-------+------------+
| colid | coldate    |
+-------+------------+
|   101 | 2015-01-01 |
|   102 | 2015-05-01 |
|   103 | 2016-01-01 |
+-------+------------+
3 rows in set (0.00 sec)

и здесь наш запрос для получения записей в течение двух дат, а не этих дат.

mysql> select * from datetable where coldate > '2015-01-01' and coldate < '2016-01-01';
+-------+------------+
| colid | coldate    |
+-------+------------+
|   102 | 2015-05-01 |
+-------+------------+
1 row in set (0.00 sec)

надеюсь, что это поможет многим.

0 голосов
/ 05 февраля 2019

Элегантное решение с использованием новой рекурсивной (Common Table Expressions) функциональности в MariaDB> = 10.3 и MySQL> = 8.0.

WITH RECURSIVE t as (
    select '2019-01-01' as dt
  UNION
    SELECT DATE_ADD(t.dt, INTERVAL 1 DAY) FROM t WHERE DATE_ADD(t.dt, INTERVAL 1 DAY) <= '2019-04-30'
)
select * FROM t;

Вышеприведенное возвращает таблицу дат между «2019-01-01» и «2019-04-30».

0 голосов
/ 04 февраля 2009

Создайте хранимую процедуру, которая принимает два параметра a_begin и a_end. Создайте временную таблицу с именем t, объявите переменную d, присвойте a_begin d и запустите WHILE loop INSERT, вводя d в t и вызвав функцию ADDDATE, чтобы увеличить значение d. Наконец SELECT * FROM t.

...