Php MySQL:如何从一个数组中检索n(数量)个数据?
我有一张留言表Php MySQL:如何从一个数组中检索n(数量)个数据?,php,mysql,laravel,laravel-4,eloquent,Php,Mysql,Laravel,Laravel 4,Eloquent,我有一张留言表 +----+---------+----------+ | id | conv_id | body | +----+---------+----------+ | 1 | 1 | haha | | 2 | 1 | blabl| | ...| ... | ... | | 25| 2 | hehe | +----+---------+----------+ …=conv_id为2、1、3或n
+----+---------+----------+
| id | conv_id | body |
+----+---------+----------+
| 1 | 1 | haha |
| 2 | 1 | blabl|
| ...| ... | ... |
| 25| 2 | hehe |
+----+---------+----------+
…=conv_id为2、1、3或n的其余消息
假设我有conv_id=array2,1,我想在与conv_id中的一个id数组匹配后获得10条消息,所以我这样做了
上面的sql在匹配了两个conv_ID并获得了所有组合消息之后,给了我10条消息。然而,这不是我想要的。相反,我希望每个conv_id匹配10条消息
如何在每个匹配的conv_id中获得10条消息?请不要用PHP循环。谢谢大家!
注意:数组conv_id可以很容易地扩展,以包括许多其他彼此唯一的值,而不仅仅是2s或1s
另外,Laravel雄辩的回答可获得额外积分!详情如下:
两种模式,对话和由对话链接的消息,有许多消息和属于对话的消息。
我上面的sql是从Messages::with'User'->其中'conv_id',$conv_id->orderBy'created_at','desc'->take10;
我认为Jared是对的,但如果您可以在表中添加另一列,则解决方案会更有效。添加一列,指示每个conv_id最早的消息数为1,最晚的消息数为会话的消息数。之后,您可以通过使用HAVING子句扫描两次表来实现您的目标
另一种可能性。使用group-concat-substring索引技巧获取最后一个conv_id和它们的第十个messageid,并重新连接消息表
SELECT `messages`.*
FROM (
SELECT
conv_id,
substring_index(
substring_index(
group_concat(`messages`.id),
',',
10
),
',',
-1
) AS lastMessageId
FROM `messages`
WHERE `conv_id` in (2, 1)
GROUP BY `conv_id`
) AS msub
INNER JOIN `messages` ON `messages`.conv_id = msub.conv_id AND `messages`.id <= msub.lastMessageId
警告:这种方法可能是错误的。我正在尝试验证它,并将在得出结论后更新它
昨天,我刚从中的一个回答中学到了一些关于雄辩关系的新东西。我想我们也可以根据你的情况调整
你想做的事情,我认为:
具有多条消息的对话模型。
但每次对话我只想要10条最新消息。大家都来了。
在雄辩中,我可能会做以下几点:
Conversation::with('messages')->whereIn('conv_id', [1, 2])->get();
但是有两件事我注意到了你的问题
我想你没有另一张叫做对话的桌子。
上面的代码不限制每个对话的消息数量。
所以我决定这里应该有两个模型,一个叫做消息,另一个叫做对话。
这两个函数都调用同一个表,但我们将告诉Eloquent使用不同的列作为主键。
为了得到一个对话模型,我在newQuery函数中添加了一个distinct,并选择only conv_id out,因为这是关于对话的唯一信息
所以最后我有这个:
models/Message.php
models/Conversation.php
现在我可以做:
Conversation::with('messages')->whereIn('conv_id', [1, 2])->get();
这给了我一个conv_id为1和2的对话列表,以及每个会话的10条最新消息
这是我第一次做这样的事情。因此,我对代码进行了测试,它可以正常工作
更新:我的答案中的代码只执行从DB::getQueryLog检索到的这两个查询:
select distinct `conv_id` from `messages` where `conv_id` in (?, ?);
select * from `messages` where `messages`.`conv_id` in (?, ?) order by `id` desc limit 10;
“一种方法是两个查询之间的联合,一个处理1,另一个处理2。”贾雷德法里什说得对,他在等待你的答案。谢谢如果您使用的是SQL Server或Oracle,那么一个简单的分区就可以了。请注意,所有的解决方案都不是特别优雅的,它们都使用子查询、联合和/或变量,因为SQL中的LIMIT不是这样工作的。这看起来很可疑,就像它做了你想做的事情:每次随机化它以得到前十个以外的东西可能会更棘手。它是否总是返回相同的10也不确定,因此如果每个值的分组(可能是某种交叉联接)只能查询一次值,那么它的工作可能会更加一致。这个查询可以进一步简化吗?如果可能的话,我需要把它翻译成拉威尔的雄辩功能。谢谢对不起,我对拉威尔不熟悉。然而,这是困难还是不可能?我真的不知道在Laravel,我认为有时候弄脏你的手并执行原始SQL语句是可以的。是的,这是可能的。我只是想让代码看起来更优雅PI不知道和messages.id这是一个性能问题,但肯定有可能group_concat result与FIND_IN_SET.Btw一起使用,对话模型中的newQuery函数用于什么,如何使用?我没有看到你在代码中使用它。非常感谢。这是因为我假设你没有另一张叫做“对话”的桌子。newQuery是Laravel在开始为您构造查询时调用的。因此,我用selectdistinct conv_id附加它,以模拟对话表。如果您已经有一个对话表,只需完全删除我的newQuery部分。我很想看看原始查询是什么样子。@JaredFarrish用DB::getQueryLog的结果更新了我的答案!嗯,等等,这里有鱼腥味。我会带着最新消息回来的。
class Message extends Eloquent
{
protected $table = 'messages';
protected $primaryKey = 'id';
public $timestamps = false;
}
class Conversation extends Eloquent
{
protected $table = 'messages';
protected $primaryKey = 'conv_id';
public $timestamps = false;
public function newQuery($excludeDeleted = true)
{
return parent::newQuery()
->select('conv_id')
->distinct();
}
public function messages()
{
return $this->hasMany('Message', 'conv_id')
->orderBy('id', 'desc')
->take(10);
}
}
Conversation::with('messages')->whereIn('conv_id', [1, 2])->get();
select distinct `conv_id` from `messages` where `conv_id` in (?, ?);
select * from `messages` where `messages`.`conv_id` in (?, ?) order by `id` desc limit 10;