0

我需要将表转换为带有值计数的 XML。

例如

Table
Id , Type, AnotherType
1, This, Widget
2, This, Fimble
3, That, Widget

我想要这样的输出。这需要是动态的,因此添加的新列或构面将生成这种类型的输出。

<matrix name="Type">
 <facet name = "this" count=2>
   <id value = 1></id>
   <id value = 2></id>
 </facet>     
 <facet name = "that" count=1>
   <id value = 3></id>
 </facet>
</matrix>
<matrix name="AnotherType">
 <facet name = "Widget" count=2>
   <id value = 1></id>
   <id value = 3></id>
 </facet>
 <facet name = "Fimble" count=1>
   <id value = 2></id>
 </facet>
</matrix>

这可能吗?

如果列/值发生变化,我想要一个处理该问题的解决方案 - 例如,它将生成一个新的矩阵和依赖于数据的事实。

4

3 回答 3

2

您可以这样做,但您需要应用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>
于 2009-12-11T12:32:18.070 回答
0

如果您有 SQL Server 2005 或更高版本,您可以这样

于 2009-12-08T08:35:01.987 回答
0

请看这里:CTE 和 Hierarchical XML Result。您可以忽略 XSLT 部分而只使用 XML。

编辑:似乎它有点诡计。请看这里:SQL XML output to populate a treeview,因为它使用纯 TSQL CTE 指令来生成您的分层 XML。

于 2009-12-08T08:46:25.457 回答