我设计了一个小数据库的想法是我有一个表产品,每个产品都有它的类别和动态属性列表(这些属性在另一个表中):
ProductCategories{ProductCategoryId, Name}
Products{ProductId, Name, ProductCategoryId}
我在这里绑定某个类别的产品。现在,每个ProductCategory都与另一个表相关,我可以在其中添加该类别的属性:
CategoryProperties{CategoryPropertyId, ProductCategoryId, Name}
每个属性的值都在此表中:
ProductPropertyValues{ProductId, CategoryPropertyId, Value}
问题出在我执行查询时:
select p.Name as ProductName, m.Name as Manufacturer, pc.Name as Category
from products p
left join dbo.Manufacturers m
on p.ManufactureId = m.ManufactureId
left join dbo.ProductCategories pc
on p.ProductCategoryId = pc.ProductCategoryId
这给我的结果如下:
| some product name | RedBull | Can |
但我希望获得产品类别的所有相关属性,这就是问题所在。当我尝试这个查询时:
select p.Name as ProductName, m.Name as Manufacturer, pc.Name as Category, cp.Name, ppv.Value
from products p
left join dbo.Manufacturers m
on p.ManufactureId = m.ManufactureId
left join dbo.ProductCategories pc
on p.ProductCategoryId = pc.ProductCategoryId
left join dbo.CategoryProperties cp
on pc.ProductCategoryId = cp.ProductCategoryId
left join dbo.ProductPropertyValues ppv
on p.ProductId = ppv.ProductId
在结果中查询而不是一行之后,我得到'121'结果。 我不知道我做错了什么。 我希望得到如下结果:
| Product name | Manufacturer | Category | prop1 | prop2 | prop3| Prop4 |
| some product name | RedBull | Can | 34 | something | 45.6 | something else |
我做错了什么或者这是不可能的?
据我所知,我在这里得到一些交叉加入。
答案 0 :(得分:2)
听起来您正在尝试PIVOT
数据。这将获取行值并将其转换为列。
如果您要转换一定数量的属性,那么您可以将查询硬编码为类似于此的内容:
select *
from
(
select p.Name as ProductName,
m.Name as Manufacturer,
pc.Name as Category,
cp.Name,
ppv.Value
from products p
left join dbo.Manufacturers m
on p.ManufactureId = m.ManufactureId
left join dbo.ProductCategories pc
on p.ProductCategoryId = pc.ProductCategoryId
left join dbo.CategoryProperties cp
on pc.ProductCategoryId = cp.ProductCategoryId
left join dbo.ProductPropertyValues ppv
on p.ProductId = ppv.ProductId
and cp.CategoryPropertyId = ppv.CategoryPropertyId
) src
pivot
(
max(value)
for Name in ([Code], [Data], etc)
) piv
如果您的数值未知,则会变得更加困难。您将不得不使用动态SQL来执行此操作。我向您展示了一个静态版本,因为它更容易从硬编码版本转移到动态解决方案。
动态版本的关键是获取列名称。完整的脚本将类似于:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(name)
from dbo.CategoryProperties
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT ProductName, Manufacturer, Category,' + @cols + ' from
(
select p.Name as ProductName,
m.Name as Manufacturer,
pc.Name as Category,
cp.Name,
ppv.Value
from products p
left join dbo.Manufacturers m
on p.ManufactureId = m.ManufactureId
left join dbo.ProductCategories pc
on p.ProductCategoryId = pc.ProductCategoryId
left join dbo.CategoryProperties cp
on pc.ProductCategoryId = cp.ProductCategoryId
left join dbo.ProductPropertyValues ppv
on p.ProductId = ppv.ProductId
and cp.CategoryPropertyId = ppv.CategoryPropertyId
) x
pivot
(
max(value)
for Name in (' + @cols + ')
) p '
execute(@query)
答案 1 :(得分:1)
要回答有关交叉加入的问题,我认为问题在于您没有将ProductPropertyValues
绑定回CategoryProperties
。因此,对于每个ProductPropertyValues
行的所有类别,您都会获得CategoryProperties
的所有属性。
现在,只要获得你想要的格式......这就是所谓的“旋转”,因为你想要一个垂直列表(所有属性)并“转动”它,水平渲染它。这很难动态执行,因为虽然SQL Server确实有PIVOT
命令,但它要求您知道在编码时用于列名的所有值。如果您知道您的属性被称为“Prop 1”,“Prop 2”等,那么这将起作用,我认为名称因产品而异。
您如何确定将所有属性放在一行中?它可以做到,但它会变得复杂。