发出执行存储过程,该存储过程具有使用动态SQL的脚本中的动态列

时间:2017-12-13 11:47:59

标签: sql sql-server stored-procedures sql-server-2014 dynamic-sql

我创建了一个存储过程,它接受动态列列表(基于所选参数),然后将它们连接起来。然后将其保存到全局临时表,然后传递到动态SQL语句,该语句将根据参数传递列名。当我运行另一个执行此存储过程的脚本时,它抱怨说:

  

无法确定元数据,因为语句'EXEC(@SqlCommand)'   在过程'CL_GetDynamicColumns2'中包含动态SQL。请考虑使用WITH RESULT SETS子句显式描述结果集。

这里的问题是我不能使用WITH RESULT SETS,因为列的输出是动态的,我永远不知道将返回多少列。列名始终以不同方式输出(如果参数已更改)。

是否可以创建一个可能动态获取我想要的列而不是使用动态SQL的函数?

--Script 1: Everything is first generated in this stored proc
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[CL_GetDynamicColumns2]
(
@TableName NVARCHAR(MAX),
@Currency NVARCHAR(MAX),
@Type NVARCHAR(MAX),
@ParameterValue NVARCHAR(MAX),
@WhereField NVARCHAR(MAX),
@ColumnList NVARCHAR(MAX) = NULL,
@SqlCommand NVARCHAR(MAX) = NULL
)

AS
BEGIN
SET NOCOUNT ON;

DECLARE @MyTableVar TABLE
(  
[TABLE_CATALOG] nvarchar(128),
[TABLE_SCHEMA] nvarchar(128),
[TABLE_NAME] nvarchar(128),
[COLUMN_NAME] nvarchar(128),
[ORDINAL_POSITION] INT,
[COLUMN_DEFAULT] NVARCHAR(4000),
[IS_NULLABLE] VARCHAR(3),
[DATA_TYPE] nvarchar(128),
[CHARACTER_MAXIMUM_LENGTH] INT,
[CHARACTER_OCTET_LENGTH] INT,
[NUMERIC_PRECISION] TINYINT,
[NUMERIC_PRECISION_RADIX] SMALLINT,
[NUMERIC_SCALE] INT,
[DATETIME_PRECISION] SMALLINT,
[CHARACTER_SET_CATALOG] nvarchar(128),
[CHARACTER_SET_SCHEMA] nvarchar(128),
[CHARACTER_SET_NAME] nvarchar(128),
[COLLATION_CATALOG] nvarchar(128),
[COLLATION_SCHEMA] nvarchar(128),
[COLLATION_NAME] nvarchar(128),
[DOMAIN_CATALOG] nvarchar(128),
[DOMAIN_SCHEMA] nvarchar(128),
[DOMAIN_NAME] nvarchar(128)
)

INSERT INTO @MyTableVar

SELECT *
FROM information_schema.columns AS C
WHERE C.TABLE_NAME = @TableName
AND C.DATA_TYPE NOT IN ('decimal','numeric')

UNION ALL

SELECT *
FROM information_schema.columns AS C
WHERE C.TABLE_NAME = @TableName
AND C.DATA_TYPE IN ('decimal','numeric')
AND C.COLUMN_NAME LIKE '%' + @Currency + '%'
AND C.COLUMN_NAME LIKE '%' + @Type + '%'


DECLARE @MyTableVar2 TABLE
(  
[TABLE_CATALOG] nvarchar(128),
[TABLE_SCHEMA] nvarchar(128),
[TABLE_NAME] nvarchar(128),
[TABLE_COLUMNS] nvarchar(MAX)
)

INSERT INTO @MyTableVar2 ([TABLE_CATALOG], [TABLE_SCHEMA], [TABLE_NAME], 
[TABLE_COLUMNS])

SELECT DISTINCT T.TABLE_CATALOG, T.TABLE_SCHEMA, T.TABLE_NAME, 
STUFF(
      (SELECT ', ' + QUOTENAME(COLUMN_NAME)
      FROM @MyTableVar AS TC
      WHERE TC.TABLE_NAME = T.TABLE_NAME
      FOR XML PATH (''))
      , 1, 1, '')  AS TABLE_COLUMNS
 FROM @MyTableVar AS T

 /*Final step: Build Dynamic Query*/

 SET @ColumnList = (SELECT L.TABLE_COLUMNS FROM @MyTableVar2 AS L)

 SET @SqlCommand = 'SELECT ' + @ColumnList + 
            ' Into ##TempCatch ' + 
            ' FROM ' + @TableName + 
             ' WHERE ' + @WhereField + ' IN ' + '(SELECT * FROM ' + 
 'dbo.fnToDelimitedTable( ' + @ParameterValue + ' ,'',''))'

 EXEC (@SqlCommand)

 SELECT * FROM ##TempCatch
 DROP TABLE ##TempCatch

 END


--script 2 to gather results from first stored procedure
DECLARE @TableName NVARCHAR(MAX) = 'SM_COLLECTIONS_WTK_RANK'
DECLARE @Currency NVARCHAR(MAX) = 'GBP'
DECLARE @Type NVARCHAR(MAX) = 'Billed'
DECLARE @ParameterValue NVARCHAR(MAX) = '1503515'
DECLARE @WhereField NVARCHAR(MAX) = 'FK_MATTER'
DECLARE @ColumnList NVARCHAR(MAX)
DECLARE @SqlCommand NVARCHAR(MAX)
DECLARE @SPWithParams NVARCHAR(MAX)

SELECT TOP 0 *
INTO ##holdingtable
FROM 
OPENROWSET('SQLNCLI','Server=;UID=;PWD=','SET FMTONLY OFF EXEC 
dbo.CL_GetDynamicColumns2')

--set the parameters of the procedure
SET @SPWithParams = 'EXEC dbo.CL_GetDynamicColumns2' + @TableName + 
@Currency + @Type + @ParameterValue + @WhereField  + @ColumnList + 
@SqlCommand
--execute the procedure
EXEC ProcToTable 'holdingtable', @SPWithParams
--view the results
SELECT * FROM ##holdingtable
DROP TABLE ##holdingtable

0 个答案:

没有答案