如何在SQL Server FOR XML中使用xml类型值函数

时间:2017-05-18 17:37:28

标签: sql-server xml

有没有办法让函数像对象一样工作?

例如:我有一个类似xml的函数:

CREATE FUNCTION dbo.CompanyXml(@id int) RETURNS XML 
AS 
BEGIN 
    RETURN (SELECT id AS [@id], name AS [@name] FROM Companies WHERE id = @id 
    FOR XML PATH('CompanyType'),TYPE)
END

当我使用该功能时:

SELECT dbo.CompanyXml(1) AS Supplier,
    dbo.CompanyXml(2) AS Client
FOR XML PATH('Document'), TYPE

我明白了:

<Document>
  <Supplier>
    <CompanyType id="1" name="Company 1" />
  </Supplier>
  <Client>
    <CompanyType id="2" name="Company 2" />
  </Client>
</Document>

但我需要:

<Document>
  <Supplier id="1" name="Company 1" />
  <Client id="2" name="Company 2" />
</Document>

有没有办法实现这个目标?

[更新]我的解决方案

(受@Shnugo启发)

我使用了表值函数FOR XML AUTO

CREATE FUNCTION dbo.CompanyTbl(@id int) RETURNS TABLE 
AS SELECT id, name FROM Companies WHERE id = @id

像这样使用

SELECT (SELECT * FROM dbo.CompanyTbl(1) AS Supplier FOR XML AUTO, TYPE),
       (SELECT * FROM dbo.CompanyTbl(2) AS Client FOR XML AUTO, TYPE)
FOR XML PATH('Document'), TYPE

2 个答案:

答案 0 :(得分:1)

别名AS SupplierAS Client是结果集中特定列的标题。您呼叫的功能不知道(并且无法知道),其结果将显示为供应商或客户......

使用FOR XML PATH() 元素的名称必须是文字

有三种方法,我选择最后一种方法:

  1. 您可以使用像Kannan Kandasamys建议的修改功能,但每个角色需要一个部分,您必须将“type”作为参数提交。更多角色需要修改功能。部署的数据库可能很难......

  2. 您可以在字符串级别创建xml(类似'<' + @element + id="' + ...),然后使用CAST(... AS XML)。在这种情况下,请注意如何处理特殊字符!

  3. (我的选择):为每个文档角色引入一个单独的函数。新角色是新功能,在大多数情况下更容易

  4. 对于Nr 3,您的代码看起来像

    SELECT dbo.SupplierXml(1) AS [*],
           dbo.ClientXml(2) AS [*]
    FOR XML PATH('Document'), TYPE;
    

    更新另一种方法:FOR XML AUTO

    试试这个:

    CREATE DATABASE TestDB;
    GO
    USE TestDB;
    GO
    CREATE TABLE TestTable(id INT,SomeOther VARCHAR(100));
    INSERT INTO TestTable VALUES(1,'Some 1'),(2,'Some 2');
    
    SELECT * FROM TestTable FOR XML AUTO;
    

    - 结果:您看,表名是元素的名称:

    <TestTable id="1" SomeOther="Some 1" />
    <TestTable id="2" SomeOther="Some 2" />
    

    - 很好,您可以使用表别名强制使用此名称:

    SELECT * FROM TestTable AS OtherName FOR XML AUTO;
    

    - 返回

    <OtherName id="1" SomeOther="Some 1" />
    <OtherName id="2" SomeOther="Some 2" />
    
    GO
    USE master;
    GO
    DROP DATABASE TestDB;
    

    现在不好的是,那个 - 再次 - 别名必须是文字,不能作为参数传入。它不是可内联的,但您可以执行类似

    的操作
    DECLARE @cmd VARCHAR(1000)='SELECT * FROM YourTable AS ' + @alias + ' FOR XML AUTO';
    EXEC (@cmd);
    

    当谈到动态设置列名(同样适用于元素名称)时,你必须使用一些丑陋的技巧......

答案 1 :(得分:0)

您可以更改以下功能:

CREATE FUNCTION dbo.CompanyXml1(@id int, @type varchar(15)) RETURNS XML 
AS 
BEGIN 
    if @type = 'Supplier' 
    begin
        return(
            SELECT id AS [@id], name AS [@name] FROM Companies WHERE id = @id 
            FOR XML PATH('Supplier'),TYPE )
    end
    else
    begin
        return(
                SELECT id AS [@id], name AS [@name] FROM Companies WHERE id = @id 
            FOR XML PATH('Client'),TYPE
            )
    end 
    return(null);       
END

您的查询如下:

SELECT dbo.CompanyXml1(1, 'Supplier'),
    dbo.CompanyXml1(2, 'Client') 
FOR XML PATH('Document'), TYPE

输出......:

<Document>
  <Supplier id="1" name="Company 1" />
  <Client id="2" name="Company 2" />
</Document>