SQL连接以获取不在两个日期之间的记录

时间:2013-03-21 06:40:16

标签: mysql sql

我有以下表格:

discount table:
id
name
description
amount

discount_exception
id
from_date
to_date
discount_id (foreign key to discount table)

折扣例外表用于存储折扣应该对用户不可用的日期范围,因此不应显示。请注意,discount和discount_exception之间存在1:M的关系。换句话说,一个折扣可以有很多例外。

现在,我编写SQL的方法是获取所有折扣,然后在数组中循环它们,并查询discount_exception表以查明每个折扣是否在特定日期范围内。我宁愿修改SQL,以便一个数据库调用可以获取所有没有异常日期的折扣,这些折扣都在指定的日期范围内。

例如,如果用户购买的是在2013-5-1和2013-5-5之间运行的5天服务,我想检查折扣和discount_exception表,以找出哪些折扣包含异常2013-5-1和2013-5-5,然后仅显示在指定日期范围内没有例外的折扣。有没有办法用一个select语句执行此操作而不是分解SQL以针对每个折扣单独调用数据库?我很难理解SQL,特别是当折扣表和discount_exception表之间存在1:M的关系时。

我正在尝试这方面的事情:

SELECT * FROM discount INNER JOIN `discount_exceptions` ON discount.id = discount_exceptions.discount_id AND (discount_exceptions.date_from NOT BETWEEN '2013-5-1' AND '2013-5-5' OR discount_exception.date_to NOT BETWEEN '2013-5-1' AND '2013-5-5');

但是这个和其他变种似乎并没有起作用。知道我做错了吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

尝试一下这个怎么样:


select * 
   from discount
    where id not in (
        SELECT discount.id FROM discount
LEFT JOIN discount_exception ON discount.id = discount_exception.discount_id WHERE ('2013-5-1' between discount_exception.from_date and discount_exception.to_date ) OR ('2013-5-5' BETWEEN discount_exception.from_date and discount_exception.to_date ) OR (discount_exception.from_date between '2013-5-1' and '2013-5-5' ) OR (discount_exception.to_date between '2013-5-1' and '2013-5-5') ) )
可能最好添加distinct来获取不同的ID

答案 1 :(得分:0)

假设您想要查找适用于日期范围的所有折扣' 2013-03-01'到' 2013-03-03',首先找到适用于此范围的所有discount_exceptions

select e.*
from discount_exception e 
where e.from_date between '2013-03-02' and '2013-03-04'
or e.to_date between '2013-03-02' and '2013-03-04';

上面加上折扣表会给出适用于此日期范围的所有折扣例外的折扣ID。使用了不同的关键字,因此您无法获得重复的ID。我们称之为"例外集"

select distinct d.id
from discount_exception e 
join discount d on d.id = e.discount_id
where e.from_date between '2013-03-02' and '2013-03-04'
or e.to_date between '2013-03-02' and '2013-03-04';

然后,您可以执行折扣表的另一次加入,以查找适用于该日期范围的所有折扣(即上述例外设置中的ID不是折扣)

select *
from discount
where id not in (
  select distinct d.id
  from discount_exception e 
  join discount d on d.id = e.discount_id
  where e.from_date between '2013-03-02' and '2013-03-04'
  or e.to_date between '2013-03-02' and '2013-03-04'
);

答案 2 :(得分:0)

要检查交叉点,您只需要查看任一范围的起点是否在另一个范围内。然后形成一个子查询以排除那些匹配的子查询。

set @start_date = CAST('2013-05-01' as date);
set @stop_date = CAST('2013-05-05' as date);

select *
from discounts
where id not in (select discount_id
                 from discount_exception
                 where from_date between @start_date and @stop_date or
                       @start_date between from_date and to_date)