我需要租用汽车价格计算。汽车价格因季节而异。
我有一个像这样的season_dates表
id slug start end
1 low 2011-01-01 00:00:00 2011-04-30 00:00:00
2 mid 2011-05-01 00:00:00 2011-06-30 00:00:00
3 high 2011-07-01 00:00:00 2011-08-31 00:00:00
4 mid 2011-09-01 00:00:00 2011-10-31 00:00:00
5 low 2011-11-01 00:00:00 2011-12-31 00:00:00
用户选择日期,例如:
start_day 08/20 end_day 08/25
我的查询:
SELECT * from arac_donemler
where DATE_FORMAT(start, '%m/%d') <= '08/20'
and DATE_FORMAT(end, '%m/%d') >= '08/25'
这给了我正确的旺季。
但我无法处理的是:如果用户选择2个季节之间的日期范围会怎么样?
例如,从8月20日到9月5日。
这次我必须发现日期范围属于哪个季节? 我必须计算每个季节的天数?
对于上面的例子, 旺季截至8月31日。所以31-20 =旺季11天,中期5天。
我如何提供这种分离?
我希望我能解释一下。
我尝试了很多东西,比如连接表,但是没能成功。
答案 0 :(得分:0)
我会让其他人以正确的方式在SQL中进行日期比较(你几乎肯定会杀死表格的索引),但是一开始,你可以准确地得到相关的季节 by
select * from arac_donemler
where end >= [arrival-date]
and start <= [departure-date]
然后,您应该在业务逻辑中而不是在数据库查询中完成剩余的处理(计算每个季节中的天数等等)。
答案 1 :(得分:0)
我会在表格中存储所有单日。 这是一个简单的例子。
create table dates (
id int not null auto_increment primary key,
pday date,
slug tinyint,
price int);
insert into dates (pday,slug,price)
values
('2011-01-01',1,10),
('2011-01-02',1,10),
('2011-01-03',2,20),
('2011-01-04',2,20),
('2011-01-05',2,20),
('2011-01-06',3,30),
('2011-01-07',3,30),
('2011-01-08',3,30);
select
concat(min(pday),'/',max(pday)) as period,
count(*) as days,
sum(price) as price_per_period
from dates
where pday between '2011-01-02' and '2011-01-07'
group by slug
+-----------------------+------+------------------+
| period | days | price_per_period |
+-----------------------+------+------------------+
| 2011-01-02/2011-01-02 | 1 | 10 |
| 2011-01-03/2011-01-05 | 3 | 60 |
| 2011-01-06/2011-01-07 | 2 | 60 |
+-----------------------+------+------------------+
3 rows in set (0.00 sec)
编辑。版本为grandtotal
select
case
when slug is null then 'Total' else concat(min(pday),'/',max(pday)) end as period,
count(*) as days,
sum(price) as price_per_period
from dates
where pday between '2011-01-02' and '2011-01-07'
group by slug
with rollup;
+-----------------------+------+------------------+
| period | days | price_per_period |
+-----------------------+------+------------------+
| 2011-01-02/2011-01-02 | 1 | 10 |
| 2011-01-03/2011-01-05 | 3 | 60 |
| 2011-01-06/2011-01-07 | 2 | 60 |
| Total | 6 | 130 |
+-----------------------+------+------------------+
4 rows in set (0.00 sec)
修改。填充表
的存储过程delimiter $$
create procedure calendario(in anno int)
begin
declare i,ultimo int;
declare miadata date;
set i = 0;
select dayofyear(concat(anno,'-12-31')) into ultimo;
while i < ultimo do
select concat(anno,'-01-01') + interval i day into miadata;
insert into dates (pday) values (miadata);
set i = i + 1;
end while;
end $$
delimiter ;
call calendario(2011);
答案 2 :(得分:0)
如果你也有一张桌子出租(真正的版本需要很多其他细节):
CREATE TABLE Rental
(
start DATE NOT NULL,
end DATE NOT NULL
);
并用以下内容填充:
INSERT INTO rental VALUES('2011-08-20', '2011-09-05');
INSERT INTO rental VALUES('2011-08-20', '2011-08-25');
然后此查询产生合理的结果:
SELECT r.start AS r_start, r.end AS r_end,
s.start AS s_start, s.end AS s_end,
GREATEST(r.start, s.start) AS p_start,
LEAST(r.end, s.end) AS p_end,
DATEDIFF(LEAST(r.end, s.end), GREATEST(r.start, s.start)) + 1 AS days,
s.id, s.slug
FROM rental AS r
JOIN season_dates AS s ON r.start <= s.end AND r.end >= s.start;
它产生:
r_start r_end s_start s_end p_start p_end days id slug
2011-08-20 2011-09-05 2011-07-01 2011-08-31 2011-08-20 2011-08-31 12 3 high
2011-08-20 2011-09-05 2011-09-01 2011-10-31 2011-09-01 2011-09-05 5 4 mid
2011-08-20 2011-08-25 2011-07-01 2011-08-31 2011-08-20 2011-08-25 6 3 high
请注意,我计算的是12天而不是11天;这是+1
表达式中的days
。这很棘手;你必须决定是否在租用的同一天归还汽车,这是一天的租车吗?如果第二天返回怎么办?也许时间很重要?但这涉及详细的业务规则而不是一般原则。也许持续时间是原始DATEDIFF()和1的较大者?另请注意,此架构中只有租赁开始和结束日期用于识别租赁;真实的架构在租赁表中会有某种租赁协议编号。
(忏悔:在MacOS X 10.7.1上使用IBM Informix 11.70.FC2进行模拟,但MySQL被记录为支持LEAST,GREATEST和DATEDIFF,我在Informix中模拟了这些。最显着的区别可能是Informix有DATE没有任何时间组件的类型,所以没有时间需要或显示。)
但[...]季节期间每年都相同。所以我想只比较几天和几个月。 2011年并不重要。明年将使用2011年。出现这个问题。例如淡季包括11月,12月,然后是1月,2月,3月,4月。如果用户选择日期范围01.05.2011到... 2011没有问题。我只是将月和日与DATE_FORMAT进行比较(结束,'%m /%d')。但如果他选择从12月到明年1月的范围,我将如何计算天数?
请注意,Season_Dates表中每年有5个条目不会使8英寸的磁盘破坏存储容量好几年,更不用说500 GiB的怪物磁盘。所以,到目前为止最简单的事情是在Season_Dates表中的5个新行中定义2012年的条目。这也允许您处理这样一个事实,即在12月,决定规则的权力将是不同的(12月20日至1月4日将是'中期' ,而不是“低”季节,例如)。