【问题标题】:How to get results from the query if the selected date is between two dates?如果所选日期在两个日期之间,如何从查询中获取结果?
【发布时间】:2015-01-08 21:22:07
【问题描述】:

我正在尝试获取以下查询的结果:返回在所选日期可用的用户。用户选择了他们何时不可用,并将其存储在具有开始日期时间和结束日期时间的“可用性”表中。 这是我一直在尝试但没有成功的方法...我不断让错误的用户返回,如果他们设置了多个不可用时间段,它也会返回。

尝试#1

User::whereHas('availabilities', function($q)use($selected_date_time)
{
    $q->where('unavailable_start_date', '>', $selected_date_time)
    ->where('unavailable_end_date', '>', $selected_date_time);
})->orWhereHas('availabilities', function($q)use($selected_date_time)
{
    $q->where('unavailable_start_date', '<', $selected_date_time)
    ->where('unavailable_end_date', '<', $selected_date_time);
})->with('availabilities')->get();

尝试#2

User::whereHas('availabilities', function($q)use($selected_date_time)->whereHas('availabilities', function($q)use($selected_date_time)
{
    $q->whereRaw('? NOT BETWEEN `unavailable_start_date` AND `unavailable_end_date`', [$selected_date_time]);
})->get();

这是在 try #1 案例中执行的 mysql 查询:

 select * from `users` where `is_user` = ? and (select count(*) from `availabilities` where `availabilities`.`user_id` = `users`.`id` and `unavailable_start_date` > ? and `unavailable_end_date` > ?) >= 1 or (select count(*) from `availabilities` where `availabilities`.`user_id` = `users`.`id` and `unavailable_start_date` < ? and `unavailable_end_date` < ?) >= 1

还有日期转储:

selected string(19) "2014-11-13 11:00:00"

unavailableStart string(19) "2014-11-12 11:30:00"

unavailableEnd string(19) "2014-11-18 11:00:00"

知道出了什么问题或如何解决这个问题?

编辑完整查询

$photographers_available =  Photographer::where('is_photographer', '=', '1')
                            ->whereHas('studioAddress', function($q)use($city_id)
                                                                   {
                                                                        $q->where('city_id', '=', $city_id);
                                                                   })
                            ->orWhereHas('user', function($q)use($city_id)  // TK could reduce to 'user.address' I think
                                                                     { 
                                                                        $q->whereHas('address', function($q)use($city_id) 
                                                                                     {
                                                                                        $q->where('city_id', '=', $city_id);
                                                                                     });
                                                                     })
                           ->whereHas('stypesPhotographer', function($q)use($stype)
                                                                   {
                                                                        $q->where('shooting_type_id', '=', $stype);
                                                                   })
                            ->where(function ($q) use ($selected_date_time) {
                            $q->whereHas('availabilities', function($q)use($selected_date_time)
                            {
                                $q->where('unavailable_start_date', '>', $selected_date_time)
                                ->where('unavailable_end_date', '>', $selected_date_time);
                            })->orWhereHas('availabilities', function($q)use($selected_date_time)
                            {
                                $q->where('unavailable_start_date', '<', $selected_date_time)
                                ->where('unavailable_end_date', '<', $selected_date_time);
                            });
                            })
                            ->with('availabilities')
                            ->get();

经过思考,orWhereHas 会不会是它出错的原因?

谢谢!

【问题讨论】:

    标签: php mysql database laravel eloquent


    【解决方案1】:

    试试这个对我很有效...

    如果使用 Eloquent ORM,请使用:

     User::Where(function($query)  use ($selected_date_time)
    {
            $query->where('unavailable_start_date','>',$selected_date_time);    
            $query->where('unavailable_end_date','>',$selected_date_time);  
    })
    ->orWhere(function($query)
    {
            $query->where('unavailable_start_date','<',$selected_date_time);    
            $query->where('unavailable_end_date','<',$selected_date_time);  
    })
    

    上面是这样的(在我的表中它会导致下面的查询)

    select * from `equipments` where (`created_at` > '2014-10-29' and `updated_at` > '2014-10-29') or (`created_at` < '2014-10-29' and `updated_at` < '2014-10-29')
    

    如果不工作请评论...

    【讨论】:

    • 它不适合我,我需要加载关系“可用性”。
    【解决方案2】:
    User::whereHas('availabilities', function ($q) use ($dt) {
        $q->where('unavailable_start_date', '<=', $dt)
          ->where('unavailable_end_date', '>', $dt);
    }, '=', 0)->get();
    

    所以我们在某种程度上扭转了这种情况。我们在 whereHas 中设置查询以查找此范围内的可用性、不可用性。所以我们正在查询所有不可用的记录(以某种方式)。然后,我们仅通过使用 whereHas ('=', 0) 的其他参数来抓取不符合此条件的关系的用户。

    因此,在此时间范围内具有此关系的任何用户都不会返回,无论他们有多少可用性记录。如果其中任何一个符合条件,他们将无法通过过滤器。

    【讨论】:

    • 太疯狂了,第二个用户总是出现!不是第一个想到的!这是当我手动测试出现的用户时,我只是通过测试日期 > 或
    • available_start_date 列是什么格式,您使用的 $dt 是什么格式?
    • 两者格式相同:string(19) "2014-11-13 11:00:00" 当相互比较时,我得到了很好的答案 -> 看到我的问题已编辑
    • 对于阅读的人,请参阅下面的@jarek 的 cmets。需要嵌套 orWhere ,然后使用此解决方案完美运行!
    • 我需要更新这个答案吗,这变得有点令人困惑:)。
    【解决方案3】:

    编辑 tldr;请记住将嵌套的where 用于orWhatever mehtods。除此之外,@lagbox 为您最初发布的问题提供了正确答案。这是完整的解决方案:

    $photographers_available =  Photographer::where('is_photographer', '=', '1')
    ->where(function ($q) use($city_id){
        $q->whereHas('studioAddress', function($q)use($city_id) {
            $q->where('city_id', '=', $city_id);
        })
        ->orWhereHas('user', function($q)use($city_id) {
            $q->whereHas('address', function($q)use($city_id) {
                $q->where('city_id', '=', $city_id);
            });
        });
    })
    ->whereHas('stypesPhotographer', function($q)use($stype) {
        $q->where('shooting_type_id', '=', $stype);
    })
    ->where(function ($q) use ($selected_date_time) {
    $q->whereHas('availabilities', function($q)use($selected_date_time) {
        $q->where('unavailable_start_date', '>', $selected_date_time)
        ->where('unavailable_end_date', '>', $selected_date_time);
    })->orWhereHas('availabilities', function($q)use($selected_date_time) {
        $q->where('unavailable_start_date', '<', $selected_date_time)
        ->where('unavailable_end_date', '<', $selected_date_time);
    });
    })
    ->with('availabilities')
    ->get();
    

    假设您的 where 子句适合您的情况,这就是您所需要的:

    User::where(function ($q) use ($selected_date_time) {
        $q->whereHas('availabilities', function($q)use($selected_date_time)
        {
            $q->where('unavailable_start_date', '>', $selected_date_time)
            ->where('unavailable_end_date', '>', $selected_date_time);
        })->orWhereHas('availabilities', function($q)use($selected_date_time)
        {
            $q->where('unavailable_start_date', '<', $selected_date_time)
            ->where('unavailable_end_date', '<', $selected_date_time);
        });
    })->with('availabilities')->get();
    

    因为,正如我们在这里看到的:

    select * from `users` 
      where `is_user` = ? 
      and (...) >= 1 
      // culprit:
      or (...) >= 1
    

    由于(可能)全局范围,您需要嵌套 orWhere

    【讨论】:

    • 该死的返回错误的用户...这不容易!你的第一个 where 子句没有条件?
    • 我没有详细介绍你的整个故事,所以我不知道这意味着什么,但这部分显然是错误的(x AND y OR z 而不是x AND (y OR z))。是的,where 没有条件,因为它用于嵌套其他wheres。因此,总结一下您的问题 - 您有 unavailabilities 表(暂时忘记名称,我的意思是它的用途)并且您想获取给定日期可用的用户,对吗?
    • 正确,我的表可用性有一个用户的外键,并且有用户不可用的开始和结束日期。
    • 好的,刚刚意识到前面的查询可能有冲突。请耐心等待一分钟,我将把整个查询放在问题中。 @jarek 现在在问题中进行完整查询,如您所见,我在做 3 Where 之前出于不同的原因,但到目前为止它返回了正确的东西
    • 好吧,如果是这样,那么@lagbox 已经为您提供了正确的解决方案。除非你最后的意思是别的......
    猜你喜欢
    • 2021-10-04
    • 2016-05-22
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多