Sql server 如何在SQLServer中对EAV表进行多选筛选
我有一个带有属性的EAV表,并且希望根据传递到存储过程中的变量对项目进行混合选择 样本表:Sql server 如何在SQLServer中对EAV表进行多选筛选,sql-server,where-clause,entity-attribute-value,Sql Server,Where Clause,Entity Attribute Value,我有一个带有属性的EAV表,并且希望根据传递到存储过程中的变量对项目进行混合选择 样本表: | group_id | item_id | key | value | +----------+---------+--------+-------+ | 1 | AA | length | 10 | | 1 | AA | width | 10 | | 1 | AA | color | white | | 1
| group_id | item_id | key | value |
+----------+---------+--------+-------+
| 1 | AA | length | 10 |
| 1 | AA | width | 10 |
| 1 | AA | color | white |
| 1 | AA | brand | beta |
| 1 | BB | length | 25 |
| 1 | BB | brand | alpha |
| 2 | CC | brand | alpha |
示例查询:
declare @attributes nvarchar(max) = 'brand name, length'
declare @attributeValues nvarchar(max) = 'alpha, beta, 25'
declare @id int = 1
select *
into #allProductsFromGroup
from items
where group_id = @id
select item_id
from #allProductsFromGroup #all
where [key] in (select value from string_split(@attributes, ','))
and [value] in (select value from string_split(@attributeValues, ','))
预期产出:
| item_id |
+---------+
| BB |
我可以为每个键
硬编码和
以及或
语句,但是有很多,我正在寻找一个更具可扩展性的解决方案
传入并解析JSON会很好,比如:
[
{ "brand": "aplha" },
{ "brand": "beta" },
{ "length": 25 }
]
如何编写第二个
select
来动态返回allProductsFromGroup
的子集,该子集动态地包含来自同一组(多选品牌或多选长度)的多个结果,但从其他组(颜色、长度等)中排除?目标查询可能如下所示:
with q as
(
select item_id,
max( case when [key] = 'brand' then [value] end ) brand,
max( case when [key] = 'length' then cast( [value] as int ) end ) length,
from #allProductsFromGroup
group by Item_id
)
select item_id
from q
where brand in ('alpha','beta') and length=25
您只需从传入的数据构建它(糟糕)。要生成的更简单的查询表单可能如下
select item_id
from #allProductsFromGroup
where [key] = 'brand' and [value] in ('alpha','beta')
intersect
select item_id
from #allProductsFromGroup
where [key] = 'length' and [value] = 25
将
和
标准映射到相交
,将或
标准映射到联合
。它也可能更便宜,因为每个查询都可以在(key,value)上查找索引。这可能是一个迟来的答案,但是如果您可以将条件作为JSON传递,那么下一种方法也是一种可能的解决方案。JSON的格式必须与答案中的格式相同,并且可以使用两个以上的条件:
表:
CREATE TABLE Data (
group_id int,
item_id varchar(2),
[key] varchar(100),
[value] varchar(100)
)
INSERT INTO Data (group_id, item_id, [key], [value])
VALUES
(1, 'AA', 'length', '10'),
(1, 'AA', 'width', '10'),
(1, 'AA', 'color', 'white'),
(1, 'AA', 'brand', 'beta'),
(1, 'BB', 'length', '25'),
(1, 'BB', 'brand', 'alpha'),
(2, 'CC', 'brand', 'alpha')
作为JSON的条件:
DECLARE @conditions varchar(max) = N'
[
{"key": "brand", "values": ["alpha", "beta"]},
{"key": "length", "values": ["25"]}
]
'
声明:
SELECT d.item_id
FROM Data d
JOIN (
SELECT j1.[key], j2.[value]
FROM OPENJSON(@conditions) WITH (
[key] varchar(100) '$.key',
[values] nvarchar(max) '$.values' AS JSON
) j1
CROSS APPLY OPENJSON(j1.[values]) j2
) o ON d.[key] = o.[key] AND d.[value] = o.[value]
GROUP BY d.item_id
HAVING COUNT(*) = (SELECT COUNT(*) FROM OPENJSON(@conditions))
结果:
item_id
BB
只是想说明一下-您希望
键
和值
所在的行与bramd
和aplha
,或name
和beta
相同,或者length
和25
?其中key=brand&value=alpha或beta
和key=length和value=25
因此对于一个结构合理的表来说,等同于Where brand in('alpha','beta')、length=25
?好吧,EAV是一种糟糕的做法,所以那艘船已经开航了。@Matthew如果将标准作为JSON传递是一种选择,那么可能是像{“brand”:[“aplha”,“beta”],“length”:[“25”]}
这样的JSON结构看起来更好。谢谢!我需要一些时间来思考这个问题。。。我希望使用类似于json\u query
的东西来为where子句引入数据。我以前没用过intersect。。。感谢您周到的回复!