我有下表代表文章的预订:
+---+------------+----------+-------------+-------------+
|id | article_id | quantity | starts_at | ends_at |
+---+------------+----------+-------------+-------------+
| 1 | 1 | 1 | 2015-03-01 | 2015-03-20 |
| 2 | 1 | 2 | 2015-03-02 | 2015-03-03 |
| 3 | 1 | 3 | 2015-03-04 | 2015-03-15 |
| 4 | 1 | 2 | 2015-03-16 | 2015-03-22 |
| 5 | 1 | 2 | 2015-03-11 | 2015-03-19 |
| 6 | 2 | 2 | 2015-03-06 | 2015-03-22 |
| 7 | 2 | 3 | 2015-03-02 | 2015-03-04 |
+---+------------+----------+-------------+-------------+
从这张表中我想提取以下信息:
+------------+----------+
| article_id | sum |
+------------+----------+
| 1 | 6 |
| 2 | 3 |
+------------+----------+
Sum表示给定时间范围内堆叠/重叠预订商品数量的最大总和。在第一个表中,id为1的文章的最大值是预订1,3和5。
是否有任何MySQL解决方案可以从这样的表中获取此信息?
非常感谢!
编辑:日期交叉点至关重要。让我们说预订5从2015-03-17开始,article_id = 1的结果为5,因为预订3和5不再重叠。 sql应该自动考虑所有可能的重叠可能性。
答案 0 :(得分:0)
select sum(quantity) from ...
group by article_id
where
... select your date range ...
答案 1 :(得分:0)
这应该有效。 两组。首先得到可能的数量的明确列表&#39 ;;第二 - 总结他们
SELECT article_id, SUM(sub.quantity) FROM
(SELECT article_id, quantity FROM table GROUP BY article_id, quantity) as sub
GROUP BY article_id
答案 2 :(得分:0)
我的回答似乎很复杂,也许;但事实并非如此,如果人们接受使用日历表是处理日期范围相关问题的优秀MySQL习语。我仔细调整了Artful Software's calendar table文章中的日历表代码。 Artful Software's query techniques是在MySQL中处理复杂事物的绝佳资源。日历表为您提供了每个日期的行,这使得许多事情变得更加容易。
对于下面的全部内容,you can go to this sqlfiddle是一个可以玩代码的地方。加载需要一段时间。
首先,这是您的数据:
CREATE TABLE articles
(`id` int, `article_id` int, `quantity` int, `starts_at` datetime, `ends_at` datetime);
INSERT INTO articles
(`id`, `article_id`, `quantity`, `starts_at`, `ends_at`)
VALUES
(1, 1, 1, '2015-03-01 00:00:00', '2015-03-20 00:00:00'),
(2, 1, 2, '2015-03-02 00:00:00', '2015-03-03 00:00:00'),
(3, 1, 3, '2015-03-04 00:00:00', '2015-03-15 00:00:00'),
(4, 1, 2, '2015-03-16 00:00:00', '2015-03-22 00:00:00'),
(5, 1, 2, '2015-03-11 00:00:00', '2015-03-19 00:00:00'),
(6, 2, 2, '2015-03-06 00:00:00', '2015-03-22 00:00:00'),
(7, 2, 3, '2015-03-02 00:00:00', '2015-03-04 00:00:00');
接下来,这里是日历表的创建 - 我创建了比需要更多的日期行(回到年初,然后到明年开始)。理想情况下,您只需永久保留一个更大的日历表,涵盖一系列日期,可以处理您可能需要的任何事情。 以下所有内容看起来都很冗长复杂。但是如果你已经有一个日历表,那么下一部分就没有必要了。
CREATE TABLE calendar ( dt datetime primary key );
/* the views below will be joined and rejoined to themselves to
get the effect creating many rows. V ends up with 10 rows. */
CREATE OR REPLACE VIEW v3 as SELECT 1 n UNION ALL SELECT 1 UNION ALL SELECT 1;
CREATE OR REPLACE VIEW v as SELECT 1 n FROM v3 a, v3 b UNION ALL SELECT 1;
/* Going to limit the calendar table to first of year of min date
and first of year after max date */
SELECT @min := makedate(year(min(starts_at)),1) FROM articles;
SELECT @max := makedate(year(min(ends_at))+1,1) FROM articles;
SET @inc = -1;
/* below we work with @min date + @inc days successively, with @inc:=@inc+1
acting like ++variable, so we start with minus 1.
We insert as many individual date rows as we want by self-joining v,
and using some kind of limit via WHERE to keep the calendar table small
for our example. For n occurrences of v below, you get a max
of 10^n rows in the calendar table. We are using v as row-creation
engine. */
INSERT INTO calendar
SELECT @min + interval @inc:=@inc+1 day as dt
FROM v a, v b, v c, v d # , v e , v f
WHERE @inc < datediff(@max,@min);
现在我们已经准备好找到堆叠了。假设上述(我知道很大的假设),这变得相当容易。为了便于阅读,我将通过几个视图来实现。
/* now create a view that will let us easily view the articles
related to indvidual dates when we query.
Not necessary, just makes things easier to read. */
CREATE OR REPLACE VIEW articles_to_dates as
SELECT c.dt, article_id
FROM articles a
INNER JOIN calendar c on c.dt between (SELECT min(starts_at) FROM articles) and (SELECT max(ends_at) FROM articles)
GROUP BY article_id, c.dt;
--SELECT * FROM articles_to_dates --This query would show the view's result
/* next view is the total amount of articles booked per individual date */
CREATE OR REPLACE VIEW booked_quantities_per_day AS
SELECT a2d.dt,a2d.article_id, SUM(a.quantity) as booked_quantity
FROM articles_to_dates a2d
INNER JOIN articles a on a2d.dt between a.starts_at and a.ends_at and a.article_id = a2d.article_id
GROUP BY a2d.dt, a2d.article_id
ORDER by a2d.article_id, a2d.dt
--SELECT * from booked_quantities_per_day --this query would show the view's result
最后,这是理想的结果:
SELECT article_id, max(booked_quantity) max_stacked
FROM booked_quantities_per_day
GROUP BY article_id;
结果:
article_id max_stacked
1 6
2 3