1

我设计了一个小数据库,想法是我有一个表 products 并且每个产品都有其类别和动态属性列表(这些属性在另一个表中):

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 |

我做错了什么或者这是不可能的?
据我了解,我在这里得到了一些交叉加入。 在此处输入图像描述

在此处输入图像描述 在此处输入图像描述

4

2 回答 2

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)
于 2013-03-02T15:37:09.017 回答
1

要回答您关于交叉连接的问题,我认为问题在于您没有绑定ProductPropertyValuesCategoryProperties. ProductPropertyValues因此,您可以从每一CategoryProperties行的所有类别中获取所有属性。

现在,就获得您想要的格式而言......这就是所谓的“透视”,因为您想要获取一个垂直列表(所有属性)并“透视”它,水平渲染它。这很难动态完成,因为虽然 SQL Server 确实有一个 PIVOT命令,但它要求您知道在编码时要用于列名的所有值。如果您知道您的属性被称为“Prop 1”、“Prop 2”等,这会起作用,但我认为名称会因产品而异。

你有多大的决心把所有的属性都放在一排?可以做到,但会很复杂。

于 2013-03-02T15:18:54.327 回答