包含复杂查询 date_format 和之间

Contain complex query date_format and between

Code Update 2017/07/20

我按照@Arcesilas (here) 的建议使用了 MySQL 的 date_format

我通过合并 start_monthstart_day (ex 2017-01-16 = 0116)

升级了我的数据结构

[...]
->contain([
    'Bookings', 
    'Amenities',
    'Periodicities' =>  function ($q) use ($check_in, $check_out) {
        $start = $q->func()->date_format([
            'Periodicities.start' => $check_in->format('Ymd'),
            "'%m%d'" => 'literal'
        ]);

        $end = $q->func()->date_format([
            'Periodicities.end' => $check_out->format('Ymd'),
            "'%m%d'" => 'literal'
        ]);

       return $q
            ->where(function ($exp) use ($start) {
                $exp->between($start, 'Periodicities.start', 'Periodicities.end');
                return $exp;
            })
            ->orWhere(function ($exp) use ($end) {
                $exp->between($end, 'Periodicities.start', 'Periodicities.end');
                return $exp;
            });
    }

])
[...]

CakephpSQL日志

SELECT 
      PeriodicitiesRooms.id AS `Periodicities_CJoin__id`, 
      PeriodicitiesRooms.periodicity_id AS `Periodicities_CJoin__periodicity_id`, 
      PeriodicitiesRooms.room_id AS `Periodicities_CJoin__room_id`, 
      PeriodicitiesRooms.price AS `Periodicities_CJoin__price`, 
      Periodicities.id AS `Periodicities__id`, 
      Periodicities.name AS `Periodicities__name`, 
      Periodicities.start AS `Periodicities__start`, 
      Periodicities.end AS `Periodicities__end`, 
      Periodicities.price AS `Periodicities__price`, 
      Periodicities.modified AS `Periodicities__modified` 
    FROM 
      periodicities Periodicities 
      INNER JOIN periodicities_rooms PeriodicitiesRooms ON Periodicities.id = (
        PeriodicitiesRooms.periodicity_id
      ) 
    WHERE 
  (
    date_format('20170726', '%m%d') BETWEEN 'Periodicities.start' 
    AND 'Periodicities.end' 
    OR (
      PeriodicitiesRooms.room_id in ('1', '2', '3') 
      AND date_format('20170720', '%m%d') BETWEEN 'Periodicities.start' 
      AND 'Periodicities.end'
    )
  )

这不会再给我任何结果,因为 CakePHP 的 ORM 在 BETWEEN' Periodicities.start 'AND' Periodicities.end'

的末尾添加了撇号 (')

如果我在我的数据库中粘贴不带撇号 (') 的 CakePHP 查询,它会起作用。您是否知道要对我的查询末尾进行哪些更改,使其看起来像这样:BETWEEN 'Periodicities.start' AND 'Periodicities.end'BETWEEN Periodicities.start AND Periodicities.end

'SELECT * FROM periodicities WHERE date_format(' . $check_in->format('Ymd') . ', '%m%d') BETWEEN start AND end'

编辑

从您的评论中我看到您不想存储年份,因为年份不相关。

在这种情况下,您仍然可以将所有日期存储为特定年份,然后将该年份硬编码到查询中。我已将查询修改为使用 2000 年。

原版

我不清楚对话内容,但我会尝试回答您提出的问题。

您似乎想知道如何查找签入时间之间的 Periodicities 或结帐时间之间的 Periodicities。

您似乎还想知道存储日期的最佳方式。

  • 只需将日期存储为日期。没必要搞复杂
  • Between 也太复杂了。

这将完成您需要它做的事情而不会造成混淆。

[...]
->contain([
    'Bookings', 
    'Amenities',
    'Periodicities' =>  function ($q) use ($check_in, $check_out) {
        $q->where([
            'Periodicities.start >' => $check_in->format('2000-m-d'),
            'Periodicities.end <' => $check_in->format('2000-m-d')
        ]);
        $q->orWhere([
            'Periodicities.start >' => $check_out->format('2000-m-d'),
            'Periodicities.end <' => $check_out->format('2000-m-d')
        ]);

        return $q;
    }

])
[...]

我用这个查询解决了我的问题:

->contain([
    'Bookings', 
    'Amenities',
    'Periodicities' =>  function ($q) use ($check_in, $check_out) {
        $q->where(function ($exp) use ($check_in, $check_out) {
            $exp->gte('Periodicities.start', $check_in->format('md'));
            $exp->lte('Periodicities.end', $check_out->format('md'));
        });
        return $q;
    }
])

我一直以 monthday md 格式在数据库中存储日期 例如:0901 < 1030 9 月 1 日 < 10 月 30 日