sqlite 未知列数的SQL筛选器

nszi6y05  于 2023-06-06  发布在  SQLite
关注(0)|答案(3)|浏览(196)

我有一个包含产品的表,一个包含产品标签的表,每个产品可以有几个标签,例如

products

product_id|name|…
1         |book
2         |game
3         |desk
…

tags

product_id|tag
3         |used
3         |physical

有没有一种“好”的方法,只使用SQL来查询所有产品,这些产品都有给定的标签,其中标签在一个数组中,只有在编译时才知道?
我能想到的唯一方法是以编程方式在tags上生成一个包含多个JOIN的查询,重命名为tag1tag2等,然后在WHERE子句中使用tag1 = tags_array[1] AND tag2 = tags_array[2]等进行过滤。
我使用的是SQLITE,如果这是相关的。

0ejtzxu1

0ejtzxu11#

对于给定的标记列表,可以使用关系除法。假设我们需要同时具有'used''physical'标记的所有产品的ID

select product_id
from tags
where tag in ('used', 'physical')     -- either one tag or the other
group by product_id                     
having count(*) = 2                     -- both are available for this product

如果你要参数化这个查询,你只需要:

  • in子句中以编程方式生成产品列表(所需标记的数量是可变的,这会影响查询字符串)
  • 将参数的计数传递给having子句

请注意,SQLite不支持开箱即用的数组。
如果你也想要产品名称,我们可以加入products

select p.id, p.name
from products p
inner join tags t on t.product_id = p.product_id
where t.tag in ('used', 'physical')
group by p.id, p.name
having count(*) = 2
ercv8c1e

ercv8c1e2#

您可以使用GROUP BYHAVING子查询的组合:

SELECT p.product_id, p.name
FROM products p
INNER JOIN tags t ON p.product_id = t.product_id
WHERE t.tag IN ('tag1', 'tag2', 'tag3')
GROUP BY p.product_id, p.name
HAVING COUNT(DISTINCT t.tag) = 3;
3ks5zfa0

3ks5zfa03#

您可以对标记数组进行过滤,以轻松计算其长度,然后可以在having子句中使用该长度。

select t.product_id, max(p.name)
from products p
inner join tags t on t.product_id = p.product_id
inner join (
  SELECT value as tag 
  FROM json_each('["used", "physical"]')
) as s on s.tag = t.tag
group by t.product_id
having count(*) = json_array_length('["used", "physical"]');

Demo here

相关问题