我想管理数据库中的一组事物。假设以下两个表:
CREATE TABLE Sets (id BIGINT PRIMARY KEY, name VARCHAR(64));
CREATE TABLE SetItems (fkSet BIGINT, item BIGINT, FOREIGN KEY (fkSet) REFERENCES Sets(id));
我可以通过在表Sets
中插入一行来创建集合,并使用相应的SetItems
将一行或多行添加到fkSet
。
获取特定集合的项目很简单,基本上是SELECT * FROM SetItems WHERE fkSet = :id
。
问题:现在我想知道在给定一组SetItem的情况下是否存在集合。
示例:我想查找是否存在包含2
和5
项的集合。
我尝试了什么:
(1)我可以尝试类似:
SELECT s.fkSet FROM Sets s, SetItems i1, SetItems i2
WHERE s.id = i1.fkSet AND i1.item = 2
AND s.id = i2.fkSet AND i2.item = 5;
但这种方法有几个缺点:
为了更好地防止SQL注入,我更喜欢使用Prepared Statements的方法。从技术上讲,我可以使用String连接为预准备语句汇编查询字符串,然后设置查询参数,但这种方法在某种程度上感觉不对。
(2)另一个解决方案:我可以先得到第一个SetItem所有的集合,然后检查每个返回的集合,如果它还包含所有其他项目而没有其他项目。如果第一个SetItem包含在大量的集合中,这将导致大量查询,这看起来效率低且不可扩展。
(3)对于应该包含的每个SetItem,我可以获取它所在的所有集合,然后在SQL之外的代码中进行交集。这将需要最多与要检查的SetItems一样多的sql查询。
(4)另一种方法是将setItems作为逗号分隔列表存储为VARCHAR,按递增顺序排序,直接作为表Sets
中的附加列。那时就不需要表SetItems了。要检查是否存在集合,我可以查询是否存在具有相同逗号分隔列表的行。但是,像“在哪个集合中包含项目xy”这样的查询将不可能如此轻松,依赖于SQL查询中的字符串匹配。不是很关系...
问题:如果存在一组相关行,如何有效地查询SQL数据库? 我应该以不同方式构建数据吗?我应该使用NoSQL数据库进行此类查询吗?
我目前正在使用H2,并且更喜欢不使用单个数据库供应商的某些特定SQL方言的解决方案。
答案 0 :(得分:1)
您可以使用having
来检查每套不同的匹配数量:
select i.fkSet
from SetItems i
where i.item in (2, 5)
group by s.fkSet
having count(distinct i.item) = 2
当然,您需要确保最终的数字(此处为2)与您在in
运算符中列出的值的数量相对应。