已掉线,重新登录

首页 > 绿虎论坛 > 历史版块 > 编程 > 数据库

标题: 如何用 SQL 求出「都关注了某100人」和「都收藏了某100帖子」的所有用户?

作者: @Ta

时间: 2022-08-10

点击: 35435

想用普通 SQL 语句解决此类『某表有多列「多值属性」(可存为「数组」或「独立表」)。现给定过滤条件,找出包含所有这些条件的行记录』问题。如:

  • 找出所有『既会MySQLPHP』『又购买过iPhone 13红米 K50』的虎友
  • 找出所有『既会说粤语上海话』『考试又过了英语专八日语 N1』的学生
  • 找出所有『既看过《明日战记》《独行月球》』『又看过《当尘埃落尽》《血清素》』的网友(我随便豆瓣首页找的啊)

注意:

  1. 尽量不要使用存储过程/函数、其他编程语言,以及 MySQL 8.0.17+ 的多值索引。
  2. 尽量使用 B+ 树索引(好像PostgreSQL有针对json的高效索引)

[隐藏样式|查看源码]


『回复列表(165|隐藏机器人聊天)』

1.

目前只能做到想法子求出各条件的主键,再求它们的交集。也不知能不能直接合并成多个where条件之类的

(/@Ta/2022-08-10 22:17//)

2.

WHERE IN (Sub Query)

(/@Ta/2022-08-11 09:02//)

3.

@无名啊

『既看过《明日战记》《独行月球》』『又看过《当尘埃落尽》《血清素》』

那不就是

看过《明日战记》、《独行月球》、《当尘埃落尽》《血清素》

吗?

SELECT * FROM hu60_user WHERE
        uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%电影A%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%电影B%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%电影C%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%电影D%');
(/@Ta/2022-08-11 11:57//)

4.

@读书顶个鸟用WHERE IN (Sub Query)是至少出现一个即可,题目要求『所有条件的所有值,同时满足』

你可能至少还要在GROUP BY后指定HAVING COUNT(*) = xxx

@老虎会游泳,表结构应该是(用户ID,用户名,看过啥电影 JSON,看过啥书 JSON,……),或者那俩 JSON 字段独立成(用户ID,看过电影ID),(用户ID,看过书籍ID)(或者字段顺序反过来,看索引需要而定)

(/@Ta/2022-08-11 11:50//)

5.

@无名啊

SELECT * FROM hu60_user WHERE
        uid IN (SELECT uid FROM hu60_用户看过的电影 WHERE 电影id = 12345)
    AND uid IN (SELECT uid FROM hu60_用户看过的电影 WHERE 电影id = 67890)
    AND uid IN (SELECT uid FROM hu60_用户看过的电影 WHERE 电影id = 78901)
    AND uid IN (SELECT uid FROM hu60_用户看过的电影 WHERE 电影id = 89012);
(/@Ta/2022-08-11 11:56//)

6.

@老虎会游泳,这语法结构。。是不是相当于:

SELECT *
  FROM hu60_user
 WHERE uid IN (SELECT uid FROM hu60_用户看过的电影 WHERE 电影id = 12345)
   AND EXISTS (SELECT uid FROM hu60_用户看过的电影 WHERE 电影id = 67890)
   AND EXISTS (SELECT uid FROM hu60_用户看过的电影 WHERE 电影id = 78901)
   AND EXISTS (SELECT uid FROM hu60_用户看过的电影 WHERE 电影id = 89012);
(/@Ta/2022-08-11 12:00//)

7.

@无名啊,我忘记写AND后面的uid IN,已补充

(/@Ta/2022-08-11 12:01//)

8.

实际试一下

SELECT uid, name FROM hu60_user WHERE
        uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%mysql%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%php%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%iphone%13%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%红米%k50%');

Screenshot_20220811_120754.jpg(267.42 KB)

完全正确

(/@Ta/2022-08-11 12:08//)

9.

@老虎会游泳,这种问题,肯定是希望能走索引提速的

你 8楼的肯定是扫全表了

我瞅瞅你5楼的

(/@Ta/2022-08-11 12:09//)

10.

@老虎会游泳,还有至少另外一个问题,不使用其他编程语言 (『注意』中的第一点提到了),怎么拼凑这种 SQL 呢?

(/@Ta/2022-08-11 12:11//)

11.

@无名啊,“不使用其他编程语言”没有现实意义,“不使用其他编程语言”的话,你怎么把参数拼接到SQL里?

既然你都能把参数拼接到SQL里了,把条件拼接到SQL里不是轻轻松松吗?

不要作茧自缚。

这是个变参SQL语句(参数个数不固定),必然是要用其他编程语言进行SQL拼接的。

就算是简单的WHERE uid IN (1, 2, 3)IN里面的uid个数不一样的时候,还不是需要用其他编程语言进行拼接。

(/@Ta/2022-08-11 12:24//)

12.

@老虎会游泳,我用了『关系除法』,来解决『满足一个条件的所有值』

但我不会改写成『多个条件』的……

(/@Ta/2022-08-11 12:15//)

13.

@无名啊,5楼给出了我的方案,8楼证明了它确实可以运行并且给出了正确的结果(它们是同一个SQL语句,只是根据虎绿林的实际情况,=变成LIKE了而已。虎绿林帖子表的实际情况就是需要全表扫描。如果你的实际情况并非如此,当然可以继续使用=以便使用索引)。

所以,我暂时没有其他考虑。

(/@Ta/2022-08-11 12:18//)

14.

@老虎会游泳,这个是课本上的『关系除法』,用于解决『从「员工技能表」中,找出(会「要求技能表」里所有技能的)所有员工』

SELECT DISTINCT	员工ID
  FROM 员工技能表 AS ES1
 WHERE NOT EXISTS (
           SELECT *
             FROM 要求技能表
            WHERE NOT EXISTS (
                      SELECT *
                        FROM 员工技能表 AS ES2
                       WHERE ES2.员工ID = ES1.员工ID
                         AND ES2.技能 = 要求技能表.技能 ))
(/@Ta/2022-08-11 12:24//)

15.

@老虎会游泳,但我不会改写成满足两个条件的(除非搞两次,再求交集了)

(/@Ta/2022-08-11 12:26//)

16.

@无名啊,里面没有参数(由用户输入的查询条件)。当存在参数并且参数个数可能不同时,必然需要其他编程语言进行SQL拼接。

就算是简单的WHERE uid IN (1, 2, 3),IN里面的uid个数不一样的时候,还不是需要用其他编程语言进行拼接。

(/@Ta/2022-08-11 12:26//)

17.

@老虎会游泳,可以变成:

FROM json_table(?, '$[*]' COLUMNS(技能ID INT PATH '$')) 要求技能表

然后提供 JSON:

["MySQL", "PHP"]

这个法子连 SQLite 都支持,算是『普通SQL』了

(/@Ta/2022-08-11 12:29//)

18.

@老虎会游泳SQLite 大概长这样:

select * from json_each('["MySQL", "PHP"]')
(/@Ta/2022-08-11 12:30//)

19.

@无名啊,请考虑一下现实情况,MySQLPHPiPhone 13红米 K50必然是用户输入的查询条件,这些条件肯定既不在程序里也不在表里,SQL语句必然是根据用户输入条件的个数动态生成的。

当用户输入三个查询条件(MySQLPHPiPhone 13)的时候,SQL语句必然和四个查询条件(MySQLPHPiPhone 13红米 K50)不同。

所以“不使用其他编程语言”有什么意义吗?

如果真的要死抠字眼,

SELECT uid, name FROM hu60_user WHERE
        uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%mysql%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%php%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%iphone%13%')
    AND uid IN (SELECT uid FROM hu60_bbs_topic_content WHERE content LIKE '%红米%k50%');

这使用其他编程语言了吗?并没有!它就是一个SQL语句,你怎么能说它使用了其他编程语言呢?它的查询条件固定了,我当然就不需要使用其他编程语言。但现实是查询条件的内容和数量都必然不固定。

(/@Ta/2022-08-11 12:31//)

下一页 1/9页,共165楼

回复需要登录

6月29日 15:35 星期天

本站由hu60wap6驱动

备案号: 京ICP备18041936号-1