【问题标题】:How to omit results with date subquery on Laravel Query Builder如何在 Laravel Query Builder 上省略日期子查询的结果
【发布时间】:2020-09-20 18:49:05
【问题描述】:

我有一个 Laravel 应用程序,其中有一个模型表和一个他们被预订的日期表。只有输入了预订日期的模特才会在日期表中显示日期。日期逐日存储。所以架构看起来如下(简化):

tbl_models

 id   | name         | details         | gender    
 1    | joe bloggs   | over 60         | male           
 2    | jill bloggs  | pink nails      | female
 3    | a n other    | greying         | male

tbl_ModelCalendar

 id   | model_id  | date  
 1    | 1         | 2020-06-05 00:00:00         
 2    | 1         | 2020-06-06 00:00:00
 3    | 1         | 2020-06-07 00:00:00
 4    | 3         | 2020-09-15 00:00:00

我希望能够根据在特定日期范围内预订的型号来选择型号。因此,我们输入一个 NotBookedOutFrom 日期对象和一个 NotBookedOutTo 日期对象,并返回这两个日期之间可用的任何模型。我想我需要一个子查询吗?我不能 INNER JOIN 预订表,因为它会忽略任何没有任何预订日期的模型(即一直免费 - 理想!)而且我不能 LEFT JOIN 因为它会返回一个基于在我们省略的日期范围之外的另一个可用日期。

目前,我的控制器中的代码块如下所示:

$model->select('tbl_models.*');

$from =  DateTime::createFromFormat('Y-m-d', Carbon::parse($NotBookedOutFrom)->format('Y-m-d'));
$to =  DateTime::createFromFormat('Y-m-d', Carbon::parse($NotBookedOutTo)->format('Y-m-d'));
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($from, $interval, $to);

$model->leftJoin('tbl_ModelCalendar', 'tbl_ModelCalendar.model_id', '=', 'tbl_models.id');

$bookedDates = array();
      foreach ($period as $dt) {
          $thisDate = $dt->format("Y-m-d H:i:s");
          $bookedDates[] = $thisDate;

      }

$model->whereNotIn('tbl_ModelCalendar.date', [$bookedDates]);

无论如何,不​​用说,这不起作用而且是一团糟。我肯定在这里错过了一些非常简单的东西,但我已经转了几个小时了。

编辑:

在 Akina 的建议下,我尝试将他的答案翻译为 Query Builder,但仍不排除已预订的模型:

$model->leftJoin('tbl_ModelCalendar', 'tbl_models.id', '=', DB::raw("tbl_ModelCalendar.model_id AND tbl_ModelCalendar.date BETWEEN $from AND $to"));
$model->whereNull('tbl_ModelCalendar.model_id');

【问题讨论】:

  • 在 WhereNotIn 中应用 tbl_ModelCalendar.date 的条件后,您的 LeftJoin 将变为 InnerJoin。此条件必须是加入条件的一部分。
  • 谢谢@Akina。这是否意味着只删除上面的 leftJoin() ?这仍然无法解决这样一个事实,即如果用户选择 6 月 6 日至 7 日之间可用的模型,它将返回模型 1 的结果,因为它们在 6 月 5 日可用。
  • 这是否意味着只删除上面的 leftJoin()? 在实践中,我建议使用纯 SQL 创建正确的查询,然后将其转换为 Laravel 形式。

标签: mysql laravel


【解决方案1】:

在纯 SQL 中,您的查询看起来像

SELECT tbl_models.*
FROM tbl_models
LEFT JOIN tbl_ModelCalendar 
    ON tbl_models.id = tbl_ModelCalendar.model_id
   AND tbl_ModelCalendar.`date` BETWEEN @NotBookedOutFrom AND @NotBookedOutTo 
WHERE tbl_ModelCalendar.model_id IS NULL;

fiddle

【讨论】:

  • 谢谢@Akina。我不认为这是对的?这将显示在这些日期之间不可用的模型。如果该表中存在日期并且与提供的日期范围匹配,我需要排除模型。
  • @TheEgg 关注WHERE tbl_ModelCalendar.model_id IS NULL。这意味着我们选择不符合加入条件的记录。
  • 谢谢秋名。不幸的是,它仍然不起作用。将其翻译为: $model->where(function($query) use ($from,$to){ $query->whereBetween('date',array($from,$to)); }); $model->whereRaw('tbl_ModelCalendar.model_id IS NULL');但仍会退回已订满的模特。
  • @TheEgg Fiddle 添加了。输出符合条件 - 看。时间范围边界通过 UDV 传输。
  • 嗨,Akina。感谢您一直以来的帮助。我已经更新了我的问题,尝试将您的 SQL 转换为查询生成器,但不幸的是,它仍然返回已预订的模型。
猜你喜欢
  • 2019-10-31
  • 2015-02-07
  • 2020-08-23
  • 1970-01-01
  • 2021-05-22
  • 1970-01-01
  • 2015-10-02
  • 2021-08-27
  • 2021-08-19
相关资源
最近更新 更多