我想在Laravel模型中对JOIN和GROUP BY使用复杂的SELECT查询。
?我想在我的应用程序中创建一个消息程序。这是带有所有消息的表“消息”。现在,我要创建一个名为“对话框”的模型。请记住,这里没有表“对话框”,对话框是联接和分组的结果。
查询示例:
SELECT
cl.name AS client_name,
COUNT(m.id) AS messages_count,
MAX(m.created_at) AS last_message,
COUNT(m.id) > SUM(m.viewed_by_client) AS has_new_for_client,
COUNT(m.id) > SUM(m.viewed_by_user) AS has_new_for_user
FROM messages AS m
INNER JOIN clients AS c ON m.client_id = c.id
GROUP BY c.id
当然,我可以使用原始SQL查询。但是我想在以后使用雄辩的关系及其所有好处。例如:
$dialog->client->full_name
$dialog->client->order->ordered_items
我有一个想法,可以从查询中在数据库中创建一个VIEW,并将该视图用作模型中的伪表。但是在我看来,这不是理想的解决方案。
那么,当我没有模型实体的真实表时,如何在Eloquent中使用JOIN和GROUP BY?还是针对我的任务有一些不同的解决方案?
答案 0 :(得分:0)
创建对话框表,并将“ dialog_id”列放入消息表中。每个消息都有一个对话框和一个客户端。在每个模型中创建关系。因此,您可以根据需要访问模型上的属性。这样,此代码即可工作;
$dialog->client->full_name
$dialog->client->order->ordered_items
答案 1 :(得分:0)
您可以拥有没有Eloquent模型的数据库表,反之则没有。就是说,没有规则禁止每个表制作超过1个模型。不过,这不是真正的标准做法。
我尝试制作一个可以从另一个模型继承的模型,但是启动方法没有按预期工作,所以我删除了它。
我认为您可以在Client
模型中使用访问者从该查询中获取所有信息。由于您的查询没有where子句,因此作用域并不是真正必要的,但也可以这样做。
# App\Client
class Client extends Model
{
// Standard Eloquent relationship
public function messages()
{
return $this->hasMany(App\Message::class);
}
// Accessor $client->client_name
public function getClientNameAttribute()
{
return $this->name;
}
// Accessor $client->last_message
public function getLastMessageAttribute()
{
// Load relationship only if it hasn't been loaded yet
if(!$this->relationshipLoaded('messages'))
$this->load('messages');
// use max() method from collection to get the results
return $this->messages->max('created_at');
}
// Accessor $client->has_new_for_client
public function getHasNewForClientAttribute()
{
// Load relationship only if it hasn't been loaded yet
if(!$this->relationshipLoaded('messages'))
$this->load('messages');
return $this->messages->count() > $this->messages->sum('viewed_by_client');
}
// Accessor $client->has_new_for_user
public function getHasNewForUserAttribute()
{
// Load relationship only if it hasn't been loaded yet
if(!$this->relationshipLoaded('messages'))
$this->load('messages');
return $this->messages->count() > $this->messages->sum('viewed_by_user');
}
}
然后您可以动态访问所有属性
$dialog = Client::withCount('messages')->find($id);
$dialog->client_name;
$dialog->messages_count;
$dialog->has_new_for_client;
$dialog->has_new_for_user;
$dialog->last_message;
但是,如果您要将$dialog
转换为数组或json格式,除非您附加,否则访问器将丢失。同样,您可以隐藏不想显示的属性。
这可以在模型的全局范围内完成
protected $appends = ['client_name', 'has_new_for_client', 'has_new_for_user', 'last_message'];
protected $hidden = ['name'];
或本地查询
$dialog->setHidden(['name']);
$dialog->setAppends(['client_name', 'has_new_for_client', 'has_new_for_user', 'last_message'];
# App\Client
class Client extends Model
{
public function scopeDialog($query)
{
$query->select('name as client_name')
->withCount('messages') // the default name will be messages_count
->selectRaw('max(m.created_at) as last_message')
->selectRaw('count(m.id) > sum(m.viewed_by_client) as has_new_for_client')
->selectRaw('count(m.id) > sum(m.viewed_by_user) as has_new_for_user')
->join('messages as m', 'm.client_id', 'clients.id')
->groupBy('clients.id');
}
}
然后像调用任何范围Client :: dialog()-> ...
一样调用它$dialog = Client::with('messages')->find($id);
// client_name
$dialog->name
// messages_count
$dialog->messages->count()
// last_message
$dialog->messages->max('created_at')
// has_new_for_client
($dialog->messages->count('id') > $dialog->messages->count('viewed_by_client'))
// has_new_for_user
($dialog->messages->count('id') > $dialog->messages->count('viewed_by_user'))