MYSQL 查询 - 获取与 post 相关的最新评论
MYSQL Query - Get latest comment related to the post
我正在尝试获取与我下载的每个 post 相关的最新 1 或 2 条评论,有点像 instagram,因为它们显示每个 post 的最新 3 条评论,到目前为止我我得到 posts 和喜欢的计数。
现在我需要做的就是弄清楚如何获得最新的评论,不太确定如何处理它,这就是为什么我希望有更多专业知识的人能帮助我!
这是我当前的查询:
(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
基本上,评论和点赞存储在同一个 table 中。
所以table是Activity
,然后我有一个存储评论文本的列comment
,然后"type"等于"comment".
可能解释得不是很好,但我愿意尝试提供尽可能详细的信息!
如果有人能提供帮助,我们将不胜感激!!
更新
关于 https://whosebug.com/users/1016435/xqbert 给出的这个查询,我目前收到这个错误:
Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation '='
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
最新编辑
Table 结构:
帖子
----------------------------------------------------------
| 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 |
----------------------------------------------------------
用户
-------------------------------------------------------------
| 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 |
-------------------------------------------------------------
Activity
----------------------------------------------------------
| 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 |
----------------------------------------------------------
这些是一些示例,在 "Activity" table 这种情况下 "type" 将始终等于 "comment"。
总结一切并期望结果:
当我查询用户 posts 时,我希望能够进入 "Activity" table 并获得 latest 他每 post 就有 2 条评论。也许不会有如此明显的评论 return 0,也许会有 100 条评论 post。但我只想获取 latest/most 最近的 2 条评论。
例如 Instagram 是如何做到的。对于每个 post 显示最近的评论 1、2 或 3....
希望对您有所帮助!
我有点迷失在你的查询中,但如果你想一次下载多个 posts 的数据,在第一个查询中包含评论数据不是一个好主意,因为你会包含关于 post 和 posting 用户多次的所有数据。您应该 运行 另一个将 post 与评论联系起来的查询。类似于:
SELECT
A.UUIDPost,
C.username,
C.profileImage,
B.Comment,
B.[DateField]
FROM Posts A JOIN
Activities B ON A.uuid = B.UUIDPost JOIN
Users C ON B.[UserId] = C.id
并使用该数据显示您的评论,包括评论用户 ID、姓名、图片等。
如果每个 post 只获得 3 条评论,您可以查看此 post:
Select top 3 values from each group in a table with SQL
如果您确定评论 table 或此 post 中不会有重复的行:
How to select top 3 values from each group in a table with SQL which have duplicates
如果您对此不确定(尽管由于 table 中的 DateField,应该不可能)。
这种类型的评论已被 post 多次编辑,并且尝试获得 "latest-for-each" 似乎总是绊脚石,并且对大多数人来说都是加入/子查询的噩梦。
特别是对于 Web 界面,您最好将一列(或 2 或 3)附加到 table 是您的活动 "posts" table 的列,例如最新 1、最新 2、最新 3。
然后,通过插入您的评论 table,在您的 table 上设置一个插入触发器,以使用最新的 ID 更新主 post。然后,您始终在 table 上拥有该 ID,而没有任何子连接。现在,正如您所提到的,您可能希望拥有最后 2 个或 3 个 ID,然后添加 3 个示例列并让您的插入触发器插入 post 评论详细信息,对主要 post table 类似
update PrimaryPostTable
set Latest3 = Latest2,
Latest2 = Latest1,
Latest1 = NewDetailCommentID
where PostID = PostIDFromTheInsertedDetail
这必须在 MySQL 下正式化为适当的触发器,但应该很容易实现。您可以用最新的 1 填充列表,然后随着新的 post 的出现,它会自动将最新的滚动到它们的第 1、第 2、第 3 个位置。最后,您的查询可以简化为
Select
P.PostID,
P.TopicDescription,
PD1.WhateverDetail as LatestDetail1,
PD2.WhateverDetail as LatestDetail2,
PD3.WhateverDetail as LatestDetail3
from
Posts P
LEFT JOIN PostDetail PD1
on P.Latest1 = PD1.PostDetailID
LEFT JOIN PostDetail PD2
on P.Latest2 = PD2.PostDetailID
LEFT JOIN PostDetail PD3
on P.Latest3 = PD3.PostDetailID
where
whateverCondition
通常不需要反规范化数据。但是,在这种情况下,在 For-Each 类型的查询中获取这些 "latest" 条目是一个很好的简化程序。祝你好运。
这是 MySQL 中的完整示例,因此您可以看到 tables 和 sql 插入的结果以及通过触发器自动标记以更新主要 post table。然后查询 post table 您可以看到最近的如何自动滚动到第一、第二和第三位置。最后一个连接展示了如何从每个 "post activity"
中提取所有数据
CREATE TABLE Posts
( id int,
uuid varchar(7),
imageLink varchar(9),
`date` datetime,
ActivityID1 int null,
ActivityID2 int null,
ActivityID3 int null,
PRIMARY KEY (id)
);
CREATE TABLE Activity
( id int,
postid int,
`type` varchar(40) collate utf8_unicode_ci,
commentText varchar(20) collate utf8_unicode_ci,
`date` datetime,
PRIMARY KEY (id)
);
DELIMITER //
CREATE TRIGGER ActivityRecAdded
AFTER INSERT ON Activity FOR EACH ROW
BEGIN
Update Posts
set ActivityID3 = ActivityID2,
ActivityID2 = ActivityID1,
ActivityID1 = NEW.ID
where
ID = NEW.POSTID;
END; //
DELIMITER ;
INSERT INTO Posts
(id, uuid, imageLink, `date`)
VALUES
(123, 'test1', 'blah', '2016-10-26 00:00:00');
INSERT INTO Posts
(id, uuid, imageLink, `date`)
VALUES
(125, 'test2', 'blah 2', '2016-10-26 00:00:00');
INSERT INTO Activity
(id, postid, `type`, `commentText`, `date`)
VALUES
(789, 123, 'type1', 'any comment', '2016-10-26 00:00:00'),
(821, 125, 'type2', 'another comment', '2016-10-26 00:00:00'),
(824, 125, 'type3', 'third comment', '2016-10-27 00:00:00'),
(912, 123, 'typeAB', 'comment', '2016-10-27 00:00:00');
-- See the results after the insert and the triggers.
-- you will see that the post table has been updated with the
-- most recent
-- activity post ID=912 in position Posts.Activity1
-- activity post ID=789 in position Posts.Activity2
-- no value in position Posts.Activity3
select * from Posts;
-- NOW, insert two more records for post ID = 123.
-- you will see the shift of ActivityIDs adjusted
INSERT INTO Activity
(id, postid, `type`, `commentText`, `date`)
VALUES
(931, 123, 'type1', 'any comment', '2016-10-28 00:00:00'),
(948, 123, 'newest', 'blah', '2016-10-29 00:00:00');
-- See the results after the insert and the triggers.
-- you will see that the post table has been updated with the
-- most recent
-- activity post ID=948 in position Posts.Activity1
-- activity post ID=931 in position Posts.Activity2
-- activity post ID=912 in position Posts.Activity3
-- notice the FIRST activity post 789 is not there as
-- anything AFTER the 4th entry, it got pushed away.
select * from Posts;
-- Finally, query the data to get the most recent 3 items for each post.
select
p.id,
p.uuid,
p.imageLink,
p.`date`,
A1.id NewestActivityPostID,
A1.`type` NewestType,
A1.`date` NewestDate,
A2.id SecondActivityPostID,
A2.`type` SecondType,
A2.`date` SecondDate,
A3.id ThirdActivityPostID,
A3.`type` ThirdType,
A3.`date` ThirdDate
from
Posts p
left join Activity A1
on p.ActivityID1 = A1.ID
left join Activity A2
on p.ActivityID2 = A2.ID
left join Activity A3
on p.ActivityID3 = A3.ID;
您可以创建一个测试数据库,以免损坏您的数据库以查看此示例。
未测试:我建议将 SQL fiddle 与一些示例数据和显示问题的现有 table 结构放在一起;这样我们就可以处理响应并确保您的模式的功能。
所以我们用一个变量来模拟一个window函数(比如row_number)
在本例中为@Row_num 和@prev_Value。 @Row_number 跟踪每个 post 的当前行(因为单个 post 可能有很多评论)然后当一个新的 post ID(UUIDPOST?)遇到 row_num 变量重置为 1。当当前记录 UUIDPOST 匹配变量 @prev_Value 时,我们只需将行增加 1。
此技术允许我们根据日期或 activity ID 降序分配行号。由于每个交叉联接仅产生 1 条记录,因此我们不会导致出现重复记录。但是,由于我们随后受到 row_number < = 2 的限制,我们只能在新添加的左连接中获得两个最新的评论。
这假设 post 与用户的关系是多对一的,这意味着 post 只能有 1 个用户。
类似这样的事情:虽然我不确定最后的左连接,但我需要更好地理解 activity table 的结构,因此对原始问题发表评论。
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
--This join simulates row_Number() over (partition by PostID, order by activityID desc) (Nice article [here](http://preilly.me/2011/11/11/mysql-row_number/) several other examples exist on SO already.
--Meaning.... Generate a row number for each activity from 1-X restarting at 1 for each new post but start numbering at the newest activityID)
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, --Some date or ID desc) Com
on Com.UUIIDPOSt = Posts.UUID
and row_number < = 2
-- Now since we have a row_number restarting at 1 for each new post, simply return only the 1st two rows.
ORDER BY date DESC
LIMIT 0, 5
我们必须将 and row_number < = 2 放在联接本身上。如果它被放在 where 子句中,你将失去那些 posts 而没有任何我认为你仍然想要的评论。
此外,我们可能应该查看 "comment" 字段以确保它不为空或为空,但首先要确保它有效。
这条错误信息
Illegal mix of collations (utf8_general_ci,IMPLICIT) and
(utf8_unicode_ci,IMPLICIT) for operation '='
通常是由于您的列和 table 的定义。它通常意味着在等号的两边有不同的归类。您需要做的是选择一个并将该决定包含在您的查询中。
此处的排序规则问题出现在@prev_value 的 CROSS JOIN 中,需要使用显式排序规则。
我还稍微将“row_number”逻辑更改为单个交叉连接,并将 if 逻辑移至 select 列表的极端。
下面显示了一些示例数据。需要样本数据来测试查询。任何试图用工作示例回答您的问题的人都需要数据。我把它包括在这里的原因是双重的。
- 以便您了解我呈现的任何结果
- 以便将来您提出另一个 SQL 相关问题时,您会了解提供数据的重要性。您这样做不仅对我们更方便。如果提问者提供了示例数据,那么提问者就已经理解了它——这不会是一些花时间帮助的陌生人的发明。
示例数据
请注意 table 中缺少一些列,仅包含 table 详细信息中指定的列。
此示例数据有 5 条针对单个 post 的评论(没有记录喜欢)
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') ;
[SQL 标准行为:每个 Post 查询 2 行]
这是我最初的查询,有一些更正。我更改了 select 列表的列顺序,以便在我呈现结果时您可以轻松地看到一些与评论相关的数据。请研究它们提供的结果,以便您了解查询将执行的操作。由于我已经指出的原因,我正在使用的样本数据中不存在以 # 开头的列。
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
;
See a working demonstration of this query at SQLFiddle
| 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 |
有 2 行 - 正如预期的那样。一行是最近的评论,另一行是下一个最近的评论。这是 SQL 的正常行为,直到在此答案下添加评论之前,问题的读者会假设此正常行为是 acceptable.
该问题缺乏明确表达的“预期结果”。
[选项 1:每个 Post 查询一行,最多 2 条评论,添加列]
在下面的评论中表明您不希望每个 post 有 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
;
See the second query working at SQLFiddle
| 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 |
** 选项 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
See this third query working at SQLFiddle
| 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 |
** 摘要 **
我提出了 3 个查询,每个查询只显示 2 个最近的评论,但每个查询都以不同的方式进行。第一个查询(默认行为)将为每个 post 显示 2 行。选项 2 添加一列但删除第二行。选项 3 连接了 2 个最近的评论。
请注意:
- 该问题缺少 table 涵盖所有列的定义
- 该问题缺少任何示例数据,这让您更难理解此处呈现的任何结果,也让我们更难准备解决方案
- 这个问题也缺乏明确的“预期结果”(想要的输出),这导致回答更加复杂
我希望额外提供的信息会有一些用处,并且现在您也知道 SQL 将数据显示为多行是正常的。如果您不希望出现这种正常行为,请具体说明您在问题中真正想要的是什么。
Post脚本。要包含“follows”的另一个子查询,您可以使用与您已有的子查询类似的子查询。它可以添加在该子查询之前或之后。您可能还会在 sqlfiddle here
看到它在使用
LEFT JOIN (
SELECT
COUNT(*) FollowCNT
, IdOtherUser
FROM Activity
WHERE type = 'Follow'
GROUP BY
IdOtherUser
) F ON USERS.id = F.IdOtherUser
虽然添加另一个子查询可能会解决您对更多信息的需求,但整体查询可能会随着数据的增长而变慢。一旦您确定了您真正需要的功能,可能值得考虑在这些 table 上需要哪些索引。 (我相信您会被建议单独寻求该建议,如果您确实包括 1. table 的完整 DDL 和 2. 查询的解释计划。)
这可能会消除排序规则的非法混合...建立连接后,执行此查询:
SET NAMES utf8 COLLATE utf8_unicode_ci;
关于 'latest 2' 的问题,请使用 mysql 命令行工具和 运行 SHOW CREATE TABLE Posts
并提供输出。 (其他相关表也是如此。)Phpmyadmin(和其他 UI)有一种无需进入命令行即可执行查询的方法。
您可以通过使用子查询进行非常简单的查询。首先,我在 where 子句中指定用户并加入 posts 因为这对我来说似乎更合乎逻辑。然后我得到了带有子查询的 post 的所有点赞。
现在我们不再分组和限制组大小,而是通过限制我们当前正在查看的日期之后的日期计数来仅加入我们想要加入的值。
INNER JOIN Activity 如果您只想显示 post 至少有一条评论。
SELECT
u.id,
u.username,
u.fullname,
u.profileImage,
p.uuid,
p.caption,
p.path,
p.date,
(SELECT COUNT(*) FROM Activity v WHERE v.uuidPost = p.uuidPost AND v.type = 'like') likes,
a.commentText,
a.date
FROM
Users u INNER JOIN
Posts p ON p.id = u.id LEFT JOIN
Activity a ON a.uuid = p.uuid AND a.type = 'comment' AND 2 > (
SELECT COUNT(*) FROM Activity v
WHERE v.uuid = p.uuid AND v.type = 'comment' AND v.date > a.date)
WHERE
u.id = 145
也就是说重新设计可能是最好的,也是性能方面的(Activity 很快就会包含很多条目,并且它们总是必须针对所需的类型进行过滤)。用户 table 可以使用 id 自动递增并作为主键。对于 posts 我还会添加一个自动递增的 id 作为主键和 user_id 作为外键(您还可以决定删除时要做什么,例如级联所有他的 post s 也会被自动删除)。
对于评论和点赞,你可以用user_id和post_id这两个外键创建分隔的table(简单的例子,像这样你只能点赞posts 而不是别的,但是如果没有很多不同类型的喜欢,那么创建一个 post_likes 和其他一些 ..._likes tables 仍然很好,你必须考虑如何通常会查询数据,如果这些点赞大部分是相互独立的,那可能是一个不错的选择。
我正在尝试获取与我下载的每个 post 相关的最新 1 或 2 条评论,有点像 instagram,因为它们显示每个 post 的最新 3 条评论,到目前为止我我得到 posts 和喜欢的计数。
现在我需要做的就是弄清楚如何获得最新的评论,不太确定如何处理它,这就是为什么我希望有更多专业知识的人能帮助我!
这是我当前的查询:
(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
基本上,评论和点赞存储在同一个 table 中。
所以table是Activity
,然后我有一个存储评论文本的列comment
,然后"type"等于"comment".
可能解释得不是很好,但我愿意尝试提供尽可能详细的信息!
如果有人能提供帮助,我们将不胜感激!!
更新
关于 https://whosebug.com/users/1016435/xqbert 给出的这个查询,我目前收到这个错误:
Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation '='
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
最新编辑
Table 结构:
帖子
----------------------------------------------------------
| 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 |
----------------------------------------------------------
用户
-------------------------------------------------------------
| 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 |
-------------------------------------------------------------
Activity
----------------------------------------------------------
| 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 |
----------------------------------------------------------
这些是一些示例,在 "Activity" table 这种情况下 "type" 将始终等于 "comment"。
总结一切并期望结果:
当我查询用户 posts 时,我希望能够进入 "Activity" table 并获得 latest 他每 post 就有 2 条评论。也许不会有如此明显的评论 return 0,也许会有 100 条评论 post。但我只想获取 latest/most 最近的 2 条评论。
例如 Instagram 是如何做到的。对于每个 post 显示最近的评论 1、2 或 3....
希望对您有所帮助!
我有点迷失在你的查询中,但如果你想一次下载多个 posts 的数据,在第一个查询中包含评论数据不是一个好主意,因为你会包含关于 post 和 posting 用户多次的所有数据。您应该 运行 另一个将 post 与评论联系起来的查询。类似于:
SELECT
A.UUIDPost,
C.username,
C.profileImage,
B.Comment,
B.[DateField]
FROM Posts A JOIN
Activities B ON A.uuid = B.UUIDPost JOIN
Users C ON B.[UserId] = C.id
并使用该数据显示您的评论,包括评论用户 ID、姓名、图片等。
如果每个 post 只获得 3 条评论,您可以查看此 post:
Select top 3 values from each group in a table with SQL
如果您确定评论 table 或此 post 中不会有重复的行:
How to select top 3 values from each group in a table with SQL which have duplicates
如果您对此不确定(尽管由于 table 中的 DateField,应该不可能)。
这种类型的评论已被 post 多次编辑,并且尝试获得 "latest-for-each" 似乎总是绊脚石,并且对大多数人来说都是加入/子查询的噩梦。
特别是对于 Web 界面,您最好将一列(或 2 或 3)附加到 table 是您的活动 "posts" table 的列,例如最新 1、最新 2、最新 3。
然后,通过插入您的评论 table,在您的 table 上设置一个插入触发器,以使用最新的 ID 更新主 post。然后,您始终在 table 上拥有该 ID,而没有任何子连接。现在,正如您所提到的,您可能希望拥有最后 2 个或 3 个 ID,然后添加 3 个示例列并让您的插入触发器插入 post 评论详细信息,对主要 post table 类似
update PrimaryPostTable
set Latest3 = Latest2,
Latest2 = Latest1,
Latest1 = NewDetailCommentID
where PostID = PostIDFromTheInsertedDetail
这必须在 MySQL 下正式化为适当的触发器,但应该很容易实现。您可以用最新的 1 填充列表,然后随着新的 post 的出现,它会自动将最新的滚动到它们的第 1、第 2、第 3 个位置。最后,您的查询可以简化为
Select
P.PostID,
P.TopicDescription,
PD1.WhateverDetail as LatestDetail1,
PD2.WhateverDetail as LatestDetail2,
PD3.WhateverDetail as LatestDetail3
from
Posts P
LEFT JOIN PostDetail PD1
on P.Latest1 = PD1.PostDetailID
LEFT JOIN PostDetail PD2
on P.Latest2 = PD2.PostDetailID
LEFT JOIN PostDetail PD3
on P.Latest3 = PD3.PostDetailID
where
whateverCondition
通常不需要反规范化数据。但是,在这种情况下,在 For-Each 类型的查询中获取这些 "latest" 条目是一个很好的简化程序。祝你好运。
这是 MySQL 中的完整示例,因此您可以看到 tables 和 sql 插入的结果以及通过触发器自动标记以更新主要 post table。然后查询 post table 您可以看到最近的如何自动滚动到第一、第二和第三位置。最后一个连接展示了如何从每个 "post activity"
中提取所有数据CREATE TABLE Posts
( id int,
uuid varchar(7),
imageLink varchar(9),
`date` datetime,
ActivityID1 int null,
ActivityID2 int null,
ActivityID3 int null,
PRIMARY KEY (id)
);
CREATE TABLE Activity
( id int,
postid int,
`type` varchar(40) collate utf8_unicode_ci,
commentText varchar(20) collate utf8_unicode_ci,
`date` datetime,
PRIMARY KEY (id)
);
DELIMITER //
CREATE TRIGGER ActivityRecAdded
AFTER INSERT ON Activity FOR EACH ROW
BEGIN
Update Posts
set ActivityID3 = ActivityID2,
ActivityID2 = ActivityID1,
ActivityID1 = NEW.ID
where
ID = NEW.POSTID;
END; //
DELIMITER ;
INSERT INTO Posts
(id, uuid, imageLink, `date`)
VALUES
(123, 'test1', 'blah', '2016-10-26 00:00:00');
INSERT INTO Posts
(id, uuid, imageLink, `date`)
VALUES
(125, 'test2', 'blah 2', '2016-10-26 00:00:00');
INSERT INTO Activity
(id, postid, `type`, `commentText`, `date`)
VALUES
(789, 123, 'type1', 'any comment', '2016-10-26 00:00:00'),
(821, 125, 'type2', 'another comment', '2016-10-26 00:00:00'),
(824, 125, 'type3', 'third comment', '2016-10-27 00:00:00'),
(912, 123, 'typeAB', 'comment', '2016-10-27 00:00:00');
-- See the results after the insert and the triggers.
-- you will see that the post table has been updated with the
-- most recent
-- activity post ID=912 in position Posts.Activity1
-- activity post ID=789 in position Posts.Activity2
-- no value in position Posts.Activity3
select * from Posts;
-- NOW, insert two more records for post ID = 123.
-- you will see the shift of ActivityIDs adjusted
INSERT INTO Activity
(id, postid, `type`, `commentText`, `date`)
VALUES
(931, 123, 'type1', 'any comment', '2016-10-28 00:00:00'),
(948, 123, 'newest', 'blah', '2016-10-29 00:00:00');
-- See the results after the insert and the triggers.
-- you will see that the post table has been updated with the
-- most recent
-- activity post ID=948 in position Posts.Activity1
-- activity post ID=931 in position Posts.Activity2
-- activity post ID=912 in position Posts.Activity3
-- notice the FIRST activity post 789 is not there as
-- anything AFTER the 4th entry, it got pushed away.
select * from Posts;
-- Finally, query the data to get the most recent 3 items for each post.
select
p.id,
p.uuid,
p.imageLink,
p.`date`,
A1.id NewestActivityPostID,
A1.`type` NewestType,
A1.`date` NewestDate,
A2.id SecondActivityPostID,
A2.`type` SecondType,
A2.`date` SecondDate,
A3.id ThirdActivityPostID,
A3.`type` ThirdType,
A3.`date` ThirdDate
from
Posts p
left join Activity A1
on p.ActivityID1 = A1.ID
left join Activity A2
on p.ActivityID2 = A2.ID
left join Activity A3
on p.ActivityID3 = A3.ID;
您可以创建一个测试数据库,以免损坏您的数据库以查看此示例。
未测试:我建议将 SQL fiddle 与一些示例数据和显示问题的现有 table 结构放在一起;这样我们就可以处理响应并确保您的模式的功能。
所以我们用一个变量来模拟一个window函数(比如row_number)
在本例中为@Row_num 和@prev_Value。 @Row_number 跟踪每个 post 的当前行(因为单个 post 可能有很多评论)然后当一个新的 post ID(UUIDPOST?)遇到 row_num 变量重置为 1。当当前记录 UUIDPOST 匹配变量 @prev_Value 时,我们只需将行增加 1。
此技术允许我们根据日期或 activity ID 降序分配行号。由于每个交叉联接仅产生 1 条记录,因此我们不会导致出现重复记录。但是,由于我们随后受到 row_number < = 2 的限制,我们只能在新添加的左连接中获得两个最新的评论。
这假设 post 与用户的关系是多对一的,这意味着 post 只能有 1 个用户。
类似这样的事情:虽然我不确定最后的左连接,但我需要更好地理解 activity table 的结构,因此对原始问题发表评论。
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
--This join simulates row_Number() over (partition by PostID, order by activityID desc) (Nice article [here](http://preilly.me/2011/11/11/mysql-row_number/) several other examples exist on SO already.
--Meaning.... Generate a row number for each activity from 1-X restarting at 1 for each new post but start numbering at the newest activityID)
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, --Some date or ID desc) Com
on Com.UUIIDPOSt = Posts.UUID
and row_number < = 2
-- Now since we have a row_number restarting at 1 for each new post, simply return only the 1st two rows.
ORDER BY date DESC
LIMIT 0, 5
我们必须将 and row_number < = 2 放在联接本身上。如果它被放在 where 子句中,你将失去那些 posts 而没有任何我认为你仍然想要的评论。
此外,我们可能应该查看 "comment" 字段以确保它不为空或为空,但首先要确保它有效。
这条错误信息
Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation '='
通常是由于您的列和 table 的定义。它通常意味着在等号的两边有不同的归类。您需要做的是选择一个并将该决定包含在您的查询中。
此处的排序规则问题出现在@prev_value 的 CROSS JOIN 中,需要使用显式排序规则。
我还稍微将“row_number”逻辑更改为单个交叉连接,并将 if 逻辑移至 select 列表的极端。
下面显示了一些示例数据。需要样本数据来测试查询。任何试图用工作示例回答您的问题的人都需要数据。我把它包括在这里的原因是双重的。
- 以便您了解我呈现的任何结果
- 以便将来您提出另一个 SQL 相关问题时,您会了解提供数据的重要性。您这样做不仅对我们更方便。如果提问者提供了示例数据,那么提问者就已经理解了它——这不会是一些花时间帮助的陌生人的发明。
示例数据
请注意 table 中缺少一些列,仅包含 table 详细信息中指定的列。
此示例数据有 5 条针对单个 post 的评论(没有记录喜欢)
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') ;
[SQL 标准行为:每个 Post 查询 2 行]
这是我最初的查询,有一些更正。我更改了 select 列表的列顺序,以便在我呈现结果时您可以轻松地看到一些与评论相关的数据。请研究它们提供的结果,以便您了解查询将执行的操作。由于我已经指出的原因,我正在使用的样本数据中不存在以 # 开头的列。
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
;
See a working demonstration of this query at SQLFiddle
| 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 |
有 2 行 - 正如预期的那样。一行是最近的评论,另一行是下一个最近的评论。这是 SQL 的正常行为,直到在此答案下添加评论之前,问题的读者会假设此正常行为是 acceptable.
该问题缺乏明确表达的“预期结果”。
[选项 1:每个 Post 查询一行,最多 2 条评论,添加列]
在下面的评论中表明您不希望每个 post 有 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
;
See the second query working at SQLFiddle
| 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 |
** 选项 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
See this third query working at SQLFiddle
| 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 |
** 摘要 **
我提出了 3 个查询,每个查询只显示 2 个最近的评论,但每个查询都以不同的方式进行。第一个查询(默认行为)将为每个 post 显示 2 行。选项 2 添加一列但删除第二行。选项 3 连接了 2 个最近的评论。
请注意:
- 该问题缺少 table 涵盖所有列的定义
- 该问题缺少任何示例数据,这让您更难理解此处呈现的任何结果,也让我们更难准备解决方案
- 这个问题也缺乏明确的“预期结果”(想要的输出),这导致回答更加复杂
我希望额外提供的信息会有一些用处,并且现在您也知道 SQL 将数据显示为多行是正常的。如果您不希望出现这种正常行为,请具体说明您在问题中真正想要的是什么。
Post脚本。要包含“follows”的另一个子查询,您可以使用与您已有的子查询类似的子查询。它可以添加在该子查询之前或之后。您可能还会在 sqlfiddle here
看到它在使用LEFT JOIN (
SELECT
COUNT(*) FollowCNT
, IdOtherUser
FROM Activity
WHERE type = 'Follow'
GROUP BY
IdOtherUser
) F ON USERS.id = F.IdOtherUser
虽然添加另一个子查询可能会解决您对更多信息的需求,但整体查询可能会随着数据的增长而变慢。一旦您确定了您真正需要的功能,可能值得考虑在这些 table 上需要哪些索引。 (我相信您会被建议单独寻求该建议,如果您确实包括 1. table 的完整 DDL 和 2. 查询的解释计划。)
这可能会消除排序规则的非法混合...建立连接后,执行此查询:
SET NAMES utf8 COLLATE utf8_unicode_ci;
关于 'latest 2' 的问题,请使用 mysql 命令行工具和 运行 SHOW CREATE TABLE Posts
并提供输出。 (其他相关表也是如此。)Phpmyadmin(和其他 UI)有一种无需进入命令行即可执行查询的方法。
您可以通过使用子查询进行非常简单的查询。首先,我在 where 子句中指定用户并加入 posts 因为这对我来说似乎更合乎逻辑。然后我得到了带有子查询的 post 的所有点赞。
现在我们不再分组和限制组大小,而是通过限制我们当前正在查看的日期之后的日期计数来仅加入我们想要加入的值。
INNER JOIN Activity 如果您只想显示 post 至少有一条评论。
SELECT
u.id,
u.username,
u.fullname,
u.profileImage,
p.uuid,
p.caption,
p.path,
p.date,
(SELECT COUNT(*) FROM Activity v WHERE v.uuidPost = p.uuidPost AND v.type = 'like') likes,
a.commentText,
a.date
FROM
Users u INNER JOIN
Posts p ON p.id = u.id LEFT JOIN
Activity a ON a.uuid = p.uuid AND a.type = 'comment' AND 2 > (
SELECT COUNT(*) FROM Activity v
WHERE v.uuid = p.uuid AND v.type = 'comment' AND v.date > a.date)
WHERE
u.id = 145
也就是说重新设计可能是最好的,也是性能方面的(Activity 很快就会包含很多条目,并且它们总是必须针对所需的类型进行过滤)。用户 table 可以使用 id 自动递增并作为主键。对于 posts 我还会添加一个自动递增的 id 作为主键和 user_id 作为外键(您还可以决定删除时要做什么,例如级联所有他的 post s 也会被自动删除)。
对于评论和点赞,你可以用user_id和post_id这两个外键创建分隔的table(简单的例子,像这样你只能点赞posts 而不是别的,但是如果没有很多不同类型的喜欢,那么创建一个 post_likes 和其他一些 ..._likes tables 仍然很好,你必须考虑如何通常会查询数据,如果这些点赞大部分是相互独立的,那可能是一个不错的选择。