查询具有多个OR / AND的多对多表

时间:2014-01-27 16:25:40

标签: sql sql-server join many-to-many

我有一个基本的多对多表:

tbFilter
filterId | filterName


tbProduct
productId | productName


tbProductFilter
filterId | productId

所以,我有很多产品有很多过滤器(颜色,大小等)。现在,我需要创建一个程序来使用一些过滤器组合来查找产品,例如: 所有产品(蓝色或绿色)和(大OR Xlarge)和(forMen)

我发现创建此查询的唯一方法是使用同一个表的多个连接,每个连接用于“组”过滤器或多个子查询,每个子组用于一个组。最大的问题是多对多表有更多的100k记录,所以这种方法表现不佳。

执行此查询的最佳方法是什么?我正在使用sql 2012。

由于

这就是我现在的工作方式:

select [produtos].* FROM [dbo].[tbProdutos] AS [produtos] JOIN [dbo].tbJuncaoProdutoCategoria] AS [juncaoProdutoCategoria] ON [produtos].[produtoId] = juncaoProdutoCategoria].[produtoId] JOIN [dbo].[tbJuncaoProdutoCategoria] AS juncaoProdutoCategoria2] ON [produtos].[produtoId] = [juncaoProdutoCategoria2].[produtoId] JOIN [dbo].[tbProdutoCategoria] AS [produtoCategoria] ON [produtoCategoria].[categoriaId] = [juncaoProdutoCategoria].[categoriaId] where [juncaoProdutoCategoria].categoriaId = 1 AND ([juncaoProdutoCategoria2].categoriaId = 300 OR [juncaoProdutoCategoria2].categoriaId = 301)

2 个答案:

答案 0 :(得分:0)

首先,您肯定想检查索引 - 您需要所有外键字段以及fitlerName上的索引。

假设您的索引处于良好状态,可以采用以下方法:

SELECT p.*       -- preferably just select the fields you need here...
FROM products p
WHERE p.productId IN (
    SELECT pf.product_id
    FROM tbProductFilter pf
    WHERE EXISTS (SELECT 1 FROM tbFilter f 
                  WHERE pf.filterId = f.filterId AND f.filterName IN ('blue', 'green'))
      AND EXISTS (SELECT 1 FROM tbFilter f 
                  WHERE pf.filterId = f.filterId AND f.filterName IN ('large', 'xlarge'))
      AND EXISTS (SELECT 1 FROM tbFilter f 
                  WHERE pf.filterId = f.filterId AND f.filterName = 'forMen')
)

答案 1 :(得分:0)

将过滤器放入表格(或表值参数),将其连接到ProductFilter表,逐个产品,并计算加入的唯一过滤器。

此方法可以处理任意数量的过滤器并执行模糊匹配,即“向我显示与这四个过滤器中的三个相匹配的产品”

DECLARE @filterCount int = 3
DECLARE @filterSet TABLE ( filterNum int, filterName varchar(max) )

INSERT @filterSet VALUES
  (1,'blue'),(1,'green'),
  (2,'large'),(2,'xlarge'),
  (3,'forMen')

SELECT pf.ProductId
FROM tbProductFilter pf
INNER JOIN tbFilter f ON f.filterId = pf.filterId
INNER JOIN @filterSet s ON s.filterName = f.filterName
GROUP BY pf.productId
HAVING COUNT(DISTINCT s.filterNum) = @filterCount