SQLite 中的子选择

Sub-selects in SQLite

问题

我最近要完成一项技术测试,这需要我执行一个相当复杂的 SQL 查询,我想先了解一下我可能收到的反馈,我给出的答案是否正确,以及如何改进。

这是我对问题的释义

Suppose we have a website selling hats, for which we want to build a database. Each type of hat has a size, price, etc. Each type of hat can also fall into none, one or more categories, and these categories can themselves be public or private.

Do the following:

  1. Write pseudo-SQL code creating the tables necessary to model the above.
  2. Write a query which will return the records for types of hats which belong to at least 5 public categories.

我的尝试

由于我的大部分经验都是使用 SQLite,所以我从 SQLite 的角度解决了这个问题,我在回答的评论中写了这个。

关于上面的第(1)点,我创建了三个table:HatCategoryBelongsToCategory,最后一个是连接table 对于前两个。我制作了 public Category table 的一列,类型为 INTEGER:0 表示假,1 表示真。

关于第(2)点,这是我的查询:

SELECT *
FROM Hat
WHERE
    (SELECT COUNT(*)
     FROM BelongsToCategory
         JOIN Category ON Category.code = BelongsToCategory.category
         WHERE (BelongsToCategory.hat = Hat.code) AND (Category.public = 1))
    >= 5

测试我的尝试

我以下列方式测试了我的尝试:

当我运行上面的SQL代码时,它返回了hat1的记录。任务完成!没那么快……当我试着玩弄一下,将 5 更改为 4、或 3、2 等时,我不断获得 hat1 的记录,除此之外别无他法。到1的时候才开始弹出hat3,一直没看到hat2。

这是怎么回事? 我的查询有问题吗? 或者这是 SQLite 浏览器中的错误?

我想知道的

我认为您的查询没有任何问题(我已经对其进行了测试并且它按预期工作)。因此,我相信您可能没有按预期插入数据。

如果您将计数子查询作为附加列添加到主查询并使用 >= 0,您可以看到计数并了解发生了什么计数

例如:-

SELECT *, (SELECT COUNT(*)
     FROM BelongsToCategory
         JOIN Category ON Category.code = BelongsToCategory.category
         WHERE (BelongsToCategory.hat = Hat.code) AND (Category.public = true)) AS cat_count
FROM Hat
WHERE
    (SELECT COUNT(*)
     FROM BelongsToCategory
         JOIN Category ON Category.code = BelongsToCategory.category
         WHERE (BelongsToCategory.hat = Hat.code) AND (Category.public = true))
    >= 0
;

下面是用来测试上面的:-

PRAGMA foreign_keys = ON;
DROP TABLE IF EXISTS BelongsToCategory;
DROP TABLE IF EXISTS Hat;
DROP TABLE IF EXISTS Category;
CREATE TABLE IF NOT EXISTS Hat (code INTEGER PRIMARY KEY, hattype TEXT, hatprice REAL, hatsize REAL, hatetc TEXT);
CREATE TABLE IF NOT EXISTS Category (code INTEGER PRIMARY KEY, category TEXT, public INTEGER);
CREATE TABLE IF NOT EXISTS BelongsToCategory (
    hat INTEGER REFERENCES Hat(code) ON DELETE CASCADE ON UPDATE CASCADE
    , category INTEGER REFERENCES Category(code) ON DELETE CASCADE ON UPDATE CASCADE
    , PRIMARY KEY(hat,category)
    )   
;

INSERT INTO Category VALUES(1,'cat1',true),(2,'cat2',true),(3,'cat3',true),(4,'cat4',true),(5,'cat5',true),(6,'cat6',false);
INSERT INTO Hat VALUES(1,'hat1',100,7,'other'),(2,'hat2',90,6,'other'),(3,'hat3',95,5,'other'),(4,'hat4',110,8,'other'),(5,'hat5',120,8,'other');
INSERT INTO BelongsToCategory VALUES
    (1,1),(1,2),(1,3),(1,4),(1,5),(1,6)
    ,(2,1)
    ,(3,1),(3,2),(3,3),(3,4)
    ,(5,6),(5,1)
;

SELECT *, (SELECT COUNT(*)
     FROM BelongsToCategory
         JOIN Category ON Category.code = BelongsToCategory.category
         WHERE (BelongsToCategory.hat = Hat.code) AND (Category.public = true)) AS cat_count
FROM Hat
WHERE
    (SELECT COUNT(*)
     FROM BelongsToCategory
         JOIN Category ON Category.code = BelongsToCategory.category
         WHERE (BelongsToCategory.hat = Hat.code) AND (Category.public = true))
    >= 0
;

上面的结果(使用>=0):-

(使用>=5):-

(使用>=4):-