您可以这样做,但您需要应用UNPIVOT
命令和动态 SQL。最好将其分为几个步骤:
1)您的表格可以有不同的列。您首先应该获取列列表。所有列都列在sys.columns
表中。以下代码将获取列列表并将其保存为逗号分隔列表。但是,第一列是单独存储的(由于进一步的目的)。
DECLARE @firstColumn NVARCHAR(256)
DECLARE @columnList NVARCHAR(MAX)
SELECT @firstColumn = name
FROM sys.columns
WHERE object_id = OBJECT_ID(@tableName)
AND column_id = 1
SET @columnList = N''
SELECT @columnList = @columnList + name + N','
FROM sys.columns
WHERE object_id = OBJECT_ID(@tableName)
AND column_id > 1
SET @columnList = LEFT(@columnList,LEN(@columnList)-1)
2)您想使用UNPIVOT
(此处的文档)命令使结构更加“程序员友好”。我们需要列的列表来做到这一点。可以使用动态 SQL 来完成(这里的示例)。以下命令完成这项工作:
DECLARE @cmd NVARCHAR(MAX)
SET @cmd = N'INSERT INTO #unPivoted
SELECT id, Matrixes, Facets
FROM
(SELECT ' + @firstColumn + N',' + @columnList + N' FROM ' + @tableName + N') p
UNPIVOT
(Facets FOR Matrixes IN(' + @columnList + N')) AS unpvt
ORDER BY Matrixes,Facets,id'
EXEC sp_executesql @cmd
在您的示例中,它将生成如下结果:
id | Matrixes | Facets
-------------------------
2 | AnotherType | Fimble
1 | AnotherType | Widget
3 | AnotherType | Widget
3 | Type | That
1 | Type | This
2 | Type | This
3)最后一件事是实际的查询。FOR XML AUTO
使用命令就足够了。但是,您应该进行一些嵌套查询以使结构看起来像您想要的那样:
SELECT matrix.name, facet.name, facet.id_count AS count, id.id AS value
FROM
(SELECT DISTINCT Matrixes AS name FROM #unPivoted) matrix
INNER JOIN
(SELECT Matrixes AS matrix_name, Facets AS name, COUNT(id) AS id_count FROM #unPivoted GROUP BY Matrixes, Facets) facet
ON matrix.name = facet.matrix_name
INNER JOIN
(SELECT Facets AS facet_name, id FROM #unPivoted) id
ON facet.name = id.facet_name
ORDER BY matrix.name, facet.name, id.id
FOR XML AUTO
和存储过程。我把所有的 PRINTs 和 SELECTs 留给你看看它是如何工作的(如果描述不够的话)。
CREATE PROCEDURE usp_tableToXML
@tableName NVARCHAR(256)
AS
BEGIN
SET NOCOUNT ON;
-- 1. Get columns from the table
DECLARE @firstColumn NVARCHAR(256)
DECLARE @columnList NVARCHAR(MAX)
SELECT @firstColumn = name
FROM sys.columns
WHERE object_id = OBJECT_ID(@tableName)
AND column_id = 1
SET @columnList = N''
SELECT @columnList = @columnList + name + N','
FROM sys.columns
WHERE object_id = OBJECT_ID(@tableName)
AND column_id > 1
SET @columnList = LEFT(@columnList,LEN(@columnList)-1)
PRINT @firstColumn
PRINT @columnList
-- 2. Unpivot the table
CREATE TABLE #unPivoted
(
id INT,
Matrixes VARCHAR(30),
Facets VARCHAR(30)
)
DECLARE @cmd NVARCHAR(MAX)
SET @cmd = N'INSERT INTO #unPivoted
SELECT id, Matrixes, Facets
FROM
(SELECT ' + @firstColumn + N',' + @columnList + N' FROM ' + @tableName + N') p
UNPIVOT
(Facets FOR Matrixes IN(' + @columnList + N')) AS unpvt
ORDER BY Matrixes,Facets,id'
PRINT @cmd
EXEC sp_executesql @cmd
SELECT * FROM #unPivoted
-- 3. The query
SELECT matrix.name, facet.name, facet.id_count AS count, id.id AS value
FROM
(SELECT DISTINCT Matrixes AS name FROM #unPivoted) matrix
INNER JOIN
(SELECT Matrixes AS matrix_name, Facets AS name, COUNT(id) AS id_count FROM #unPivoted GROUP BY Matrixes, Facets) facet
ON matrix.name = facet.matrix_name
INNER JOIN
(SELECT Facets AS facet_name, id FROM #unPivoted) id
ON facet.name = id.facet_name
ORDER BY matrix.name, facet.name, id.id
FOR XML AUTO
END
GO
EXEC usp_tableToXML 'Types'
顺便说一句,我猜你在你的 XML 结构中犯了一个小错误。不应该是这样(facet
标签应该在ids之后关闭吗?):
<matrix name="AnotherType">
<facet name="Fimble" count="1">
<id value="2" />
</facet>
<facet name="Widget" count="2">
<id value="1" />
<id value="3" />
</facet>
</matrix>
<matrix name="Type">
<facet name="That" count="1">
<id value="3" />
</facet>
<facet name="This" count="2">
<id value="1" />
<id value="2" />
</facet>
</matrix>