【问题标题】:Getting N rows from far related table with conditions on close related table从远相关表中获取 N 行,并在密切相关表上获取条件
【发布时间】:2014-12-24 12:54:03
【问题描述】:

我有两张表,schedulesshifts,是一对多的关系。

schedule 具有 daymonthyear 字段以及 is_published 布尔值。 shift 有一个 user_idusers 建立一对一的关系。

现在,我想获得 user 中的下 5 个即将到来的 shifts。我必须从schedule 开始,因为该表中有日期。但是,更重要的是,我应该只检索属于已发布scheduleshifts

所以最大的问题是:

条目数应为 5 班。但是,从时间表开始,直到有 5 个班次属于用户,我才知道需要检索多少个时间表。

除了反复试验(即检索 x 下一个时间表并测试是否存在足够的班次。如果没有,检索下 n 个时间表直到配额得到满足),还有其他选择吗?

时间表架构

Schema::create('schedules', function(Blueprint $table) 
{
    $table->increments('id');
    $table->integer('user_id', false, true);
    $table->integer('client_id', false, true);
    $table->datetime('for');
    $table->enum('type', array('template', 'revision', 'common'));
    $table->string('name', 50)->default('Untitled Template');
    $table->boolean('is_published');
    $table->timestamp('published_at');
    $table->softDeletes();
    $table->timestamps();
});

这里,user_id 是创建者的 id,而不是日程所属的人。这用于跟踪将来如何创建计划。

Shift 架构

Schema::create('shifts', function(Blueprint $table) 
{
    $table->increments('id');
    $table->integer('schedule_id', false, true);
    $table->integer('user_id', false, true);
    $table->foreign('schedule_id')->references('id')->on('schedules')->onDelete('cascade');
    $table->softDeletes();
    $table->timestamps();
});

【问题讨论】:

  • 您是否在 Eloquent 模型中设置了关系?
  • 是的,关系是在 Eloquent 表中设置的。我的问题不是如何链接关系,而是如何获取一定数量的shifts,而是从schedule开始
  • 我明白了,只是在确保...但是我还有一个问题。您写道shiftsusers 具有一对一的关系。另一方面,您说您想要属于用户的即将到来的 5 个班次。你真的想要最后的结果中的时间表吗?
  • @lukasgeiter,感谢您的回复。不,我不想在最后安排日程。我想得到一个shifts 的数组。我希望用户能够看到他们即将到来的 5 班次;这些转变可能发生在下周,或者 5 次可能跨越下个月或下一年。我从schedule 开始的原因是因为schedule 中有日期条目。 shift 只是通过它的 id 引用 schedule
  • 1 为什么你对日期使用这种奇怪的模式而不是时间戳? 2 你期望的结果是什么?

标签: mysql laravel laravel-4 eloquent


【解决方案1】:

我会走简单的路:

// User model
public function shifts()
{
   return $this->hasManyThrough('Shift', 'Schedule');
}

然后:

$now = Carbon\Carbon::now();

$upcomingShifts = $user->shifts()
     ->where('schedules.is_published', 1)
     ->where('schedules.for', '>', $now)
     ->orderBy('schedules.for')
     ->take(5)
     ->get();

你可以让它更灵活一点,例如。这样:

// User model
public function getUpcomingShifts($limit = 5)
{
   $joinTable = $this->shifts()->getParent()->getTable(); // schedules

   $now = Carbon\Carbon::now();

   return $this->shifts()
     ->where($joinTable.'.is_published', 1)
     ->where($joinTable.'.for', '>', $now)
     ->orderBy($joinTable.'.for')
     ->take($limit)
     ->get();
}

// then
$user->getUpcomingShifts();

【讨论】:

    【解决方案2】:

    好吧,我不知道我是否成功,但试试看:

    User::find($userId)
        ->shifts()
        ->with('schedule')
        ->where('is_published', true)
        ->orderBy('year', 'asc')
        ->orderBy('month', 'asc')
        ->orderBy('day', 'asc')
        ->take(5)
        ->get();
    

    更新

    第二次尝试,希望成功

    User::find($userId)
        ->schedules()
        ->has('shifts')
        ->where('is_published', true)
        ->orderBy('year', 'asc')
        ->orderBy('month', 'asc')
        ->orderBy('day', 'asc')
        ->take(5)
        ->get();
    

    另一个更新

    第三次是魅力:)

    $results = User::find($userId)
        ->schedules()
        ->where('is_published', true)
        ->orderBy('year', 'asc')
        ->orderBy('month', 'asc')
        ->orderBy('day', 'asc')
        ->take(5)
        ->get();
    

    为此,您需要在用户模型中使用它:

    public function schedules(){
        return $this->belongsToMany('Schedule', 'shifts');
    }
    

    因此,要访问班次,您可以使用 pivot 属性:

    foreach($results as $result){
        echo $result->pivot
    }
    

    如果您想要完整的 Shift 模型而不仅仅是属性,请将其定义为 Pivot 模型:

    class Shift extends Illuminate\Database\Eloquent\Relations\Pivot
    

    在调度模型中:

    public function newPivot(Eloquent $parent, array $attributes, $table, $exists){
        if ($parent instanceof User) {
            return new Shift($parent, $attributes, $table, $exists);
        }
        return parent::newPivot($parent, $attributes, $table, $exists);
    }
    

    【讨论】:

    • 感谢您的帖子,但正如我所说,daymonthyearis_publishedschedules 表的一部分,而不是 shifts 表的一部分.这正是我的问题;我想take(5) 但是,该操作是在schedule 上调用的,而不是shift
    • @Kousha 好的,您可以为您的数据库和模型发布 sql 脚本吗?我想尝试一些事情
    • 当然,你想要我的架构?
    • 你的架构,甚至是一个完整的转储;)
    • 不,这不起作用。表schedules 中的user_id 反映了计划的创建者,就像您启动了计划一样。这是给定日期的雇员的时间表。每天都有多个班次或用户在工作。
    【解决方案3】:

    选择用户名,inner_q.* FROM 用户, (SELECT sch.year, sch.month, sch.day, sh.start_time FROM schedule sch INNER JOIN shift sh ON sch.id=sh.schedule_id WHERE sch.is_published=TRUE AND sh.user_id=user.id LIMIT 5) AS inner_q;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-23
      • 2018-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-15
      相关资源
      最近更新 更多