我有一个存储过程,它返回80列和300行。我要写一个select函数,它能得到2个这样的列。类似的

SELECT col1, col2 FROM EXEC MyStoredProc 'param1', 'param2'

当我使用上面的语法时,我得到了错误:

“无效的列名”。

我知道最简单的解决方案是更改存储过程,但我没有编写它,也不能更改它。

有什么办法能让我如愿以偿吗?

I could make a temp table to put the results in, but because there are 80 columns so I would need to make an 80 column temp table just to get 2 columns. I wanted to avoid tracking down all the columns that are returned. I tried using WITH SprocResults AS .... as suggested by Mark, but I got 2 errors Incorrect syntax near the keyword 'EXEC'.Incorrect syntax near ')'. I tried declaring a table variable and I got the following error Insert Error: Column name or number of supplied values does not match table definition If I try SELECT * FROM EXEC MyStoredProc 'param1', 'param2' I get the error : Incorrect syntax near the keyword 'exec'.


当前回答

创建一个动态视图,并从中获得结果.......

CREATE PROCEDURE dbo.usp_userwise_columns_value
(
    @userid BIGINT
)
AS 
BEGIN
        DECLARE @maincmd NVARCHAR(max);
        DECLARE @columnlist NVARCHAR(max);
        DECLARE @columnname VARCHAR(150);
        DECLARE @nickname VARCHAR(50);

        SET @maincmd = '';
        SET @columnname = '';
        SET @columnlist = '';
        SET @nickname = '';

        DECLARE CUR_COLUMNLIST CURSOR FAST_FORWARD
        FOR
            SELECT columnname , nickname
            FROM dbo.v_userwise_columns 
            WHERE userid = @userid

        OPEN CUR_COLUMNLIST
        IF @@ERROR <> 0
            BEGIN
                ROLLBACK
                RETURN
            END   

        FETCH NEXT FROM CUR_COLUMNLIST
        INTO @columnname, @nickname

        WHILE @@FETCH_STATUS = 0
            BEGIN
                SET @columnlist = @columnlist + @columnname + ','

                FETCH NEXT FROM CUR_COLUMNLIST
                INTO @columnname, @nickname
            END
        CLOSE CUR_COLUMNLIST
        DEALLOCATE CUR_COLUMNLIST  

        IF NOT EXISTS (SELECT * FROM sys.views WHERE name = 'v_userwise_columns_value')
            BEGIN
                SET @maincmd = 'CREATE VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), @userid) + ') as userid , ' 
                            + CHAR(39) + @nickname + CHAR(39) + ' as nickname, ' 
                            + @columnlist + ' compcode FROM dbo.SJOTran '
            END
        ELSE
            BEGIN
                SET @maincmd = 'ALTER VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), @userid) + ') as userid , ' 
                            + CHAR(39) + @nickname + CHAR(39) + ' as nickname, ' 
                            + @columnlist + ' compcode FROM dbo.SJOTran '
            END

        --PRINT @maincmd
        EXECUTE sp_executesql @maincmd
END

-----------------------------------------------
SELECT * FROM dbo.v_userwise_columns_value

其他回答

一个快速的方法是添加一个新参数“@Column_Name”,并让调用函数定义要检索的列名。在你的sproc的返回部分,你会有if/else语句并只返回指定的列,或者如果为空-返回所有。

CREATE PROCEDURE [dbo].[MySproc]
        @Column_Name AS VARCHAR(50)
AS
BEGIN
    IF (@Column_Name = 'ColumnName1')
        BEGIN
            SELECT @ColumnItem1 as 'ColumnName1'
        END
    ELSE
        BEGIN
            SELECT @ColumnItem1 as 'ColumnName1', @ColumnItem2 as 'ColumnName2', @ColumnItem3 as 'ColumnName3'
        END
END

这里有一个简单的答案:

SELECT ColA, ColB
FROM OPENROWSET('SQLNCLI','server=localhost;trusted_connection=yes;','exec schema.procedurename')

SQLNCLI是本地SQL客户端,“localhost”将使它利用您正在执行过程的服务器。

不需要构建临时表或任何其他jazz。

对于SQL Server,我发现这工作得很好:

创建一个临时表(或永久表,并不重要),并对存储过程执行insert into语句。SP的结果集应该与表中的列匹配,否则将得到一个错误。

这里有一个例子:

DECLARE @temp TABLE (firstname NVARCHAR(30), lastname nvarchar(50));

INSERT INTO @temp EXEC dbo.GetPersonName @param1,@param2;
-- assumption is that dbo.GetPersonName returns a table with firstname / lastname columns

SELECT * FROM @temp;

就是这样!

对于任何使用SQL 2012或更高版本的用户,我都能够使用非动态且每次都有相同列输出的存储过程来实现这一点。

总体思想是构建动态查询来创建、插入、选择和删除临时表,并在生成所有临时表后执行。首先从存储过程中检索列名和类型,动态生成临时表。

注意:如果您愿意/能够更新SP或更改配置并使用OPENROWSET,那么有更好、更通用的解决方案,它们只需要更少的代码行。如果没有其他方法,请使用下面的方法。

DECLARE @spName VARCHAR(MAX) = 'MyStoredProc'
DECLARE @tempTableName VARCHAR(MAX) = '#tempTable'

-- might need to update this if your param value is a string and you need to escape quotes
DECLARE @insertCommand VARCHAR(MAX) = 'INSERT INTO ' + @tempTableName + ' EXEC MyStoredProc @param=value'

DECLARE @createTableCommand VARCHAR(MAX)

-- update this to select the columns you want
DECLARE @selectCommand VARCHAR(MAX) = 'SELECT col1, col2 FROM ' + @tempTableName

DECLARE @dropCommand VARCHAR(MAX) = 'DROP TABLE ' + @tempTableName

-- Generate command to create temp table
SELECT @createTableCommand = 'CREATE TABLE ' + @tempTableName + ' (' +
    STUFF
    (
        (
            SELECT ', ' + CONCAT('[', name, ']', ' ', system_type_name)
            FROM sys.dm_exec_describe_first_result_set_for_object
            (
              OBJECT_ID(@spName), 
              NULL
            )
            FOR XML PATH('')
        )
        ,1
        ,1
        ,''
    ) + ')'

EXEC( @createTableCommand + ' '+ @insertCommand + ' ' + @selectCommand + ' ' + @dropCommand)

要实现这一点,首先你创建一个#test_table,如下所示:

create table #test_table(
    col1 int,
    col2 int,
   .
   .
   .
    col80 int
)

现在执行过程并将值放在#test_table中:

insert into #test_table
EXEC MyStoredProc 'param1', 'param2'

现在你从#test_table中获取值:

select col1,col2....,col80 from #test_table