mysql - 在 MariaDB 中的两个表选择语句中的第三个表上使用计数函数

标签 mysql count mariadb

我刚刚花了几个小时阅读 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 -- 查询首先按照 JOINON 子句的指示组合表。结果被放入(至少逻辑上)到临时表中。通常,这个临时表的行数比任何被JOINed的表的行数都多。

然后执行COUNT(..)。它正在计算该临时表中的行数。也许这个数字正是您想要的,也许它是一个巨大的数字。

count(user_likes.post_id) 还有一个额外的问题,即不计算 user_likes.post_id IS NULL 的任何行。这通常是无关紧要的,在这种情况下,您应该简单地说 COUNT(*)

请不要使用comcomalist 形式加入。始终使用 FROM a JOIN b ON ...,其中 ON 子句说明表 ab 的关联方式。如果还有一些过滤,请将其放入 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/

相关文章:

php - 选择 UNIX_TIMESTAMP() 返回奇怪的 JSON 键

c - Arduino Due C 定时器编码(中断计数)

python - 计算文档数量

java - ZeroDateTimeBehavior=convertToNull 在使用 hibernate 的 jdbc url 中不起作用

Mysql多实例无法通过socket连接

php - 有时 mysql 全文搜索在应该返回任何结果时却没有返回任何结果

mysql - 查找重复项,然后使用主表中的 id 更新表,然后删除表中的记录

c++ - 文件中的字数,C++

python - MySQL 拒绝远程连接

mysql - 在选择额外列时 MariaDB 中的 SQL 响应变慢