查找与所有指定组中的任何值匹配的行

时间:2018-11-04 19:02:19

标签: sql sql-server

我有下表:AttributesItemAttributeValues具有以下结构。

属性

Id          Name
================
1           Color
2           Size
3           Occasion
4           Material

ItemAttributeValues

ItemId      AttributeId     Value           
=================================
A1          1               Green
A1          2               XL
A2          2               X
A3          1               Red
A3          3               Casual
A4          4               Linen

我有一个存储过程,该存储过程接受名为@filters的参数,该参数是用户定义的表值类型,具有以下结构和样本值:

Name        Value
=================
Color       Green
Color       Red
Occasion    Casual

我想从ItemId表中找到所有与过滤器中每个唯一属性匹配至少一个值的ItemAttributeValues表。如示例值所示,提供了属性名称(非id),因此我们需要将两个表连接起来。

在上述示例中,具有ColorRed的{​​{1}}或Green的值为Occasion的那些ItemId产生以下输出:

Casual

问题

我无法制定包含上述条件的sql逻辑,我可以使用一些指向正确方向的帮助,特别是对于将ItemId ======= A3 用作值,将Or用作值的逻辑属性。我正在使用SQL Server 2014。

1 个答案:

答案 0 :(得分:1)

我测试了所有与您讨论的方案。

似乎工作正常。请抛出您的反馈或测试方案。

尝试一下

declare @Attributes table(Id int,Name varchar(30))
insert into @Attributes VALUES
(1,'Color')
,(2,'Size')
,(3,'Occasion')
,(4,'Material')


declare @ItemAttributeValues table(ItemId varchar(30), 
AttributeId int, Value varchar(30))  

insert into @ItemAttributeValues VALUES
('A1',1,'Green')
,('A1',2,'XL')
,('A2',2,'X')
,('A3',1,'Red')
,('A3',3,'Casual')
,('A4',4,'Linen') -- ,('A3',4,'Linen')

declare @Filter table(Name varchar(30),Value varchar(30))

insert into @Filter VALUES
('Color',  'Green')
,('Color', 'Red')
,('Occasion','Casual')
--,('Material', 'Linen')
--,('Size','X')
--,('Size','XL')

Declare @DistinctFilterAttribute int

select   @DistinctFilterAttribute =count(distinct name) from @Filter
select @DistinctFilterAttribute

;With CTE as
(
SELECT IAV.*
,ROW_NUMBER() OVER(PARTITION BY IAV.ItemId order by IAV.AttributeId )rn
from @Filter F
inner join @ItemAttributeValues IAV on F.Value=IAV.Value
)

select itemid from cte
where rn=@DistinctFilterAttribute

现在,当需求明确时,这是最优化的查询,

select IAV.ItemId from @ItemAttributeValues IAV 
where exists(select 1 from @Filter F where F.Value=IAV.Value)
group by IAV.ItemId
having count(*)=@DistinctFilterAttribute

@ItemAttributeValues似乎是非常重要的表。 所有3列似乎都是索引的良好候选者。 由于这似乎是虚拟表结构,所以无话可说。

取决于在join/where条件下最常使用哪一列 可以在这些列上创建索引。

如果可以在过滤器表中传递Id,尽管Name没那么糟。