我需要一个 MySQL 表来保存 2011-01-01 和 2011-12-31 之间的所有日期。我创建了一个表,其中一个列名为“_date”,输入 DATE。
通过什么查询,我可以在表格中填充所有所需的日期(而不必手动输入)?
试试这个:
DROP PROCEDURE IF EXISTS filldates;
DELIMITER |
CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE)
BEGIN
WHILE dateStart <= dateEnd DO
INSERT INTO tablename (_date) VALUES (dateStart);
SET dateStart = date_add(dateStart, INTERVAL 1 DAY);
END WHILE;
END;
|
DELIMITER ;
CALL filldates('2011-01-01','2011-12-31');
这是可以使用的 SQL Fiddle:http://sqlfiddle.com/#!2/65d13/1
编辑(检查日期是否已存在)按照Andrew Fox的要求。
CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE)
BEGIN
DECLARE adate date;
WHILE dateStart <= dateEnd DO
SET adate = (SELECT mydate FROM MyDates WHERE mydate = dateStart);
IF adate IS NULL THEN BEGIN
INSERT INTO MyDates (mydate) VALUES (dateStart);
END; END IF;
SET dateStart = date_add(dateStart, INTERVAL 1 DAY);
END WHILE;
END;//
这是可以使用的 SQL Fiddle:http://sqlfiddle.com/#!2/66f86/1
我不希望我的 SQL 查询需要外部依赖项(需要有一个日历表、用日期填充临时表的过程等)。此查询的最初想法来自 http://jeffgarretson.wordpress.com /2012/05/04/generate-a-range-of-dates-in-mysql/ 为了清晰和易用性,我对其进行了稍微优化。
SELECT (CURDATE() - INTERVAL c.number DAY) AS date
FROM (SELECT singles + tens + hundreds number FROM
( SELECT 0 singles
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) singles JOIN
(SELECT 0 tens
UNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30
UNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60
UNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90
) tens JOIN
(SELECT 0 hundreds
UNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300
UNION ALL SELECT 400 UNION ALL SELECT 500 UNION ALL SELECT 600
UNION ALL SELECT 700 UNION ALL SELECT 800 UNION ALL SELECT 900
) hundreds
ORDER BY number DESC) c
WHERE c.number BETWEEN 0 and 364
优化和扩展此表以供其他用途很简单。如果您只需要一周的数据,您可以轻松摆脱数十、数百表。
如果您需要更大的数字集,很容易添加数千表。您只需复制并粘贴具有数百的表格并添加零到九个数字即可。
编辑:SQL SERVER 版本需要细微调整
SELECT DATEADD(day, -1 * c.number, CAST(GETDATE() AS DATE)) AS date
FROM (SELECT singles + tens + hundreds number FROM
( SELECT 0 as singles
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) singles CROSS JOIN
(SELECT 0 tens
UNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30
UNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60
UNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90
) tens CROSS JOIN
(SELECT 0 hundreds
UNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300
UNION ALL SELECT 400 UNION ALL SELECT 500 UNION ALL SELECT 600
UNION ALL SELECT 700 UNION ALL SELECT 800 UNION ALL SELECT 900
) hundreds
) c
WHERE c.number BETWEEN 0 and 364
ORDER BY date ASC
如果你遇到像我这样程序被禁止的情况,并且你的sql用户没有插入权限,因此不允许插入,但你想生成特定时间段内的日期列表 ,说今年要做一些聚合,使用这个
select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) gen_date from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where gen_date between '2017-01-01' and '2017-12-31'
我发现这个“粘贴即用”变体有效:
DROP PROCEDURE IF EXISTS FillCalendar;
DROP TABLE IF EXISTS calendar;
CREATE TABLE IF NOT EXISTS calendar(calendar_date DATE NOT NULL PRIMARY KEY);
DELIMITER $$
CREATE PROCEDURE FillCalendar(start_date DATE, end_date DATE)
BEGIN
DECLARE crt_date DATE;
SET crt_date = start_date;
WHILE crt_date <= end_date DO
INSERT IGNORE INTO calendar VALUES(crt_date);
SET crt_date = ADDDATE(crt_date, INTERVAL 1 DAY);
END WHILE;
END$$
DELIMITER ;
CALL FillCalendar('2013-01-01', '2013-01-03');
CALL FillCalendar('2013-01-01', '2013-01-07');
我最近需要创建一个
calendar_date
表,如下所示:
CREATE TABLE `calendar_date` (
`date` DATE NOT NULL -- A calendar date.
, `day` SMALLINT NOT NULL -- The day of the year for the date, 1-366.
, `month` TINYINT NOT NULL -- The month number, 1-12.
, `year` SMALLINT NOT NULL -- The year.
, PRIMARY KEY (`id`));
然后,我使用以下查询将
January 1, 2001
和 December 31, 2100
(包含两者)之间的所有可能日期填充到其中:
INSERT INTO `calendar_date` (`date`
, `day`
, `month`
, `year`)
SELECT
DATE
, INCREMENT + 1
, MONTH(DATE)
, YEAR(DATE)
FROM
-- Generate all possible dates for every year from 2001 to 2100.
(SELECT
DATE_ADD(CONCAT(YEAR, '-01-01'), INTERVAL INCREMENT DAY) DATE
, INCREMENT
FROM
(SELECT
(UNITS + TENS + HUNDREDS) INCREMENT
FROM
(SELECT 0 UNITS UNION
SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION
SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION
SELECT 7 UNION SELECT 8 UNION SELECT 9) UNITS
CROSS JOIN
(SELECT 0 TENS UNION
SELECT 10 UNION SELECT 20 UNION SELECT 30 UNION
SELECT 40 UNION SELECT 50 UNION SELECT 60 UNION
SELECT 70 UNION SELECT 80 UNION SELECT 90) TENS
CROSS JOIN
(SELECT 0 HUNDREDS UNION
SELECT 100 UNION SELECT 200 UNION SELECT 300 UNION
SELECT 400 UNION SELECT 500 UNION SELECT 600 UNION
SELECT 700 UNION SELECT 800 UNION SELECT 900) HUNDREDS
) INCREMENT
-- For every year from 2001 to 2100, find the number of days in the year.
, (SELECT
YEAR
, DAYOFYEAR(CONCAT(YEAR, '-12-31')) - DAYOFYEAR(CONCAT(YEAR, '-01-01')) + 1 DAYS
FROM
-- Generate years from 2001 to 2100.
(SELECT
(2000 + UNITS + TENS) YEAR
FROM
(SELECT 0 UNITS UNION
SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION
SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION
SELECT 7 UNION SELECT 8 UNION SELECT 9) UNITS
CROSS JOIN
(SELECT 0 TENS UNION
SELECT 10 UNION SELECT 20 UNION SELECT 30 UNION
SELECT 40 UNION SELECT 50 UNION SELECT 60 UNION
SELECT 70 UNION SELECT 80 UNION SELECT 90) TENS
) YEAR
WHERE
YEAR BETWEEN 2001 AND 2100
) YEAR
WHERE
INCREMENT BETWEEN 0 AND DAYS - 1
ORDER BY
YEAR
, INCREMENT) DATE;
在我的本地 MySQL 数据库上,
INSERT
查询只花了几秒钟。希望这对某人有帮助。
如果你的表有足够大的连续 id 集,你可以使用 -
INSERT INTO tablename (_date)
SELECT '2011-01-01' + INTERVAL (id - 1) DAY
FROM some_table_with_lots_of_ids
WHERE id BETWEEN 1 AND 365
注意:但请注意,这可能会让您在闰年(有 366 天)遇到麻烦
这可以在 PHP 中通过使用简单的 for 循环来实现。有几种方法可以做到这一点。一种方法是将原始日期放入变量中,并通过在每个循环上添加 +1 天来让循环每天运行,例如,您将从 01/01/2011 开始,然后循环将第一次添加 0,下一次添加 1 天,然后是 2 天,依此类推到 $i 变量中。然后,您可以打印出这些天数或将它们添加到数据库中。在这种情况下 $i 将代表以 0 为起点的计数器,<=365 is how many loops you want to go through which is equal to or less than the number of days and $i++ adds +1 to the $i variable on each loop.
date('Y-m-d' 将日期转换为 yyyy-mm-dd。使用大写 Y 将为您提供完整的 4 位数年份,而使用小写 y 将为您提供该年份的最后 2 位数字。您希望将其保留在这个命令将其添加到 mySQL 的日期字段中。
strtotime($originalDate 将日期解析为 Unix 时间戳,而 ."+".$i." day") 基本上将 $i 的值(以天为单位)添加到日期中。
最后是 mysqli 查询。 $db 代表数据库连接变量,需要将其更改为您为连接设置的任何变量。接下来是实际的查询。只需将单词 table 替换为您的表名称,并将 VALUES 之前的日期替换为您的日期行名称,然后就可以开始了。
以下是一个例子:
<?php
for($i=0;$i<=365;$i++){
$originalDate = "01/01/2011";
$date = date('Y-m-d',strtotime($originalDate . "+".$i." day"));
mysqli_query($db, "INSERT INTO table (date)VALUES('$date')");
}
使用 for 函数实现此目的的另一种方法是将 strtotime 日期直接包含在 for 操作中,作为与计数器变量的相反,这是一段更短的代码。将 $i=0 (起始计数器点)替换为开始日期点,然后使用小于或等于结束日期点(循环数),最后将第一个语句的加 +1 放入变量可供使用。
最后,将日期转换为 Y-m-d 格式,准备放入数据库并运行查询。
同样,与第一个示例一样,可以将其打印或直接放入数据库中。
以下是一个例子:
<?php
for ($startdate = strtotime("2011-01-01"); $startdate <= strtotime("2011-12-31"); $startdate = strtotime("+1 day", $startdate)) {
$date= date("Y-m-d", $startdate);
mysqli_query($db, "INSERT INTO tracking (date)VALUES('$date')");
}
我可能让它听起来比实际更令人困惑,但希望它至少能让您了解它是如何工作的。
感谢伊万德。 我有一个更好的解决方案,它允许您创建指定的日历表。 例如,如果我尝试创建 2014-04 的表,它看起来像这样:
SELECT (CURDATE() - INTERVAL c.number DAY) AS DATE
FROM
(
SELECT singles + tens + hundreds number FROM
(
SELECT 0 singles
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) singles JOIN
(
SELECT 0 tens
UNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30
UNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60
UNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90
) tens JOIN
(
SELECT 0 hundreds
UNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300
UNION ALL SELECT 400 UNION ALL SELECT 500 UNION ALL SELECT 600
UNION ALL SELECT 700 UNION ALL SELECT 800 UNION ALL SELECT 900
) hundreds
ORDER BY number DESC
) c
WHERE c.number BETWEEN
DAYOFYEAR(NOW()) - DAYOFYEAR('2014-04-01')- DAY(LAST_DAY('2014-04-01')) +1
AND
DAYOFYEAR(NOW()) - DAYOFYEAR('2014-04-01')
受到 IvanD 大量加入的启发,我得出这个:
SELECT DATE_ADD('2015-10-21', INTERVAL c.number DAY) AS DATE
FROM
(
SELECT singles + tens + hundreds+thousands number FROM
(
SELECT 0 singles
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) singles JOIN
(
SELECT 0 tens
UNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30
UNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60
UNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90
) tens JOIN
(
SELECT 0 hundreds
UNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300
UNION ALL SELECT 400 UNION ALL SELECT 500 UNION ALL SELECT 600
UNION ALL SELECT 700 UNION ALL SELECT 800 UNION ALL SELECT 900
) hundreds
JOIN
(
SELECT 0 thousands
UNION ALL SELECT 1000 UNION ALL SELECT 2000 UNION ALL SELECT 3000
UNION ALL SELECT 4000 UNION ALL SELECT 5000 UNION ALL SELECT 6000
UNION ALL SELECT 7000 UNION ALL SELECT 8000 UNION ALL SELECT 9000
) thousands
ORDER BY number DESC
) c
WHERE c.number BETWEEN
0
AND
DATEDIFF('2016-10-08', '2015-10-21')
INSERT INTO my_dates (\`_date\`) SELECT DATE_ADD('2011-01-01', INTERVAL @_tmp:=@_tmp+1 day) \`_date\`
FROM (SELECT @_tmp:=-1 d UNION SELECT 1 UNION SELECT 2
UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6
UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a /\*10^1\*/
JOIN (SELECT 0 UNION SELECT 1 UNION SELECT 2
UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6
UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b /\*10^2\*/
JOIN (SELECT 0 UNION SELECT 1 UNION SELECT 2
UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6
UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c /\*10^3\*/
WHERE @_tmp+1 BETWEEN 0 AND DATEDIFF('2011-12-31', '2011-01-01');