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

发布于 2024-11-17 12:52:02 字数 722 浏览 2 评论 0原文

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

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

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

编辑:

到目前为止,我计划分发 AND,即 ((COOL OR NOT FUNNY) AND NOT CAILDISH) => (酷而不幼稚)或(不好笑也不幼稚)。然后我可以确定用“或”组合在一起的每个部分,例如:

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 将它们连接在一起。

I have a mySQL table with columns: name and label. If a person, "Bob" has the labels "cool","funny", and "childish", my table would have the corresponding rows: (Bob, cool), (Bob, funny), and (Bob, childish).

Is there an efficient way to select people based on labels with a boolean query? For example, in pseudo-SQL: SELECT name WHERE person IS (COOL OR NOT FUNNY) AND NOT CHILDISH.

I think I could hack something together using UNION, JOIN, maybe some sub-queries, but I was wondering if there was an efficient way to do this.

EDIT:

As of now, I am planning to distribute AND, ie ((COOL OR NOT FUNNY) AND NOT CHILDISH) => (COOL AND NOT CHILDISH) OR (NOT FUNNY AND NOT CHILDISH). And then I can determine each of the parts that are OR'd together with something like:

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"

And then use UNION to join them together.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

陌伤ぢ 2024-11-24 12:52:02

对于否定检查,最有效的方法是使用 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 关键字从第一个查询中选择不同的行,不选择 em> 出现在第二个查询中。

LABEL 上建立索引会提高性能:

CREATE INDEX NAME_LABEL_NAME ON NAME_LABEL(NAME);

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

For the negative checks, the most efficient way would be to use MINUS as follows:

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');

The MINUS keyword selects distinct rows from the first query and don't appear in the second query.

Performance would be better with an index on LABEL:

CREATE INDEX NAME_LABEL_NAME ON NAME_LABEL(NAME);

Unfortunately, the "NOT FUNNY" requires an EXISTS subquery. If you use a join, the MySQL query optimizer turns it into a subselect anyway :(

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文