我只是花了几个小时阅读MariaDB文档和这里的各种问题,试图找出一个SQL语句,它做了我想要的。我绝对不是专家...最终我确实得到了我预期的结果,但我不知道它为什么有效。我想确保我真的得到了我想要的结果,它不仅适用于我扔给它的几个测试用例。
我有三个表留言簿,用户和user_likes。我正在尝试编写一个SQL语句,该语句将返回用户的用户名和名字,帖子内容,发布日期,留言簿中的帖子ID,第三列喜欢,这是留言簿中的帖子ID出现在user_likes表中的总次数。它应该只返回标准类型的帖子,并应按帖子日期升序对行进行排序。
示例数据:
CREATE TABLE users
(`user_id` int, `user_first` varchar(6), `user_last` varchar(7),
`user_email` varchar(26), `user_uname` varchar(6))
;
INSERT INTO users
(`user_id`, `user_first`, `user_last`, `user_email`, `user_uname`)
VALUES
(0, 'Bob', 'Abc', 'email@example.com', 'user1'),
(13, 'Larry', 'Abc', 'email@example.com', 'user2'),
(15, 'Noel', 'Abc', 'email@example.com', 'user3'),
(16, 'Kate', 'Abc', 'email@example.com', 'user4'),
(17, 'Walter', 'Sobchak', 'walter.sobchak@shabbus.com', 'Walter'),
(18, 'Jae', 'Abc', 'email@example.com', 'user5')
;
CREATE TABLE user_likes
(`user_id` int, `post_id` int, `like_id` int)
;
INSERT INTO user_likes
(`user_id`, `post_id`, `like_id`)
VALUES
(0, 23, 1),
(0, 41, 2),
(13, 23, 7)
;
CREATE TABLE guestbook
(`post_id` int, `user_id` int, `post_date` datetime,
`post_content` varchar(27), `post_type` varchar(8),
`post_level` int, `post_parent` varchar(4))
;
INSERT INTO guestbook
(`post_id`, `user_id`, `post_date`, `post_content`,
`post_type`, `post_level`, `post_parent`)
VALUES
(2, 0, '2018-12-15 20:32:40', 'test1', 'testing', 0, NULL),
(8, 0, '2018-12-16 14:06:40', 'test2', 'testing', 0, NULL),
(9, 13, '2018-12-16 15:47:55', 'test4', 'testing', 0, NULL),
(23, 0, '2018-12-25 17:59:46', 'Merry Christmas!', 'standard', 0, NULL),
(39, 16, '2018-12-26 00:28:04', 'Hello!', 'standard', 0, NULL),
(40, 15, '2019-01-27 00:46:12', 'Hello 2', 'standard', 0, NULL),
(41, 18, '2019-02-25 00:44:35', 'What are you doing?', 'standard', 0, NULL)
;
我尝试了一大堆涉及计数的复杂陈述,但没有得到我想要的。通过看似愚蠢的运气,我偶然创建了这个声明,它似乎给了我想要的东西。
SELECT
u.user_uname, u.user_first, g.post_id, g.post_date,
g.post_content, count(user_likes.post_id) AS likes
FROM
users AS u, guestbook AS g
LEFT JOIN
user_likes on g.post_id=user_likes.post_id
WHERE
u.user_id=g.user_id AND g.post_type='standard'
GROUP BY
g.post_id
ORDER BY
g.post_date ASC;
问题: 为什么这个计数功能似乎有效?
我能够工作的计数函数是这样的,但它仅适用于硬编码的post_id值。
SELECT COUNT(CASE post_id WHEN 23 THEN 1 ELSE null END) FROM user_likes;
当我尝试通过更改为此值来匹配留言簿表中的post_id时,我得到一个不正确的值,该值似乎是整个user_likes表。
SELECT COUNT(case when guestbook.post_id=user_likes.post_id then 1 else null end) FROM guestbook, user_likes;
在末尾添加一个GROUP BY guestbook.post_id
让我更接近,但现在我需要弄清楚如何将其与我原来的 select 语句结合起来。
+----------------------------------------------------------------------------+
| COUNT(case when guestbook.post_id=user_likes.post_id then 1 else null end) |
+----------------------------------------------------------------------------+
| 0 |
| 0 |
| 0 |
| 2 |
| 0 |
| 0 |
| 1 |
+----------------------------------------------------------------------------+
这是我想要的输出,我正在得到。我只是不相信我的说法是可靠或正确的。
+------------+------------+---------+---------------------+---------------------+-------+
| user_uname | user_first | post_id | post_date | post_content | likes |
+------------+------------+---------+---------------------+---------------------+-------+
| user1 | Bob | 23 | 2018-12-25 17:59:46 | Merry Christmas! | 2 |
| user4 | Kate | 39 | 2018-12-26 00:28:04 | Hello! | 0 |
| user3 | Noel | 40 | 2019-01-27 00:46:12 | Hello 2 | 0 |
| user5 | Jae | 41 | 2019-02-25 00:44:35 | What are you doing? | 1 |
+------------+------------+---------+---------------------+---------------------+-------+
语句工作的小提琴:http://sqlfiddle.com/#!9/968656/1/0
JOIN
+COUNT
-- 查询首先按照JOIN
和ON
子句的指示组合表。 结果(至少在逻辑上)放入临时表中。 通常,此临时表的行数比要JOINed
的任何表都要多得多。
然后执行COUNT(..)
。 它正在计算该临时表中的行数。 也许这个数字正是你想要的,也许这是一个被夸大的数字。
count(user_likes.post_id)
有一个额外的小问题,即不计算user_likes.post_id IS NULL
的任何行。 这通常是无关紧要的,在这种情况下,您应该简单地说COUNT(*)
.
请不要使用逗号形式加入。 始终使用FROM a JOIN b ON ...
,其中ON
子句说明了表a
和b
之间的关系。 如果还有一些过滤,请将其放入WHERE
子句中。
如果COUNT
太大,请搁置已开发的查询,重新开始开发一个只做一件事的查询 - 计算县。 此查询可能会使用较少的表。
然后在此基础上获取所需的任何其他数据。 它可能看起来像
SELECT ...
FROM ( SELECT foo, COUNT(*) AS ct FROM t1 GROUP BY foo ) AS sub1
JOIN t2 ON t2.foo = sub1.foo
JOIN t3 ON ...
WHERE ...
获取获得正确COUNT
的初始查询。 然后,如果需要,请回来寻求更多帮助。
正如布莱恩所尝试的那样
好的,我做了一些更改。
SELECT u.user_uname, u.user_first,
g2.post_id, g2.post_content, g2.post_date,
sub.likes
FROM
(
SELECT g.post_id,
SUM(g.post_id = ul.post_id) AS likes
FROM guestbook AS g
JOIN user_likes AS ul
WHERE g.post_type = 'standard'
) AS sub
JOIN guestbook AS g2 ON sub.post_id = g2.post_id
JOIN users AS u ON u.user_id = g2.user_id;
指标:
guestbook: (post_type, post_id) -- for derived table
guestbook: (post_id) -- for outer SELECT
users: (user_id)
user_likes: (post_id)
笔记:
ORDER BY
删除,因为它在上下文中毫无用处。COUNT..CASE
改为更短的SUM
。- 使用
JOIN ON
由于只有一个值来自派生表,因此这可能同样有效:
SELECT u.user_uname, u.user_first,
g.post_id, g.post_content, g.post_date,
( SELECT COUNT(*)
FROM user_likes AS ul
WHERE g.post_id = ul.post_id
) AS likes
FROM guestbook AS g
JOIN users AS u USING(user_id);
WHERE g.post_type = 'standard'
这涉及很多变化;看看它看起来是否"正确"。 现在简单多了。
索引与上述相同。