如何用sql的日期函数,分别查出1月~12月每个月的销售金额?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何用sql的日期函数,分别查出1月~12月每个月的销售金额?相关的知识,希望对你有一定的参考价值。
如何根据“销售金额”和“销售时间”,分别查出1月~12月每个月的销售金额?时间段是自动获取非手写上去的! 附图
谢谢你的回答,但是我不是固定只求某一年内 12个月的,我是实际时间是哪一年,就统计哪一年12个月,每个月的销售金额
一般情况下数据是按日期存到数据库中的,但考虑到某些月份是无数据的,可用如下语句:
1、创建测试表及插入测试数据:
create table sale
(id int,
name varchar(10),
sdate datetime,
money int)
insert into sale values (1,\'西瓜\',\'2015-01-01\',10)
insert into sale values (2,\'香蕉\',\'2015-01-05\',20)
insert into sale values (3,\'苹果\',\'2015-02-01\',60)
insert into sale values (4,\'葡萄\',\'2015-02-23\',345)
insert into sale values (5,\'柚子\',\'2015-04-23\',10)
insert into sale values (6,\'牛奶\',\'2015-05-12\',67)
insert into sale values (7,\'地瓜\',\'2015-06-01\',10)
insert into sale values (8,\'土豆\',\'2015-07-01\',10)
2、执行语句:
with t as
( select \'2015-\'+right(\'0\'+cast(number+1 as varchar),2) number from master..spt_values where type=\'p\' and number<=11 )
select t.number month,SUM(isnull(b.money,0)) money
from t left join sale b on
t.number=CONVERT(varchar(7),b.sdate,120)
group by t.number
结果截图:
参考技术A /*分别查出1月~12月每个月的销售金额
*/
--12个月总是固定的
DECLARE @sale TABLE(ddate DATETIME,fsale DECIMAL(18,2))
INSERT INTO @sale(ddate,fsale)
SELECT '2010-10-11',10000.01 UNION ALL
SELECT '2010-10-12',20000.02 UNION ALL
SELECT '2010-09-01',55555.11 UNION ALL
SELECT '2010-08-21',33333.33 UNION ALL
SELECT '2009-12-11',77777.11
SELECT SUM(CASE WHEN MONTH(s.ddate) = 1 THEN s.fsale ELSE 0 END) AS '一月',
SUM(CASE WHEN MONTH(s.ddate) = 2 THEN s.fsale ELSE 0 END) AS '二月',
SUM(CASE WHEN MONTH(s.ddate) = 3 THEN s.fsale ELSE 0 END) AS '三月',
SUM(CASE WHEN MONTH(s.ddate) = 4 THEN s.fsale ELSE 0 END) AS '四月',
SUM(CASE WHEN MONTH(s.ddate) = 5 THEN s.fsale ELSE 0 END) AS '五月',
SUM(CASE WHEN MONTH(s.ddate) = 6 THEN s.fsale ELSE 0 END) AS '六月',
SUM(CASE WHEN MONTH(s.ddate) = 7 THEN s.fsale ELSE 0 END) AS '七月',
SUM(CASE WHEN MONTH(s.ddate) = 8 THEN s.fsale ELSE 0 END) AS '八月',
SUM(CASE WHEN MONTH(s.ddate) = 9 THEN s.fsale ELSE 0 END) AS '九月',
SUM(CASE WHEN MONTH(s.ddate) = 10 THEN s.fsale ELSE 0 END) AS '十月',
SUM(CASE WHEN MONTH(s.ddate) = 11 THEN s.fsale ELSE 0 END) AS '十一月',
SUM(CASE WHEN MONTH(s.ddate) = 12 THEN s.fsale ELSE 0 END) AS '十二月'
FROM @sale AS s
WHERE YEAR(s.ddate) = 2010本回答被提问者采纳
如何用一系列日期填充表格?
【中文标题】如何用一系列日期填充表格?【英文标题】:How to populate a table with a range of dates? 【发布时间】:2012-04-25 07:08:50 【问题描述】:我需要一个 MySQL 表来保存 2011 年 1 月 1 日到 2011 年 12 月 31 日之间的所有日期。我创建了一个表,其中一列名称为“_date”,输入 DATE。
我可以通过什么查询在表格中填充所有所需的日期(而不必手动输入)?
【问题讨论】:
而您只使用mysql
?没有像 php 之类的?
为了回答你的问题,我可以访问 PHP,但是 (i) 真的不知道如何快速计算 PHP 范围内的所有日期和 (ii) 我猜 MySQL 可以效率高得多?
@hjpotter92:如果您对两者都同样了解,那么在 PHP 中确实不容易。在 MySQL 中执行此操作效率更高。
Here is an example 使用一个简单的命令来生成所需范围内的日期,并将它们通过管道传输到 sqlite 进行导入。我想最后一部分适应mysql会很容易。
【参考方案1】:
试试这个:
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
【讨论】:
至少在我的服务器上不起作用。alter routine command denied to user 'name'@'localhost' for routine 'name.filldates': DROP PROCEDURE IF EXISTS filldates
这次出现不同的错误:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER | CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE) BEGIN WHI' at line 1: DELIMITER | CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE) BEGIN WHILE dateStart <= dateEnd
你在运行自己的mysql服务器吗?如果是这样,请尝试以 root 用户身份登录,甚至向您当前的用户帐户授予必要的权限。示例:GRANT ALL ON mydb.* TO 'someuser'@'somehost';
更多信息:dev.mysql.com/doc/refman/5.1/en/…
致那些遇到语法错误的人。如果您通过 MySQL Workbench 连接到数据库并尝试运行创建过程脚本,您将收到语法错误。要运行此脚本,请右键单击“存储过程”菜单并选择“创建存储过程”,然后粘贴创建过程脚本,删除脚本末尾的“//”并点击“应用”。它对我有用。
Wana 给你双倍的分数!【参考方案2】:
如果您有一张表,其中包含足够大的连续 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 天)期间给您带来麻烦
【讨论】:
【参考方案3】:我发现这种粘贴式变体有效:
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');
【讨论】:
如果有人想要一些 pi: CALL FillCalendar('2013-01-01', '2099-01-04');从日历中选择计数(*); 31415【参考方案4】:我不希望我的 SQL 查询需要外部依赖项(需要有一个日历表、使用日期填充临时表的过程等)。这个查询的最初想法来自 http://jeffgarretson.wordpress.com/2012/05/04/generating-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
优化和扩展此表以用于其他用途很简单。如果您只需要一周的数据,您可以轻松摆脱数十和数百张表。
如果您需要更大的数字集,添加千位表很容易。您只需要复制并粘贴数百个表格并添加一个零到九个数字。
【讨论】:
这是一个非常有趣的概念,在处理很多日期时有点慢,但是,确实不错。不过也许比其他替代品更快。 非常聪明。如果有人问自己:内部生成的c表选择0-9、10-90、100-900之间的总和,这是一个很大的区间,数字从0到999(总共1000个数字)。外部选择是选择从 0 到 364(即 365 天)的数字列表,并选择一年到今天的所有日期(CURDATE)。【参考方案5】:感谢 IvanD。 我有一个更好的解决方案,它允许您创建指定的日历表。 例如,如果我试图创建一个 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')
【讨论】:
这不会返回table of 2014-04
,而是在所选月份和当年中包含已经过去的天数的表格!【参考方案6】:
受到 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')
【讨论】:
@Leniel Macaferi,你能帮忙***.com/questions/45490612/…【参考方案7】:这可以通过使用简单的 for 循环在 PHP 中实现。有几种方法可以做到这一点。一种方法是将原始日期放在一个变量中,并通过在每个循环上添加 +1 天让循环每天运行它,例如,您将从 01/01/2011 开始,然后循环将第一次添加 0,下一次添加 1 天,然后是 2 天,依此类推,以此类推到 $i 变量。然后您可以打印出日期或将它们添加到您的数据库中。在这种情况下,$i 将代表计数器,以 0 为起点,
date('Ymd' 将日期转换为 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 操作中,作为对 counter 变量的反对,这是一段更短的代码。将 $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')");
我可能让它听起来比实际更令人困惑,但希望它至少能让您了解它是如何工作的。
【讨论】:
虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性 cmets 挤满你的代码,因为这会降低代码和解释的可读性! 抱歉,这是我第一次发帖。我已经编辑了答案以包含描述。我还回复了另一个帖子,他想在另一篇文章中只添加一年中的周一至周五。我想你可以在我的个人资料中找到...【参考方案8】:如果您遇到像我这样程序被禁止,并且您的 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'
【讨论】:
这是这里最干净和最简洁的解决方案,但它可以做得更简洁:使用 HAVING 而不是 WHERE,您可以摆脱外部 SELECT 包装器。 这太棒了 喜欢这个,我正在与谷歌数据工作室合作,这是我在三天的搜索中发现的在一次选择中获取日期且不更改数据库的唯一方法。 我有一个数据库,我只能访问它的视图,而不是表本身,这是完美的。【参考方案9】:我最近需要创建一个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
查询只用了几秒钟。希望这对某人有所帮助。
【讨论】:
【参考方案10】: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');
【讨论】:
以上是关于如何用sql的日期函数,分别查出1月~12月每个月的销售金额?的主要内容,如果未能解决你的问题,请参考以下文章
获取每个月的第一个日期 SQL Server 2008 R2