Laravel OrderBy OneToMany Relation

时间:2017-10-31 07:11:12

标签: mysql laravel laravel-5 eloquent laravel-eloquent

我有2个表events_users: 其中存储有关参加某些活动的人的信息。许多人参加了许多活动,因此使用这个链接表。

+--------+---------+---------+
|  eid   | user_id | slot_no |
+--------+---------+---------+
| event1 | user1   |       0 |
| event1 | user2   |       1 |
| event2 | user3   |       0 |
+--------+---------+---------+

和events_user_score: 其中记录了事件中不同分数的人。在不同的事件中,可能有许多不同的分数类型,这就是为什么它在自己的表中,而不是在第一个表中的列

+--------+---------+------------+--------+
|  eid   | user_id | score_type | number |
+--------+---------+------------+--------+
| event1 | user1   |          1 |      4 |
| event1 | user1   |          2 |      3 |
| event2 | user3   |          1 |      6 |
| event1 | user1   |          2 |      5 | <- this row could not exist as
+--------+---------+------------+--------+    no duplicates possible with same eid, user_id & score_type

我希望能够根据第二个表中的数字对第一个表的选择进行排序。因此,我希望得到一个能够得到这样结果的联合工作。实际上将score_type转换为列,并将数字作为值。

+--------+---------+---------+---+---+
|  eid   | user_id | slot_no | 1 | 2 |
+--------+---------+---------+---+---+
| event1 |   user1 |       0 | 4 | 3 |
| event1 |   user2 |       1 |   |   |
| event2 |   user3 |       0 | 6 |   |
+--------+---------+---------+---+---+

到目前为止,我已尝试使用laravel的“hasMany”,但我无法使用该技术进行排序。所以我正在尝试尝试某种类型的左连接,但是真的很困惑,因为现在我没有得到任何分数:

$attendees = Events_user::whereIn("events_users.eid", $lastWeeksEvents->pluck('eid'))->where("slot_no",">=",0)
                            ->leftJoin('event_user_score', function ($join) {
                                $join->on('events_users.eid', '=', 'event_user_score.eid')
                                     ->where('events_users.uid', '=', 'event_user_score.uid');
                            })
                        ->get();

假设$lastWeeksEvents返回一个事件列表,其中eid与第一个表中的事件匹配。

编辑 - 即使它们是score_types 1 - 6.让我们坚持只是尝试获得类型1&amp;列为2列。如果这更容易吗?

2 个答案:

答案 0 :(得分:0)

要获得所需的结果,您可以在纯SQL中编写以下内容

select e1.*,
max(case when e2.score_type  =1 then e2.number else 0 end ) score_type1,
max(case when e2.score_type  =2 then e2.number else 0 end ) score_type2
from events_users e1
left join events_user_score e2 on e1.eid = e2.eid
                                  and e1.user_id = e2.user_id
group by e1.eid, e1.user_id,e1.slot_no

Demo

上述查询假设可以有两个score_types为1&amp; 2如果有更多上述查询对于这种类型的结果集是不可行的。

使用laravel的查询构建器可以写成。

$attendees = Events_user::from('events_users as e1')
                          ->select(DB::raw("e1.*,max(case when e2.score_type  =1 then e2.number else 0 end ) score_type1, max(case when e2.score_type  =2 then e2.number else 0 end ) score_type2"))
                          ->leftJoin('events_user_score as e2', function ($join) {
                                $join->on('e1.user_id', '=', 'e2.user_id');
                          })
                          ->groupBy('e1.eid')
                          ->groupBy('e1.user_id')
                          ->groupBy('e1.slot_no')
                          ->get();

上述解决方案通过匹配事件和用户将events_users表连接到您的第二个表events_user_score。聚合被调用以获得每个eid的唯一数据,user_id&amp; SLOT_NO

答案 1 :(得分:0)

您还可以使用子查询,如下所示:

纯SQL:

select u.eid, u.user_id, u.slot_no, 
(select number from events_user_score s where s.eid = u.eid and s.user_id = u.user_id and s.score_type = 1) as `1`,
(select number from events_user_score s where s.eid = u.eid and s.user_id = u.user_id and s.score_type = 2) as `2`

from events_users u

现在,在Laravel中使用它:

//Get all score types
$score_types = DB::table('events_user_score')
->select('score_type')
->groupBy('score_type')
->get();

$event_query = Events_user::from(DB::raw('events_users u'))
->select('eid', 'user_id', 'slot_no');

//Add score types as sub queries
foreach ($score_types as $score) {
    $event_query->addSelect(DB::raw('(select number from events_user_score s where s.eid = u.eid and s.user_id = u.user_id and s.score_type = ' . $score->score_type . ') as `' . $score->score_type . '`'));
}

//Example, to sort by score type 1
$data = $event_query->orderBy('1')->get();

请务必在代码顶部添加use DB;