我需要创建一个存储过程,它返回产品特征及其产品数量。输入参数为:
- 产品类别。查询必须返回此特定类别及其子类别的数据
- 选定的产品特性 - 表值参数。如果此参数包含行,则查询必须计算也具有此特定特征的产品的每个特征的产品计数。
问题:
- 数据库包含 500 000 多个产品行,那么就性能而言,最佳解决方案(t-sql 查询)是什么?
- 我尝试进行如下所示的查询,但我认为它很难看,而且实际上无法正确计算产品数量。我需要专业的帮助来尽快做出正确的查询
表脚本和示例数据:
--categories
create table tCategory(c_id int identity(1,1) primary key, c_name nvarchar(200), c_parent int)
insert into tCategory(c_name, c_parent) select 'Smartphones', null
insert into tCategory(c_name, c_parent) select 'iPhone 6S', 1
insert into tCategory(c_name, c_parent) select 'iPhone 7', 1
insert into tCategory(c_name, c_parent) select 'iPhone 7 Plus', 1
--products
create table tProduct(p_id int identity(1,1) primary key, p_name nvarchar(200), c_id int)
insert into tProduct(p_name, c_id) select '4.7" Apple iPhone 6S 32 gb gold', 2
insert into tProduct(p_name, c_id) select '4.7" Apple iPhone 6S 32 gb brown', 2
insert into tProduct(p_name, c_id) select '4.7" Apple iPhone 7 32 gb pink', 3
insert into tProduct(p_name, c_id) select '4.7" Apple iPhone 7 32 gb brown', 3
insert into tProduct(p_name, c_id) select '5.5" Apple iPhone 7 Plus 32 gb black', 4
insert into tProduct(p_name, c_id) select '4.7" Apple iPhone 6S 128 gb pink', 2
--characteristics type (color, size etc.)
create table tProductCharItem(pci_id int identity(1,1) primary key, pci_name nvarchar(200))
insert into tProductCharItem(pci_name) select 'Display'
insert into tProductCharItem(pci_name) select 'Color'
insert into tProductCharItem(pci_name) select 'Memory'
--characteristics value (blue, 50х50 etc.)
create table tProductCharItemValue(pciv_id int identity(1,1) primary key, pci_id int, pciv_value nvarchar(50))
insert into tProductCharItemValue(pci_id, pciv_value) select 1, '4.7"'
insert into tProductCharItemValue(pci_id, pciv_value) select 1, '5.5"'
insert into tProductCharItemValue(pci_id, pciv_value) select 2, 'gold'
insert into tProductCharItemValue(pci_id, pciv_value) select 2, 'brown'
insert into tProductCharItemValue(pci_id, pciv_value) select 2, 'pink'
insert into tProductCharItemValue(pci_id, pciv_value) select 2, 'black'
insert into tProductCharItemValue(pci_id, pciv_value) select 3, '32 gb'
insert into tProductCharItemValue(pci_id, pciv_value) select 3, '128 gb'
--products characteristics
create table tProductChar(pc_id int identity(1,1) primary key, p_id int, pciv_id int)
insert into tProductChar(p_id, pciv_id) select 1, 1
insert into tProductChar(p_id, pciv_id) select 1, 7
insert into tProductChar(p_id, pciv_id) select 1, 3
insert into tProductChar(p_id, pciv_id) select 2, 1
insert into tProductChar(p_id, pciv_id) select 2, 4
insert into tProductChar(p_id, pciv_id) select 2, 7
insert into tProductChar(p_id, pciv_id) select 3, 1
insert into tProductChar(p_id, pciv_id) select 3, 5
insert into tProductChar(p_id, pciv_id) select 3, 7
insert into tProductChar(p_id, pciv_id) select 4, 1
insert into tProductChar(p_id, pciv_id) select 4, 4
insert into tProductChar(p_id, pciv_id) select 4, 7
insert into tProductChar(p_id, pciv_id) select 5, 2
insert into tProductChar(p_id, pciv_id) select 5, 6
insert into tProductChar(p_id, pciv_id) select 5, 7
insert into tProductChar(p_id, pciv_id) select 6, 1
insert into tProductChar(p_id, pciv_id) select 6, 5
insert into tProductChar(p_id, pciv_id) select 6, 8
用户未选择任何过滤器时的预期结果:
+--------+---------+----------+------------+----------------+
| pci_id | pciv_id | pci_name | pciv_value | products_count |
+--------+---------+----------+------------+----------------+
| 1 | 1 | Display | 4.7" | 5 |
| 2 | 3 | Color | gold | 1 |
| 2 | 4 | Color | brown | 2 |
| 2 | 5 | Color | pink | 2 |
| 2 | 6 | Color | black | 1 |
| 3 | 7 | Memory | 32 gb | 5 |
| 3 | 8 | Memory | 128 gb | 1 |
| 1 | 2 | Display | 5.5" | 1 |
+--------+---------+----------+------------+----------------+
用户按颜色特征“棕色”选择过滤器时的预期结果
+--------+---------+----------+------------+----------------+
| pci_id | pciv_id | pci_name | pciv_value | products_count |
+--------+---------+----------+------------+----------------+
| 1 | 1 | Display | 4.7" | 2 |
| 2 | 3 | Color | gold | 0 |
| 2 | 4 | Color | brown | 2 |
| 2 | 5 | Color | pink | 0 |
| 2 | 6 | Color | black | 0 |
| 3 | 7 | Memory | 32 gb | 2 |
| 3 | 8 | Memory | 128 gb | 0 |
| 1 | 2 | Display | 5.5" | 0 |
+--------+---------+----------+------------+----------------+
这是我的尝试(丑陋且无法正确计算产品数量):
CREATE TYPE integer_list_tbltype AS TABLE (n int NOT NULL PRIMARY KEY)
declare @c_id int = 1 --category id
declare @pciv_ids integer_list_tbltype --list of selected filters (products characteristics)
insert into @pciv_ids(n) select 4
;with cats as
(
select c_id from tCategory where c_id = @c_id
union all
select t.c_id from cats
inner join tCategory t on cats.c_id = t.c_parent
),
groupped_pci as (
select distinct p.c_id, pci.pci_id, pciv.pciv_id
from tProductChar pc
join tProduct p on pc.p_id = p.p_id
join tProductCharItemValue pciv on pc.pciv_id = pciv.pciv_id
join tProductCharItem pci on pciv.pci_id = pci.pci_id),
products_count as (
select count(distinct p.p_id) cnt, pc.pciv_id
from tProduct p join tProductChar pc on p.p_id = pc.p_id
cross apply (select * from tProductChar pc left join @pciv_ids t on pc.pciv_id = t.n where p_id = p.p_id and pc.pciv_id is not null) t
group by pc.pciv_id
)
select pci.pci_id, pciv.pciv_id, pci.pci_name, pciv.pciv_value, pc.cnt products_count
from groupped_pci
join cats on cats.c_id = groupped_pci.c_id
join tProductCharItem pci on groupped_pci.pci_id = pci.pci_id
join tProductCharItemValue pciv on groupped_pci.pciv_id = pciv.pciv_id
left join products_count pc on groupped_pci.pciv_id = pc.pciv_id
最佳答案
这就是我会做的以避免子查询:
declare @filters table (pciv_id int)
insert into @filters(pciv_id) values (4)
if exists (select * from @filters)
set @hasFilter=1
;with cats as
(
select c_id from tCategory where c_id = @c_id
union all
select t.c_id from cats
inner join tCategory t on cats.c_id = t.c_parent
)
, filteredProducts as
(
select p.p_id
from cats
inner join tProduct p on p.c_id=cats.c_id
inner join tProductChar pc on pc.p_id=p.p_id
inner join tProductCharItemValue pcv on pcv.pciv_id=pc.pciv_id
left join @filters f on f.pciv_id=pc.pciv_id
where @hasFilter=0 or f.pciv_id is not null
group by p.p_id
)
select ci.pci_id, pcv.pciv_id, ci.pci_name, pcv.pciv_value, count(p.p_id) products_count
from tProductCharItem ci
inner join tProductCharItemValue pcv on pcv.pci_id=ci.pci_id
left join tProductChar pc on pc.pciv_id=pcv.pciv_id
left join filteredProducts p on p.p_id=pc.p_id
group by ci.pci_id, pcv.pciv_id, ci.pci_name, pcv.pciv_value
关于sql - 在线商店产品过滤器的 T-SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63147609/