如何在 SQL 服务器中多重 select 过滤 EAV table
How to multi-select filter an EAV table in SQL Server
我有一个带有属性的 EAV table,我想根据传递到存储过程中的变量对项目进行混合 selection。
样本table:
| 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 |
我可以在每个 key
的 and
和 or
语句中进行硬编码,但是有很多,我正在寻找更具扩展性的解决方案。
传入并解析JSON就好了,比如:
[
{ "brand": "aplha" },
{ "brand": "beta" },
{ "length": 25 }
]
我如何将第二个 select
写入动态 return allProductsFromGroup
的子集,动态包含来自同一组的多个结果(多 select 品牌或multi-select 长度),但从其他组(颜色、长度等)中排除?
目标查询可能如下所示:
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
将 and
标准映射到 intersect
,并将 or
标准映射到 union
。它也可能更便宜,因为每个查询都可以在 (key,value) 上寻找索引。
这可能是一个迟到的答案,但如果您可以将条件传递为 JSON,下一个方法也是一个可能的解决方案。 JSON 必须与答案中的格式相同,您可以使用两个以上的条件:
Table:
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
我有一个带有属性的 EAV table,我想根据传递到存储过程中的变量对项目进行混合 selection。
样本table:
| 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 |
我可以在每个 key
的 and
和 or
语句中进行硬编码,但是有很多,我正在寻找更具扩展性的解决方案。
传入并解析JSON就好了,比如:
[
{ "brand": "aplha" },
{ "brand": "beta" },
{ "length": 25 }
]
我如何将第二个 select
写入动态 return allProductsFromGroup
的子集,动态包含来自同一组的多个结果(多 select 品牌或multi-select 长度),但从其他组(颜色、长度等)中排除?
目标查询可能如下所示:
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
将 and
标准映射到 intersect
,并将 or
标准映射到 union
。它也可能更便宜,因为每个查询都可以在 (key,value) 上寻找索引。
这可能是一个迟到的答案,但如果您可以将条件传递为 JSON,下一个方法也是一个可能的解决方案。 JSON 必须与答案中的格式相同,您可以使用两个以上的条件:
Table:
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