我有下表:Attributes
和ItemAttributeValues
具有以下结构。
属性
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),因此我们需要将两个表连接起来。
在上述示例中,具有Color
或Red
的{{1}}或Green
的值为Occasion
的那些ItemId产生以下输出:
Casual
问题:
我无法制定包含上述条件的sql逻辑,我可以使用一些指向正确方向的帮助,特别是对于将ItemId
=======
A3
用作值,将Or
用作值的逻辑属性。我正在使用SQL Server 2014。
答案 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
没那么糟。