mysql - 在 mySQL 中进行并集和交集的有效方法

标签 mysql logic boolean union intersection

我有一个 mySQL 表,其中包含以下列:名称和标签。如果一个人“鲍勃”具有“酷”、“有趣”和“幼稚”标签,那么我的表将具有相应的行:(鲍勃,酷)、(鲍勃,有趣)和(鲍勃,幼稚)。

是否有一种有效的方法可以通过 boolean 查询根据标签选择人员?例如,在伪 SQL 中:SELECT name WHERE person IS (COOL OR NOT FUNNY) AND NOT CHILDISH。

我想我可以使用 UNION、JOIN 或一些子查询将一些东西组合在一起,但我想知道是否有一种有效的方法来做到这一点。

编辑:

到目前为止,我计划分发 AND,即((酷或不好笑)AND NOT CAILDISH)=>(COOL AND NOT CAILDISH)OR(不好笑且不幼稚)。然后我可以确定与以下内容进行“或”运算的每个部分:

SELECT DISTINCT a.name
FROM `tags` AS a
JOIN `tags` AS b ON (a.label='cool' AND a.name=b.name AND b.name NOT IN (
    SELECT name FROM `tags` WHERE label='funny'))
JOIN `tags` AS c ON (a.name=c.name AND c.name='childish')
# for "COOL AND NOT FUNNY AND CHILDISH"

然后使用 UNION 将它们连接在一起。

最佳答案

对于否定检查,最有效的方法是使用MINUS,如下所示:

SELECT NAME
FROM NAME_LABEL
WHERE LABEL IN ('COOL') -- use IN for easy matching of multiple labels
UNION
SELECT NAME
FROM NAME_LABEL NL
WHERE NOT EXISTS (SELECT * FROM NAME_LABEL WHERE NAME = NL.NAME AND LABEL IN ('FUNNY')) 
MINUS
SELECT NAME
FROM NAME_LABEL
WHERE LABEL IN ('CHILDISH');

MINUS 关键字从第一个查询中选择不同的行,并且不会出现在第二个查询中。

LABEL 上建立索引,性能会更好:

CREATE INDEX NAME_LABEL_NAME ON NAME_LABEL(NAME);

不幸的是,“NOT FUNNY”需要 EXISTS 子查询。如果您使用连接,MySQL 查询优化器无论如何都会将其转换为子选择:(

关于mysql - 在 mySQL 中进行并集和交集的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6515198/

相关文章:

ruby-on-rails - 在Rails ActiveRecord中分配给 boolean 字段时如何转换值?

c++ - cin 到 boolean vector

java - Java 中的字符串回文检查器不起作用?

mysql - 将两个查询放入同一个表中(按日期分组)

mysql - 让mysql区分大小写?

php - mysql/php 选择行并发送电子邮件不起作用

php - 获取聊天数据并按接收者和发送者 ID 排序

vb.net - 递归函数不遵循所有路径

logic - 什么是学术界以外的自然扣除?

algorithm - 找出三个出现次数为偶数的唯一数字