我刚刚花了几个小时阅读 MariaDB 文档和这里的各种问题,试图找出一条可以完成我想要的操作的 SQL 语句。我绝对不是专家......最终我确实得到了我预期的结果,但我不知道它为什么有效。我想确保我确实得到了我想要的结果,并且它不仅仅适用于我扔给它的几个测试用例。
我有三个表 guestbook、users 和 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', '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ef8a828e8683af8a978e829f838ac18c8082" rel="noreferrer noopener nofollow">[email protected]</a>', 'user1'),
(13, 'Larry', 'Abc', '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2e4b434f47426e4b564f435e424b004d4143" rel="noreferrer noopener nofollow">[email protected]</a>', 'user2'),
(15, 'Noel', 'Abc', '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9efbf3fff7f2defbe6fff3eef2fbb0fdf1f3" rel="noreferrer noopener nofollow">[email protected]</a>', 'user3'),
(16, 'Kate', 'Abc', '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f49199959d98b4918c9599849891da979b99" rel="noreferrer noopener nofollow">[email protected]</a>', 'user4'),
(17, 'Walter', 'Sobchak', '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="acdbcdc0d8c9de82dfc3cecfc4cdc7ecdfc4cdceced9df82cfc3c1" rel="noreferrer noopener nofollow">[email protected]</a>', 'Walter'),
(18, 'Jae', 'Abc', '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="acc9c1cdc5c0ecc9d4cdc1dcc0c982cfc3c1" rel="noreferrer noopener nofollow">[email protected]</a>', '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 |
+------------+------------+---------+---------------------+---------------------+-------+
语句工作的 fiddle :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(*)
。
请不要使用comcomalist 形式加入。始终使用 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
。加入
已使用
由于只有一个值来自派生表,因此这可能同样有效:
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'
这涉及到很多改变;看看它看起来是否“正确”。现在简单多了。
索引同上。
关于mysql - 在 MariaDB 中的两个表选择语句中的第三个表上使用计数函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63698519/