【问题标题】:Boolean expressions for a tagging system in SQLSQL 中标记系统的布尔表达式
【发布时间】:2010-12-22 05:58:04
【问题描述】:

为标记系统提供此 SQL 表:

CREATE TABLE tags (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100)
);
CREATE INDEX tags_name_idx ON tags(name);

CREATE TABLE tagged_items (
    tag_id INT,
    item_id INT
);
CREATE INDEX tagged_items_tag_id_idx ON tagged_items(tag_id);
CREATE INDEX tagged_items_item_id_idx ON tagged_items(item_id);

CREATE TABLE items (
    id SERIAL PRIMARY KEY,
    content VARCHAR(255)
);

用户在SQL中的布尔表达式查询“tag1 AND tag2”为:

SELECT items.* FROM items
    INNER JOIN tagged_items AS i1 ON (items.id = i1.item_id) INNER JOIN tags AS t1 ON (i1.tag_id = t1.id)
    INNER JOIN tagged_items AS i2 ON (items.id = i2.item_id) INNER JOIN tags AS t2 ON (i2.tag_id = t2.id)
WHERE t1.name = 'tag1' AND t2.name = 'tag2';

你如何翻译其他带有布尔表达式的查询,例如“tag1 OR tag2 AND tag3”……甚至更复杂的查询,例如“tag1 AND (tag2 OR tag3) AND NOT tag4 OR tag5" 到 SQL?

【问题讨论】:

  • 请问可以添加表 DATA 吗?
  • 也许他的意思是“SELECT data.* FROM items”,否则 items 是未定义的。
  • 是的,我在 SELECT 中弄错了(现在修复了帖子)......对此感到抱歉。

标签: sql boolean tagging


【解决方案1】:

假设数据 -> 项目、单词 -> 名称和 tagged_item -> tagged_items。

这适用于“tag1 AND (tag2 OR tag3) AND NOT tag4 OR tag5”。我相信你可以弄清楚其余的。

SELECT items.* FROM items
    LEFT JOIN (SELECT i1.item_id FROM tagged_items AS i1 INNER JOIN tags AS t1 ON i1.tag_id = t1.id AND t1.name = 'tag1') AS ti1 ON items.id = ti1.item_id
    LEFT JOIN (SELECT i2.item_id FROM tagged_items AS i2 INNER JOIN tags AS t2 ON i2.tag_id = t2.id AND t2.name = 'tag2') AS ti2 ON items.id = ti2.item_id
    LEFT JOIN (SELECT i3.item_id FROM tagged_items AS i3 INNER JOIN tags AS t3 ON i3.tag_id = t3.id AND t3.name = 'tag3') AS ti3 ON items.id = ti3.item_id
    LEFT JOIN (SELECT i4.item_id FROM tagged_items AS i4 INNER JOIN tags AS t4 ON i4.tag_id = t4.id AND t4.name = 'tag4') AS ti4 ON items.id = ti4.item_id
    LEFT JOIN (SELECT i5.item_id FROM tagged_items AS i5 INNER JOIN tags AS t5 ON i5.tag_id = t5.id AND t5.name = 'tag5') AS ti5 ON items.id = ti5.item_id
WHERE ti1.item_id IS NOT NULL AND (ti2.item_id IS NOT NULL OR ti3.item_id IS NOT NULL) AND ti4.item_id IS NULL OR ti5.item_id IS NOT NULL;

编辑: 如果你想避免子查询,你可以这样做:

SELECT items.* FROM items 
    LEFT JOIN tagged_items AS i1 ON items.id = i1.item_id LEFT JOIN tags AS t1 ON i1.tag_id = t1.id AND t1.name = 'tag1'
    ...
WHERE t1.item_id IS NOT NULL ...

我不确定您为什么要这样做,因为额外的左连接可能会导致运行速度变慢。

【讨论】:

  • 有什么办法可以避免使用嵌套的 SELECT 吗?就像我给出的“tag1 AND tag2”示例一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 2023-03-23
  • 2016-04-06
  • 2010-10-04
相关资源
最近更新 更多