SQL Server各种存储过程临时表结果为JSON

时间:2015-11-18 11:13:15

标签: sql-server json tsql stored-procedures

这有点复杂,因为它需要从一开始就知道很少,除了每个存储过程返回一个数据集(这是一个临时表)。

我无法使用OPENQUERY或OPENROWSET

我正在使用SQL Server 2012

我想做的是有一个单一的入口点,它为我建立了一个字符串。

CREATE PROCEDURE BuildMeAString (@spname varchar(30))
AS

  -- select results from a stored procedure

  SELECT * INTO #temp FROM @spname

  -- get the column names to build the first record of the JSON string

  -- loop through the rows and build a JSON string for each row

GO

我喜欢这种方式,所以我可以更改任何被调用的存储过程,而无需以标准方式格式化

这甚至可能吗?

2 个答案:

答案 0 :(得分:0)

CREATE PROCEDURE BuildMeAString (@spname varchar(30))
AS

  -- select results from a stored procedure

  exec('SELECT * INTO #temp FROM ' + @spname + '


  SELECT * FROM #temp -- <-- do here what ever process you want.
  ')

如果使用动态查询,那应该相当容易。

LE:

以下是从临时表中选择列的查询。

ALTEr PROCEDURE BuildMeAString (@spname varchar(30))
AS

  -- select results from a stored procedure  SELECT * FROM #temp -- <-- do here what ever process you want.

  exec('SELECT * INTO #temp FROM ' + @spname + '



  SELECT 
    c.name,
    t.Name,
    c.max_length,
    c.precision    
    FROM    
     tempdb.sys.columns c
    INNER JOIN 
      tempdb.sys.types t ON c.user_type_id = t.user_type_id
    LEFT OUTER JOIN 
      tempdb.sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id
    LEFT OUTER JOIN 
      tempdb.sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
    WHERE
    c.object_id = OBJECT_ID(''tempdb..#temp'')
  ')

答案 1 :(得分:0)

实现此动态的唯一方法,尤其是在处理存储过程的结果集时,是使用以下方法之一:

你说你不能使用前两个,所以离开SQLCLR,sys.dm_exec_describe_first_result_set + CONCAT(技术上CONCAT不是必需的,但它会使这个有点更容易)。

SQLCLR可能最适合此类操作,因为它允许您:

  • 完全跳过临时表,
  • 在数据的同时获取列名(由于此方法中没有临时表,因此不需要列数据类型)

使用这种方法你会:

  • 创建要执行的存储过程的SqlCommand(或任何查询,实际上)
  • 调用ExecuteReader()
  • SqlCommand方法
  • 调用SqlDataReaderGetName()GetSchemaTable()方法获取列名称
  • Read()循环中调用SqlDataReader的{​​{1}}方法以获取每一行
  • 在循环中构造JSON,为每个字段调用while
  • 将JSON文档构建为GetValue(ordinal).ToString()

如果不使用SQLCLR,则需要将存储过程的结果集存储到临时表中,以便在从临时表中选择数据时对其进行变换/格式化。

使用这种方法你会:

  • 调用StringBuilder以获取字段名称和数据类型
  • 构建一个动态SQL字符串,它既可以创建表变量,也可以创建sys.dm_exec_describe_first_result_set语句(也在内部动态SQL上下文中),从表变量中获取数据并将其格式化为JSON。
  • 通过SELECT调用动态SQL,以便将生成的JSON字符串传递回外部/当前SQL上下文。
sp_executesql

测试:

CREATE PROCEDURE dbo.GetJSONfromResultSet
(
  @Query NVARCHAR(MAX),
  @JSON NVARCHAR(MAX) OUTPUT,
  @TestMode BIT = 0
)
AS
SET NOCOUNT ON;

DECLARE @CRLF NCHAR(2) = NCHAR(0x0D) + NCHAR(0x0A);
DECLARE @SQL NVARCHAR(MAX) = N'SET NOCOUNT ON;
DECLARE @CRLF NCHAR(2) = NCHAR(0x0D) + NCHAR(0x0A);
DECLARE @TempData TABLE (',
        @Concat NVARCHAR(MAX) = N'SET @Output = N''''; -- declared by sp_executesql call
SELECT @Output += CONCAT(@CRLF, N''{'', @CRLF,';

SELECT @SQL += @CRLF + N'[' + cols.name + N'] ' +
               ISNULL(cols.user_type_name, cols.system_type_name) +
               IIF(cols.is_nullable = 0, N' NOT', N'') + N' NULL,',
       @Concat += @CRLF + N'N''   "' + cols.name + N'": ' +
       N'"'', ' + cols.name + N', N''"' + -- make this a CASE to handle string vs number
       N','', @CRLF,'
FROM   sys.dm_exec_describe_first_result_set(@Query, NULL, NULL) cols
ORDER BY cols.column_ordinal;

SET @SQL = LEFT(@SQL, LEN(@SQL) - 1);
SET @SQL += @CRLF + N');' + @CRLF + @CRLF;
SET @SQL += N'INSERT INTO @TempData' + @CRLF;
SET @SQL += N'  ' + @Query + N';' + @CRLF + @CRLF;

SET @Concat = STUFF(@Concat, LEN(@Concat) - 9, 1, N'');
SET @Concat += @CRLF + N'N''},'')' + @CRLF;
SET @Concat += N'FROM @TempData;' + @CRLF;
SET @Concat += N'SET @Output = LEFT(@Output, LEN(@Output) - 1);' + @CRLF + @CRLF;

--SET @Concat += N'PRINT @Output;' + @CRLF; -- optional inner debug

SET @SQL += @Concat;

IF (@TestMode = 1)
BEGIN
  PRINT @SQL;
END;
ELSE
BEGIN
  EXEC sp_executesql
    @SQL,
    N'@Output NVARCHAR(MAX) OUTPUT',
    @Output = @JSON OUTPUT;
END;
GO

因此,这在纯T-SQL中有效,但如果您使用的是SQL Server 2005,2008或2008 R2则不行。 DECLARE @SQL NVARCHAR(MAX) = N'SELECT TOP(5) * FROM sys.objects'; EXEC dbo.GetJSONfromResultSet @SQL, N'', 1 GO DECLARE @SQL NVARCHAR(MAX) = N'SELECT TOP(5) * FROM sys.objects', @JSONout NVARCHAR(MAX); EXEC dbo.GetJSONfromResultSet @SQL, @JSON = @JSONout OUTPUT; SELECT @JSONout; PRINT @JSONout; 有一整套限制,例如不处理用户临时表或动态SQL等存储过程.SQLCLR适用于从SQL Server 2005开始的所有版本,并且没有其他限制。