【问题标题】:Execute Arbitrary SQL Command and Return XML in Azure SQL Database?在 Azure SQL 数据库中执行任意 SQL 命令并返回 XML?
【发布时间】:2012-06-16 20:05:28
【问题描述】:

我正在研究是否可以执行任意 SQL 命令(动态 SQL 语句或存储过程)并将结果作为 XML 返回,在 Azure SQL 数据库中

我知道可以使用常规的本地 SQL Server 数据库来完成 - 在我们的例子中,我们使用 CLR 函数。替代“常规”解决方案包括使用 OPENROWSET 或 OPENQUERY,这两种方法都不适用于 Azure。

自 SQL Server 2012 起提供了一个新的 EXECUTE ... AS FOR XML 选项,但当我尝试它时出现错误 - 我无法找到正确的使用示例。

exec ('select ''A'', 2, ''d''')
with result sets (as for xml)

返回

消息 11537,第 16 级,状态 1,第 1 行 EXECUTE 语句失败,因为它的 WITH RESULT SETS 子句为结果集编号 1 指定了 1 列,但该语句在运行时发送了 3 列。

明确说明;我无法控制正在传递的命令 - 它很可能是一个存储过程,并且很可能返回一个“常规”(即非 xml)结果集。用例是一组 SQL 测试,而不是实际的生产代码。

【问题讨论】:

  • 我现在无法确认以下内容,但这里有一个想法:SQL 数据库以向后兼容模式运行; Azure 中的数据库设置为与 SQL 2008 R2 兼容 - 这可能解释了为什么它可以在本地 SQL 2012 机器上运行,但不能在 Azure 中运行。
  • Herve - 实际上 SQL Azure 的 DB 版本是 Microsoft SQL Azure (RTM) - 11.0.1944.0 May 24 2012 03:22:34 - 这是 SQL 2012 版本。如果我上面的选择只有一个列,它会起作用 - 正确的答案是我对 AS FOR XML 的理解不正确 - 请参阅下面接受的答案中的史蒂夫霍华德的声明。
  • Oskar - 我不是指 SQL 引擎的版本,它确实是 SQL 2012。我指的是数据库的兼容模式。您所要做的就是运行此语句,您将看到 Azure 中的数据库实际上在模式 100 下运行,即 SQL 2008:SELECT compatibility_level, name FROM sys.databases - 这是讨论兼容模式的文章:@987654322 @
  • @Herve - 嗯 - 我不知道,谢谢你的信息!

标签: sql xml azure-sql-database sql-server-2012


【解决方案1】:

我从微软客户咨询团队的高级项目经理 Steve Howard 那里找到了一个权威的答案:

AS FOR XML 不会将非 XML 表格结果从 将执行的语句或存储过程转换为 XML。 AS FOR XML 指定 XML 结果 来自语句或存储 EXECUTE 语句调用的过程将被转换为 格式,就好像它们是由 SELECT ... FOR XML ... 语句生成的一样。全部 原始语句中类型指令的格式将是 删除,返回的结果就像没有类型指令一样 指定的。

但他也为我提供了这种选择:

/*
       Demo of how to display results from a stored procedure in XML
       Author: Steve Howard
       Date: June 21, 2012
       Intended as a demo only. Adapt to your purposes

*/

-- for this demo, declare a variable @tsql_batch to hold the batch to be executed
-- note that this could become a parameter in a stored procedure if this is how this is used

declare @tsql_batch  nvarchar(4000)

-- set the variable for the demo only
-- you will need to set this in your testing

set @tsql_batch = N'exec forDemo'

