Sql 如何处理从数据库中选择动态属性
我设计了一个小数据库,其想法是我有一个表products,每个产品都有其类别和动态属性列表(这些属性在另一个表中): 我在这里绑定某个类别的产品。现在,每个ProductCategory都与另一个表相关,我可以在其中为该类别添加属性:Sql 如何处理从数据库中选择动态属性,sql,sql-server,tsql,pivot,Sql,Sql Server,Tsql,Pivot,我设计了一个小数据库,其想法是我有一个表products,每个产品都有其类别和动态属性列表(这些属性在另一个表中): 我在这里绑定某个类别的产品。现在,每个ProductCategory都与另一个表相关,我可以在其中为该类别添加属性: CategoryProperties{CategoryPropertyId, ProductCategoryId, Name} 每个属性的值在此表中: ProductPropertyValues{ProductId, CategoryPropertyId, Va
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 |
| Product name | Manufacturer | Category | prop1 | prop2 | prop3| Prop4 |
| some product name | RedBull | Can | 34 | something | 45.6 | something else |
但是我想获得和这个产品类别的所有相关属性,这就是问题所在。当我尝试此查询时:
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'结果。
我不知道我做错了什么。
我希望得到如下结果:
| some product name | RedBull | Can |
| Product name | Manufacturer | Category | prop1 | prop2 | prop3| Prop4 |
| some product name | RedBull | Can | 34 | something | 45.6 | something else |
我做错了什么,或者这是不可能的?据我所知,这里有些交叉连接。
为了回答您关于交叉连接的问题,我认为问题在于您没有将
产品属性值
绑定到类别属性
。因此,您可以从ProductPropertyValues
中获取每个CategoryProperty
行的所有类别的所有属性
现在,只要得到你想要的格式。。。这被称为“透视”,因为您希望获取一个垂直列表(所有属性)并“透视”它,水平呈现它。这很难动态完成,因为尽管SQL Server有一个PIVOT
命令,但它要求您知道编码时要用于列名的所有值。如果你知道你的财产被称为“1号道具”、“2号道具”等,那就行了,但我认为这些名称会因产品而异
您如何确定将所有属性都放在一行中?这是可以做到的,但会很复杂 听起来好像您正试图
透视数据。这将获取行值并将其转换为列
如果要转换一组属性,则可以将查询硬编码为类似以下内容:
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
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)
如果有未知数量的值,它会变得更困难。您必须使用动态sql来执行此操作。我向您展示了一个静态版本,因为它更容易从硬编码版本转移到动态解决方案
动态版本的关键是获取列名。完整脚本将类似于以下内容:
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
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)
关于交叉连接,你是对的。我现在更改了查询,它返回11行。这正是我拥有的那类房产的数量。那部分是固定的,但我真的需要它在一排。我一整天都在苦苦挣扎:(@1110)你想展示的房产最多是多少?还是“不管有多少”?所有属性。所以第二个。@1110我本来想把你链接到上面bluefeet之前的一篇文章,但看起来他给了你相同的答案,是根据你的情况定制的。我可能会做得稍有不同,但想法是一样的。这是否意味着每个属性名称都必须有Prop
前缀?@1110不,我是创建名为Prop_
的列,然后在每个列的末尾附加一个行号值。因此,如果您有5个属性,那么您将有名为Prop_1
、Prop_2
等的列。我已经创建了一个表结构,您可以为一些示例数据和n在注释中发布新创建的架构链接?这将更容易与您的数据一起显示。在动态查询中,我在关键字“on”附近得到了不正确的语法:
fot this line)t on p.ProductId
我现在尝试了它。但是我没有得到好的结果。我得到11行,但所有属性都有相同的值:(我用结果的图像更新了问题。@1110请参见我的编辑。您需要将cp.Name
值转换为列。我已更新了脚本。