这有点复杂,因为它需要从一开始就知道很少,除了每个存储过程返回一个数据集(这是一个临时表)。
我无法使用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
我喜欢这种方式,所以我可以更改任何被调用的存储过程,而无需以标准方式格式化
这甚至可能吗?
答案 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)
实现此动态的唯一方法,尤其是在处理存储过程的结果集时,是使用以下方法之一:
OPENQUERY
OPENROWSET
你说你不能使用前两个,所以离开SQLCLR,sys.dm_exec_describe_first_result_set
+ CONCAT
(技术上CONCAT
不是必需的,但它会使这个有点更容易)。
SQLCLR可能最适合此类操作,因为它允许您:
使用这种方法你会:
SqlCommand
(或任何查询,实际上)ExecuteReader()
SqlCommand
方法
GetName()
或GetSchemaTable()
方法获取列名称Read()
循环中调用SqlDataReader
的{{1}}方法以获取每一行while
GetValue(ordinal).ToString()
如果不使用SQLCLR,则需要将存储过程的结果集存储到临时表中,以便在从临时表中选择数据时对其进行变换/格式化。
使用这种方法你会:
StringBuilder
以获取字段名称和数据类型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开始的所有版本,并且没有其他限制。