-- declare a table to hold the results of sp_describe_first_result_set
-- note that this can also be used for multiple result sets. See the documentation
-- at: http://technet.microsoft.com/en-us/library/ff878602(v=sql.110).aspx
declare @resultDescription table
(
       is_hidden                                       bit                        null
,      column_ordinal                                  int                        not null primary key
,      name                                            sysname                    not null
,      is_nullable                                     bit                        null
,      system_type_id                                  int                        null
,      system_type_name                         nvarchar(256) null
,      max_length                                      smallint             null
,      precision                                       tinyint                    null
,      scale                                           tinyint                    null
,      collation_name                                  sysname                    null
,      user_type_id                             int                        null
,      user_type_database                       sysname                    null
,      user_type_schema                         sysname                    null
,      user_type_name                                  sysname                    null
,      assembly_qualified_type_name      nvarchar(4000)       null
,      xml_collection_id                        int                        null
,      xml_collection_database                  sysname                    null
,      xml_collection_schema                    sysname                    null
,      xml_collection_name                      sysname                    null
,      is_xml_document                                 bit                        null
,      is_case_sensitive                        bit                        null
,      is_fixed_length_clr_type          bit                        null
,      source_server                            sysname                    null
,      source_database                                 sysname                    null
,      source_schema                            sysname                    null
,      source_table                             sysname                    null
,      source_column                            sysname                    null
,      is_identity_column                       bit                        null
,      is_part_of_unique_key                    bit                        null
,      is_updateable                            bit                        null
,      is_computed_column                       bit                        null
,      is_sparse_column_set              bit                        null
,      ordinal_in_order_by_list          smallint             null
,      order_by_list_length              smallint             null
,      order_by_is_descending                   smallint             null
,      tds_type_id                                     int                        null
,      tds_length                                      int                        null
,      tcs_collation_id                         int                        null
,      tds_collation_sort_id                    tinyint                    null
)

-- populate the table variable
insert into @resultDescription
       exec sp_describe_first_result_set @tsql_batch

-- declare the cursor to create the "create table statement:
declare crs cursor for SELECT '[' + name + '] ' + system_type_name + ' ' + case is_nullable when 0 then 'not null ' else 'null ' end + '
' FROM @resultDescription order by column_ordinal asc

-- variables to hold the statement to be executes as well as the current value from the cursor
declare @exec NVARCHAR(4000)
declare @curVal      nvarchar(1000)
open crs
fetch next from crs into @curval
-- begin building the dynamic SQL statement to be executed
set @exec = 'DECLARE @temp TABLE 
(
' + @curval

fetch next from crs into @curval

while @@FETCH_STATUS = 0
begin
       set @exec = @exec + ', ' + @curVal
       fetch next from crs into @curVal
end
close crs
deallocate crs
set @exec = @exec + '
)


INSERT INTO @temp
       exec sp_executesql N''' + @tsql_batch + '''

SELECT * FROM @temp FOR XML AUTO

' 


-- get the results
exec (@exec)


-- of you want to just see the statement that was executed:

print @exec

【讨论】:

    【解决方案2】:

    基于使用“FOR XML AUTO TYPE”对 SQL Azure Table 进行的快速测试,确实以 XML 格式返回结果,所以我相信您肯定可以得到 XML 格式的结果,但并非每个查询都可以返回为 XML,这需要考虑.

    获得完整/正确格式的 XML 有点困难,因此您可能想看看这些articles 和这个one

    【讨论】:

    • 对不起,我不太明白 - 你把 FOR XML AUTO TYPE 语句放在哪里?请记住,上面的“select ...”语句在执行时对我来说是未知的,它更有可能是一个要执行的存储过程。
    【解决方案3】:

    要输出简单(即无类型的 XML),您可以使用如下所示的“for XML”子句。

    不支持类型化 XML 和 XML 索引。 Windows Azure SQL 数据库支持 XML 数据类型。

    我在 SQL Azure 中使用此示例测试了您的场景,效果很好:

    --Create the procedure
    CREATE PROC SalesLT.ProductList @ProdName nvarchar(50)
    AS
    -- First result set
    SELECT ProductID, Name, ListPrice
        FROM SalesLT.Product
        WHERE Name LIKE @ProdName
        FOR XML AUTO;
    -- Second result set 
    SELECT Name, COUNT(S.ProductID) AS NumberOfOrders
        FROM SalesLT.Product AS P
        JOIN SalesLT.SalesOrderDetail AS S
            ON P.ProductID  = S.ProductID 
        WHERE Name LIKE @ProdName
        GROUP BY Name
        FOR XML AUTO;
    GO
    
    -- Execute the procedure 
    EXEC SalesLT.ProductList '%tire%'
    

    【讨论】:

    • Lynn,问题不只是从我可以编辑的 SELECT 语句返回 XML - 问题是从 EXEC 语句返回 XML。 SQL 2012 有一个新的 AS FOR XML 选项,但除了 msdn.microsoft.com/en-us/library/ms188332.aspx 之外,很难找到文档
    • Lynn,感谢您继续查看此内容,但又一次 - 原始存储过程(我无法控制)不返回 XML。问题的关键是如何在 SQL 2012 中使用 EXECUTE 的 AS FOR XML 选项。您的代码在 SELECT 上显示了传统的 FOR XML 选项。
    猜你喜欢
    • 2013-08-24
    • 1970-01-01
    • 2014-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多