mysql查询 - 如何查找不在特定日期内的项目

时间:2013-07-16 13:15:56

标签: mysql sql cakephp

我似乎对SQL很无用,我正在试图弄清楚要使用的正确查询。

我有一个表项和一个表预订。一个项目可以有很多预订,并在两个日期之间进行预订。

我正在尝试创建一个搜索查询,该查询将返回两个用户输入日期之间没有预订的所有项目。

我现在的SQL看起来像:

SELECT `Item`.`id`, `Item`.`user_id`, `Item`.`name`, `Item`.`description`, `User`.`id`, `User`.`username`, `User`.`password`, `User`.`email` 
FROM `database`.`items` AS `Item` 
LEFT JOIN `database`.`reservations` AS `ReservationJoin` ON (`ReservationJoin`.`item_id` = `Item`.`id` AND `ReservationJoin`.`start` >= '2013-07-17' and `ReservationJoin`.`finnish` <= '2013-07-20') 
LEFT JOIN `database`.`users` AS `User` ON (`Item`.`user_id` = `User`.`id`) 
WHERE ((`Item`.`name` LIKE '%projector%') OR (`Item`.`description` LIKE '%projector%') 
AND `ReservationJoin`.`id` IS NULL 
LIMIT 10

我在cakephp 2.3中这样做,所以代码如下:

$this->paginate = array(
      "conditions" => array(
        "or" => array(
          "Item.name LIKE" => '%'.$projector.'%',
          "Item.description LIKE" => '%'.$projector.'%',
        ),
        "ReservationJoin.id" => null,
      ),
      "joins" => array(
        array(
          "table" => "reservations",
          "alias" => "ReservationJoin",
          "type" => "LEFT",
          "conditions" => array(
            "ReservationJoin.item_id = Item.id",
            "ReservationJoin.checkin >= '{$start}' and ReservationJoin.checkout <= '{$finnish}'",
          )
        )
      ),
      "limit"=>10
    );
    $data = $this->paginate('Item');

这不起作用,我认为这与加入有关,不能正确排除保留。但是我无法弄清楚正确的mysql是什么。一个善良的灵魂能告诉我应该使用什么吗?

感谢

3 个答案:

答案 0 :(得分:2)

如果某件事在两个日期之间有预订,则以下之一为真:

  1. 日期之间的开始日期
  2. 日期之间的结束日期
  3. 它具有较早日期之前的开始日期和第二日期之后的结束日期
  4. 以下查询在having子句中使用此逻辑。方法是在项目级别进行汇总,并确保上述三个条件成立:

    SELECT i.`id`, i.`user_id`, i.`name`, i.`description`
    FROM `database`.`items`i LEFT JOIN
         `database`.`reservations` r
         ON r.`item_id` = i.`id`
    WHERE ((i.`name` LIKE '%projector%') OR (i.`description` LIKE '%projector%')
    group by i.id
    having max(start between '2013-07-17' and '2013-07-20') = 0 and
           max(finish between '2013-07-17' and '2013-07-20') = 0 and
           max(start < '2013-07-17' and finished > '2013-07-20') = 0
    LIMIT 10;
    

    请注意,不会返回任何匹配项,因为当startned为NULL时,条件将被视为false。

答案 1 :(得分:0)

你可以试试这个。

SELECT `Item`.`id`, `Item`.`user_id`, `Item`.`name`, `Item`.`description`, `User`.`id`, `User`.`username`, `User`.`password`, `User`.`email` 
FROM `database`.`items` AS `Item` 
LEFT JOIN `database`.`reservations` AS `ReservationJoin` ON (`ReservationJoin`.`item_id` = `Item`.`id`) 
LEFT JOIN `database`.`users` AS `User` ON (`Item`.`user_id` = `User`.`id`) 
WHERE ((`Item`.`name` LIKE '%projector%') OR (`Item`.`description` LIKE '%projector%')) 
AND `ReservationJoin`.`start` >= '2013-07-17' 
AND `ReservationJoin`.`finnish` <= '2013-07-20'
AND `ReservationJoin`.`id` IS NULL 
LIMIT 10

即将日期子句移动到WHERE子句中,而不是处于JOIN CLAUSE中

答案 2 :(得分:0)

我认为在CakePHP中你可能更容易将所有条件放在WHERE子句中。 (这也可以通过一些OUTER JOIN来完成,但可能很难转录到CakePHP中)

    SELECT id, user_id, name, description
    FROM items
    WHERE ((name LIKE '%projector%') OR (description LIKE '%projector%'))
    AND NOT EXISTS(
    SELECT *
    FROM reservations
    WHERE items.id = reservations.item_id
    AND (
    '2013-07-17' BETWEEN start and finnish
    OR
    '2013-07-20' BETWEEN start and finnish
    OR 
    start BETWEEN '2013-07-17' AND '2013-07-20'));

或者,使用相同的逻辑可以清除WHERE子句

    SELECT id, user_id, name, description
    FROM items
    WHERE ((name LIKE '%projector%') OR (description LIKE '%projector%'))
    AND NOT EXISTS(
    SELECT *
    FROM reservations
    WHERE items.id = reservations.item_id
    AND NOT(
    '2013-07-17' > finnish
    OR
    '2013-07-20' < start
    ));