我有一张包含相似信息的表格,我想在用户选择开始日期时提取这样的数据' 2015-01-22'和结束日期' 2015-07-31' 。 结果应如下所示。
Month Total Quantity
January: 8
February: 6
March: 0
April: 0
May: 2
June: 18
July: 6
这是一个示例查询和小提琴
CREATE TABLE orders
(
id INT PRIMARY KEY AUTO_INCREMENT,
order_date DATE,
product_id INT,
quantity INT,
customer_id INT
);
INSERT INTO orders (order_date, product_id, quantity, customer_id)
VALUES
('2015-01-01', 1, 2, 123),
('2015-01-06', 3, 6, 123),
('2015-02-14', 2, 4, 123),
('2015-02-15', 2, 2, 123),
('2015-05-16', 1, 1, 456),
('2015-05-17', 1, 1, 456),
('2015-06-18', 1, 5, 789),
('2015-06-18', 3, 7, 123),
('2015-06-10', 3, 6, 123),
('2015-07-13', 1, 5, 456),
('2015-07-14', 1, 1, 456);
http://sqlfiddle.com/#!2/01ac19/1
结果应该是每月订单总数
答案 0 :(得分:1)
首先,你想要什么 NEED被称为"日历表"。它们是您可以制作的最有用的分析表。他们的个人定义和数据填写方式各不相同,并且不在此处讨论,但出于我们的目的,我们将使用以下最低定义:
CREATE TABLE Calendar (calendarDate DATE PRIMARY KEY,
year INTEGER,
month INTEGER
dayOfMonth INTEGER);
......并且它充满了您期望的数据(从您的业务开始时插入每个日期,到将来的合理点)。您还需要索引 - 批次索引。
接下来,您需要考虑一些关于数据库的重要事项:如果将函数输出用作标准,它们就无法使用索引。基本上,如果它不在SELECT
子句中,使用函数(甚至通过一些隐式转换)会使查询变慢。因此,应该避免像YEAR(order_date)
这样的事情
那么我们如何通过年或月等事物进行汇总?通过范围查询。如果数据库有一个索引,那么查找一个范围的起点和终点(并且可以很好地并行化)也相当便宜。在我们的示例中,范围为>= startOfMonth
到< startOfNextMonth
。我们现在可以构建一个进程范围表:
SELECT year, month,
calendarDate AS monthStart,
calendarDate + INTERVAL 1 MONTH AS nextMonthStart
FROM Calendar
WHERE dayOfMonth = 1
AND calendarDate >= :queryStartRange
AND calendarDate < :queryEndRange
...其中:
表示月初值,留作读者的练习。
现在,请记住我的说法&#34;没有功能&#34;? calendarDate + INTERVAL 1 MONTH
实际上很重要。但是,这并不重要;结果表是如此之小(每年只有12行!),好的RDBMS可以将内容放在内存中以获得更快的结果(因为只需要更长的时间来命中索引)。
现在我们有了范围查询表,我们可以将它加入Orders
(&#34; fact&#34;)表;
SELECT DRange.year, DRange.month, SUM(Orders.quantity) AS total_quantity
FROM (SELECT year, month,
calendarDate AS monthStart,
calendarDate + INTERVAL 1 MONTH AS nextMonthStart
FROM Calendar
WHERE dayOfMonth = 1
AND calendarDate >= :queryStartRange
AND calendarDate < :queryEndRange) AS DRange
JOIN Orders
ON Orders.order_date >= DRange.monthStart
AND Orders.order_date < DRange.nextMonthStart
GROUP BY DRange.year, DRange.month
ORDER BY DRange.year, DRange.month
Example Fiddle
(有趣的诀窍:如果一个月没有订单,则使用LEFT JOIN
代替JOIN
会为空数量行提供净值 - 例如您的示例数据中的3月和4月)
那么这对我们有什么影响?基础数据的范围查询访问,这将使查询更快。如果由于某种原因,order_date
变为时间戳,则查询完全安全 - 我们将正确获取所有订单,并将其置于适当的月份。
答案 1 :(得分:0)
尝试此查询
SELECT MONTHNAME(DATE(order_date)) AS dateinfo, SUM(quantity) AS total_sales
FROM orders
GROUP BY dateinfo