我需要在表中的XML列上执行一个数据透视表,其中XML包含多个具有许多属性的元素。每个元素中的属性始终相同,但元素的数量会有所不同。让我举个例子......
FormEntryId | FormXML | DateCreated
====================================================================================
1 |<Root> | 10/15/2009
| <Form> |
| <FormData FieldName="Username" FieldValue="stevem" /> |
| <FormData FieldName="FirstName" FieldValue="Steve" /> |
| <FormData FieldName="LastName" FieldValue="Mesa" /> |
| </Form> |
|</Root> |
| |
------------------------------------------------------------------------------------
2 |<Root> | 10/16/2009
| <Form> |
| <FormData FieldName="Username" FieldValue="bobs" /> |
| <FormData FieldName="FirstName" FieldValue="Bob" /> |
| <FormData FieldName="LastName" FieldValue="Suggs" /> |
| <FormData FieldName="NewField" FieldValue="test" /> |
| </Form> |
|</Root> |
我需要结束每个不同的FieldName属性值(在本例中为Username,FirstName,LastName和NewField)的结果集,并将其对应的FieldValue属性作为值。我上面给出的例子的结果如下:
FormEntryId | Username | FirstName | LastName | NewField | DateCreated
======================================================================
1 | stevem | Steve | Mesa | NULL | 10/15/2009
----------------------------------------------------------------------
2 | bobs | Bob | Suggs | test | 10/16/2009
我已经找到了使用静态列
实现此目的的方法SELECT
FormEntryId,
FormXML.value('/Root[1]/Form[1]/FormData[@FieldName="Username"][1]/@FieldValue','varchar(max)') AS Username,
FormXML.value('/Root[1]/Form[1]/FormData[@FieldName="FirstName"][1]/@FieldValue','varchar(max)') AS FirstName,
FormXML.value('/Root[1]/Form[1]/FormData[@FieldName="LastName"][1]/@FieldValue','varchar(max)') AS LastName,
FormXML.value('/Root[1]/Form[1]/FormData[@FieldName="NewField"][1]/@FieldValue','varchar(max)') AS NewField,
DateCreated
FROM FormEntry
但是,我想看看是否有一种方法可以根据不同的“FieldName”属性值集使列成为动态。
答案 0 :(得分:4)
查看this dynamic pivot以及最近this one - 您基本上需要能够SELECT DISTINCT FieldName
使用此技术动态构建查询。
以下是您的特定问题的完整答案(请注意,在知道列应显示的顺序时,从不同属性生成列表时存在列顺序弱点:
DECLARE @template AS varchar(MAX)
SET @template = 'SELECT
FormEntryId
,{@col_list}
,DateCreated
FROM FormEntry'
DECLARE @col_template AS varchar(MAX)
SET @col_template = 'FormXML.value(''/Root[1]/Form[1]/FormData[@FieldName="{FieldName}"][1]/@FieldValue'',''varchar(max)'') AS {FieldName}'
DECLARE @col_list AS varchar(MAX)
;WITH FieldNames AS (
SELECT DISTINCT FieldName
FROM FormEntry
CROSS APPLY (
SELECT X.FieldName.value('@FieldName', 'varchar(255)')
FROM FormXML.nodes('/Root[1]/Form[1]/FormData') AS X(FieldName)
) AS Y (FieldName)
)
SELECT @col_list = COALESCE(@col_list + ',', '') + REPLACE(@col_template, '{FieldName}', FieldName)
FROM FieldNames
DECLARE @sql AS varchar(MAX)
SET @sql = REPLACE(@template, '{@col_list}', @col_list)
EXEC (@sql)
答案 1 :(得分:1)
动态数据透视表没有内置于语言中。在结果结构已知之前,有必要扫描包含潜在列名的整个表。因此,动态数据透视表的表结构在运行时之前是未知的。这在解析和解释语言方面产生了许多问题。
如果您决定自己实施动态数据透视,请注意SQL注入机会。请务必将QUOTENAME或等效值应用于计划用作结果中列名的值。如果源中将成为列名的不同值的数量超过结果集的允许列数,还要考虑所需的结果。