1

在 SQLite 中,我想编写一个 SELECT 查询来查找具有某些属性+值或不具有某些属性的文章,其中属性位于另一个表中。

这就是我组织数据库的方式:

Articles:

ID  Name
1   Paper clip
2   Water hose
3   Rubber duck

Features
ID    Articles_ID  Name    Value
1     1            Color   White
2     2            Color   Yellow
3     2            Length  1.4m
4     3            Color   Yellow

如果我想找到黄色的文章,我可以这样做:

SELECT distinct a.Name from Articles a join Features f
             where a.ID = f.Articles_ID
               and f.Name = "Color"
               and f.Value = "Yellow";

但是,如果我想查找颜色为黄色但没有任何长度特征的文章怎么办。即我想要橡皮鸭,因为它没有长度,但我不想要水管。

在我的 UI 中可以选择:

Color: [ ] <empty>
       [x] Yellow
       [ ] White
       [ ] ...

Length: [x] <empty>
        [ ] 0.7m
        [ ] 1.4m
        [ ] ...

我的文章表有 ~20k 行和 ~200k 特征。

也许我的数据库不适合这种查询?如有必要,我可以轻松地重新生成它。

4

1 回答 1

1

(注意:您可能需要文章 ID,在这种情况下您不需要DISTINCT;并且连接的语法应该是tableA JOIN tableB ON condition。)

有三种可能:你可以得到所有黄色文章,然后排除所有有长度的文章:

SELECT a.ID,
       a.Name
FROM Articles a
JOIN Features f ON a.ID = f.Articles_ID
WHERE f.Name = 'Color'
  AND f.Value = 'Yellow'
EXCEPT
SELECT a.ID,
       a.Name
FROM Articles a
JOIN Features f ON a.ID = f.Articles_ID
WHERE f.Name = 'Length'

或者,使用子查询来匹配Length不存在相应记录的记录:

SELECT a.ID,
       a.Name
FROM Articles a
JOIN Features f ON a.ID = f.Articles_ID
WHERE f.Name = 'Color'
  AND f.Value = 'Yellow'
  AND NOT EXISTS (SELECT ID
                  FROM Features f2
                  WHERE f2.Articles_ID = a.ID
                    AND f2.Name = 'Length')

或者,使用 aLEFT JOIN与所有Length要素连接,并匹配此类连接未成功的那些记录。(使用Color第一个特征连接中的条件,这个查询是最常规的。)

SELECT a.ID,
       a.Name
FROM Articles a
JOIN      Features f1 ON  a.ID = f1.Articles_ID
                      AND f1.Name = 'Color'
LEFT JOIN Features f2 ON  a.ID = f2.Articles_ID
                      AND f2.Name = 'Length'
WHERE f1.Value = 'Yellow'
  AND f2.Value IS NULL

哪种查询最有效取决于您拥有哪些索引以及 SQLite 是否决定使用它们。使用EXPLAIN QUERY PLAN进行检查。

于 2012-11-30T10:37:43.710 回答