10 php mysql sql greatest-n-per-group
我正在尝试获取与我下载的每个帖子相关的最新1或2条评论,有点像instagram,因为它们显示每个帖子的最新3条评论,到目前为止我收到的帖子和喜欢的数量.
现在我需要做的就是弄清楚如何获得最新的评论,不太确定如何处理它,这就是为什么我希望有更多专业知识的人可以帮助我!
这是我目前的查询:
(SELECT
P.uuid,
P.caption,
P.imageHeight,
P.path,
P.date,
U.id,
U.fullname,
U.coverImage,
U.bio,
U.username,
U.profileImage,
coalesce(Activity.LikeCNT,0),
Activity.CurrentUserLiked
FROM USERS AS U
INNER JOIN Posts AS P
ON P.id = U.id
LEFT JOIN (SELECT COUNT(DISTINCT Activity.uuidPost) LikeCNT, Activity.uuidPost, Activity.id, sum(CASE WHEN Activity.id = $id then 1 else 0 end) as CurrentUserLiked
FROM Activity Activity
WHERE type = 'like'
GROUP BY Activity.uuidPost) Activity
ON Activity.uuidPost = P.uuid
AND Activity.id = U.id
WHERE U.id = $id)
UNION
(SELECT
P.uuid,
P.caption,
P.imageHeight,
P.path,
P.date,
U.id,
U.fullname,
U.coverImage,
U.bio,
U.username,
U.profileImage,
coalesce(Activity.LikeCNT,0),
Activity.CurrentUserLiked
FROM Activity AS A
INNER JOIN USERS AS U
ON A.IdOtherUser=U.id
INNER JOIN Posts AS P
ON P.id = U.id
LEFT JOIN (SELECT COUNT(DISTINCT Activity.uuidPost) LikeCNT, Activity.uuidPost, Activity.id, sum(CASE WHEN Activity.id = $id then 1 else 0 end) as CurrentUserLiked
FROM Activity Activity
WHERE type = 'like'
GROUP BY Activity.uuidPost) Activity
ON Activity.uuidPost = P.uuid
AND Activity.id = U.id
WHERE A.id = $id)
ORDER BY date DESC
LIMIT 0, 5
Run Code Online (Sandbox Code Playgroud)
基本上,评论存储在与喜欢的表相同的表中.
所以表是Activity,然后我有一个comment存储注释文本的列,然后"类型"等于"注释".
可能没有很好的解释,但我愿意尝试尽可能多的细节!
如果有人可以帮助它非常感谢!!
UPDATE
在/sf/users/71150481/给出的此查询中,我目前收到此错误:
操作'='的非法混合排序(utf8_general_ci,IMPLICIT)和(utf8_unicode_ci,IMPLICIT)
SELECT Posts.id,
Posts.uuid,
Posts.caption,
Posts.path,
Posts.date,
USERS.id,
USERS.username,
USERS.fullname,
USERS.profileImage,
coalesce(A.LikeCNT,0),
com.comment
FROM Posts
INNER JOIN USERS
ON Posts.id = 145
AND USERS.id = 145
LEFT JOIN (SELECT COUNT(A.uuidPost) LikeCNT, A.UUIDPost
FROM Activity A
WHERE type = 'like'
GROUP BY A.UUIDPOST) A
on A.UUIDPost=Posts.uuid
LEFT JOIN (SELECT comment, UUIDPOST, @row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number,@prev_value := UUIDPOST
FROM Activity
CROSS JOIN (SELECT @row_num := 1) x
CROSS JOIN (SELECT @prev_value := '') y
WHERE type = 'comment'
ORDER BY UUIDPOST, date DESC) Com
ON Com.UUIIDPOSt = Posts.UUID
AND row_number <= 2
ORDER BY date DESC
LIMIT 0, 5
Run Code Online (Sandbox Code Playgroud)
最新编辑
表结构:
帖子
----------------------------------------------------------
| id | int(11) | | not null |
| uuid | varchar(100) | utf8_unicode_ci | not null |
| imageLink | varchar(500) | utf8_unicode_ci | not null |
| date | timestamp | | not null |
----------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
USERS
-------------------------------------------------------------
| id | int(11) | | not null |
| username | varchar(100) | utf8_unicode_ci | not null |
| profileImage | varchar(500) | utf8_unicode_ci | not null |
| date | timestamp | | not null |
-------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
活动
----------------------------------------------------------
| id | int(11) | | not null |
| uuid | varchar(100) | utf8_unicode_ci | not null |
| uuidPost | varchar(100) | utf8_unicode_ci | not null |
| type | varchar(50) | utf8_unicode_ci | not null |
| commentText | varchar(500) | utf8_unicode_ci | not null |
| date | timestamp | | not null |
----------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
这些是一些例子,在"活动"表格中,"type"将始终等于"comment".
总结一切和渴望的结果:
当我查询用户帖子时,我希望能够进入"活动"表并获得他所拥有的每个帖子的最新 2条评论.也许没有评论所以很明显它会返回0,也许这篇文章可能有100条评论.但我只想获得最新/最近的2条评论.
一个例子可以看看Instagram是如何做到的.对于每个帖子,显示最近的评论1,2或3 ....
希望这可以帮助!
这个错误信息
操作“=”时非法混合排序规则 (utf8_general_ci,IMPLICIT) 和 (utf8_unicode_ci,IMPLICIT)
通常是由于列和表的定义造成的。它通常意味着等号的两侧有不同的排序规则。您需要做的是选择一个并将该决定包含在您的查询中。
这里的排序规则问题出现在 @prev_value 的 CROSS JOIN 中,它需要使用显式排序规则。
我还稍微将“row_number”逻辑更改为单个交叉连接,并将 if 逻辑移至选择列表的最末端。
下面显示了一些示例数据。需要示例数据来测试查询。任何试图用工作示例回答您的问题的人都需要数据。我把它放在这里的原因是双重的。
样本数据
请注意,表中缺少某些列,仅包含表详细信息中指定的列。
此示例数据针对单个帖子有 5 条评论(未记录点赞)
CREATE TABLE Posts
(
`id` int,
`uuid` varchar(7) collate utf8_unicode_ci,
`imageLink` varchar(9) collate utf8_unicode_ci,
`date` datetime
);
INSERT INTO Posts(`id`, `uuid`, `imageLink`, `date`)
VALUES
(145, 'abcdefg', 'blah blah', '2016-10-10 00:00:00') ;
CREATE TABLE USERS
(
`id` int,
`username` varchar(15) collate utf8_unicode_ci,
`profileImage` varchar(12) collate utf8_unicode_ci,
`date` datetime
) ;
INSERT INTO USERS(`id`, `username`, `profileImage`, `date`)
VALUES
(145, 'used_by_already', 'blah de blah', '2014-01-03 00:00:00') ;
CREATE TABLE Activity
(
`id` int,
`uuid` varchar(4) collate utf8_unicode_ci,
`uuidPost` varchar(7) collate utf8_unicode_ci,
`type` varchar(40) collate utf8_unicode_ci,
`commentText` varchar(11) collate utf8_unicode_ci, `date` datetime
) ;
INSERT INTO Activity (`id`, `uuid`, `uuidPost`, `type`, `commentText`, `date`)
VALUES
(345, 'a100', 'abcdefg', 'comment', 'lah lha ha', '2016-07-05 00:00:00'),
(456, 'a101', 'abcdefg', 'comment', 'lah lah lah', '2016-07-06 00:00:00'),
(567, 'a102', 'abcdefg', 'comment', 'lha lha ha', '2016-07-07 00:00:00'),
(678, 'a103', 'abcdefg', 'comment', 'ha lah lah', '2016-07-08 00:00:00'),
(789, 'a104', 'abcdefg', 'comment', 'hla lah lah', '2016-07-09 00:00:00') ;
Run Code Online (Sandbox Code Playgroud)
[SQL 标准行为:每个 Post 查询 2 行]
这是我最初的查询,有一些更正。我更改了选择列表的列顺序,以便当我呈现结果时您可以轻松地看到一些与评论相关的数据。请研究它们提供的结果,以便您了解查询的作用。由于我已经指出的原因,我正在使用的示例数据中不存在以 # 开头的列。
SELECT
Posts.id
, Posts.uuid
, rcom.uuidPost
, rcom.commentText
, rcom.`date` commentDate
#, Posts.caption
#, Posts.path
, Posts.`date`
, USERS.id
, USERS.username
#, USERS.fullname
, USERS.profileImage
, COALESCE(A.LikeCNT, 0) num_likes
FROM Posts
INNER JOIN USERS ON Posts.id = 145
AND USERS.id = 145
LEFT JOIN (
SELECT
COUNT(A.uuidPost) LikeCNT
, A.UUIDPost
FROM Activity A
WHERE type = 'like'
GROUP BY
A.UUIDPOST
) A ON A.UUIDPost = Posts.uuid
LEFT JOIN (
SELECT
@row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number
, commentText
, uuidPost
, `date`
, @prev_value := UUIDPOST
FROM Activity
CROSS JOIN ( SELECT @row_num := 1, @prev_value := '' collate utf8_unicode_ci ) xy
WHERE type = 'comment'
ORDER BY
uuidPost
, `date` DESC
) rcom ON rcom.uuidPost = Posts.UUID
AND rcom.row_number <= 2
ORDER BY
posts.`date` DESC
;
Run Code Online (Sandbox Code Playgroud)
结果:
| id | uuid | uuidPost | commentText | date | date | id | username | profileImage | num_likes |
|-----|---------|----------|-------------|------------------------|---------------------------|-----|-----------------|--------------|-----------|
| 145 | abcdefg | abcdefg | hla lah lah | July, 09 2016 00:00:00 | October, 10 2016 00:00:00 | 145 | used_by_already | blah de blah | 0 |
| 145 | abcdefg | abcdefg | ha lah lah | July, 08 2016 00:00:00 | October, 10 2016 00:00:00 | 145 | used_by_already | blah de blah | 0 |
Run Code Online (Sandbox Code Playgroud)
有 2 行 - 正如预期的那样。一行用于最新评论,另一行用于下一个最新评论。这是 SQL 的正常行为,在该答案下添加注释之前,问题的读者会认为这种正常行为是可以接受的。
该问题缺乏明确阐述的“预期结果”。
[选项 1:每个 Post 查询一行,最多 2 条评论,添加列]
在下面的评论中,我们发现您不希望每个帖子有 2 行,这将是一个简单的解决方案。嗯,这很简单,但是有一些选项,并且这些选项是由用户以需求的形式指定的。如果问题有“预期结果”,那么我们就会知道选择哪个选项。尽管如此,这是一种选择
SELECT
Posts.id
, Posts.uuid
, max(case when rcom.row_number = 1 then rcom.commentText end) Comment_one
, max(case when rcom.row_number = 2 then rcom.commentText end) Comment_two
#, Posts.caption
#, Posts.path
, Posts.`date`
, USERS.id
, USERS.username
#, USERS.fullname
, USERS.profileImage
, COALESCE(A.LikeCNT, 0) num_likes
FROM Posts
INNER JOIN USERS ON Posts.id = 145
AND USERS.id = 145
LEFT JOIN (
SELECT
COUNT(A.uuidPost) LikeCNT
, A.UUIDPost
FROM Activity A
WHERE type = 'like'
GROUP BY
A.UUIDPOST
) A ON A.UUIDPost = Posts.uuid
LEFT JOIN (
SELECT
@row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number
, commentText
, uuidPost
, `date`
, @prev_value := UUIDPOST
FROM Activity
CROSS JOIN ( SELECT @row_num := 1, @prev_value := '' collate utf8_unicode_ci ) xy
WHERE type = 'comment'
ORDER BY
uuidPost
, `date` DESC
) rcom ON rcom.uuidPost = Posts.UUID
AND rcom.row_number <= 2
GROUP BY
Posts.id
, Posts.uuid
#, Posts.caption
#, Posts.path
, Posts.`date`
, USERS.id
, USERS.username
#, USERS.fullname
, USERS.profileImage
, COALESCE(A.LikeCNT, 0)
ORDER BY
posts.`date` DESC
;
Run Code Online (Sandbox Code Playgroud)
| id | uuid | Comment_one | Comment_two | date | id | username | profileImage | num_likes |
|-----|---------|-------------|-------------|---------------------------|-----|-----------------|--------------|-----------|
| 145 | abcdefg | hla lah lah | ha lah lah | October, 10 2016 00:00:00 | 145 | used_by_already | blah de blah | 0 |
Run Code Online (Sandbox Code Playgroud)
** 选项 2,将最新评论连接到单个逗号分隔列表 **
SELECT
Posts.id
, Posts.uuid
, group_concat(rcom.commentText) Comments_two_concatenated
#, Posts.caption
#, Posts.path
, Posts.`date`
, USERS.id
, USERS.username
#, USERS.fullname
, USERS.profileImage
, COALESCE(A.LikeCNT, 0) num_likes
FROM Posts
INNER JOIN USERS ON Posts.id = 145
AND USERS.id = 145
LEFT JOIN (
SELECT
COUNT(A.uuidPost) LikeCNT
, A.UUIDPost
FROM Activity A
WHERE type = 'like'
GROUP BY
A.UUIDPOST
) A ON A.UUIDPost = Posts.uuid
LEFT JOIN (
SELECT
@row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number
, commentText
, uuidPost
, `date`
, @prev_value := UUIDPOST
FROM Activity
CROSS JOIN ( SELECT @row_num := 1, @prev_value := '' collate utf8_unicode_ci ) xy
WHERE type = 'comment'
ORDER BY
uuidPost
, `date` DESC
) rcom ON rcom.uuidPost = Posts.UUID
AND rcom.row_number <= 2
GROUP BY
Posts.id
, Posts.uuid
#, Posts.caption
#, Posts.path
, Posts.`date`
, USERS.id
, USERS.username
#, USERS.fullname
, USERS.profileImage
, COALESCE(A.LikeCNT, 0)
ORDER BY
posts.`date` DESC
Run Code Online (Sandbox Code Playgroud)
| id | uuid | Comments_two_concatenated | date | id | username | profileImage | num_likes |
|-----|---------|---------------------------|---------------------------|-----|-----------------|--------------|-----------|
| 145 | abcdefg | hla lah lah,ha lah lah | October, 10 2016 00:00:00 | 145 | used_by_already | blah de blah | 0 |
Run Code Online (Sandbox Code Playgroud)
** 概括 **
我提出了 3 个查询,每个查询仅显示 2 个最新评论,但每个查询都以不同的方式执行此操作。第一个查询(默认行为)将为每个帖子显示 2 行。选项 2 添加一列但删除第二行。选项 3 连接 2 个最新评论。
请注意:
我确实希望所提供的附加信息会有一些用处,并且现在您也知道 SQL 将数据呈现为多行是正常的。如果您不希望出现这种正常行为,请在问题中具体说明您真正想要的是什么。
后记。要包含另一个“follows”子查询,您可以使用与已有子查询类似的子查询。它可以添加在该子查询之前或之后。您还可以在 sqlfiddle中看到它的使用
LEFT JOIN (
SELECT
COUNT(*) FollowCNT
, IdOtherUser
FROM Activity
WHERE type = 'Follow'
GROUP BY
IdOtherUser
) F ON USERS.id = F.IdOtherUser
Run Code Online (Sandbox Code Playgroud)
虽然添加另一个子查询可能会满足您对更多信息的需求,但总体查询可能会随着数据的增长而变慢。一旦确定了真正需要的功能,就值得考虑这些表上需要哪些索引。(我相信建议您单独寻求该建议,如果确实这样做,请确保包括 1. 表的完整 DDL 和 2. 查询的解释计划。)
| 归档时间: |
|
| 查看次数: |
1102 次 |
| 最近记录: |