检查是否存在一组相关行

时间:2017-11-23 19:58:13

标签: sql database h2

我想管理数据库中的一组事物。假设以下两个表:

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的情况下是否存在集合。

示例:我想查找是否存在包含25项的集合。

我尝试了什么:

(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;

但这种方法有几个缺点:

  • 如果我需要检查更多的SetItems,我认为它的扩展非常糟糕。
  • 我需要将sql-query与字符串连接放在一起,这是我不喜欢的,增加了注入攻击的可能性。
  • 它还可以找到除了2和5之外还有其他项目的集合,我不喜欢。

为了更好地防止SQL注入,我更喜欢使用Prepared Statements的方法。从技术上讲,我可以使用String连接为预准备语句汇编查询字符串,然后设置查询参数,但这种方法在某种程度上感觉不对。

(2)另一个解决方案:我可以先得到第一个SetItem所有的集合,然后检查每个返回的集合,如果它还包含所有其他项目而没有其他项目。如果第一个SetItem包含在大量的集合中,这将导致大量查询,这看起来效率低且不可扩展。

(3)对于应该包含的每个SetItem,我可以获取它所在的所有集合,然后在SQL之外的代码中进行交集。这将需要最多与要检查的SetItems一样多的sql查询。

(4)另一种方法是将setItems作为逗号分隔列表存储为VARCHAR,按递增顺序排序,直接作为表Sets中的附加列。那时就不需要表SetItems了。要检查是否存在集合,我可以查询是否存在具有相同逗号分隔列表的行。但是,像“在哪个集合中包含项目xy”这样的查询将不可能如此轻松,依赖于SQL查询中的字符串匹配。不是很关系...

问题:如果存在一组相关行,如何有效地查询SQL数据库? 我应该以不同方式构建数据吗?我应该使用NoSQL数据库进行此类查询吗?

我目前正在使用H2,并且更喜欢不使用单个数据库供应商的某些特定SQL方言的解决方案。

1 个答案:

答案 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运算符中列出的值的数量相对应。