我有一个存储过程,返回80列和300行。我想写一个选择,获得其中2列。像
这样的东西SELECT col1, col2 FROM EXEC MyStoredProc 'param1', 'param2'
当我使用上面的语法时,我收到错误:
“列名无效”。
我知道最简单的解决方案是更改存储过程,但我没有写它,我无法更改它。
有没有办法做我想做的事?
我可以创建一个临时表来放入结果,但因为有80列,所以我需要制作一个80列的临时表来获得2列。我想避免追踪返回的所有列。
我尝试使用Mark建议的WITH SprocResults AS ....
,但我收到了2个错误
关键字'EXEC'附近的语法不正确。
''''附近的语法不正确。
我尝试声明一个表变量,我收到了以下错误
插入错误:列名或提供的值数与表定义不匹配
如果我试试
SELECT * FROM EXEC MyStoredProc 'param1', 'param2'
我收到错误:
关键字'exec'附近的语法不正确。
答案 0 :(得分:173)
你可以拆分查询吗?将存储的proc结果插入表变量或临时表中。然后,从表变量中选择2列。
Declare @tablevar table(col1 col1Type,..
insert into @tablevar(col1,..) exec MyStoredProc 'param1', 'param2'
SELECT col1, col2 FROM @tablevar
答案 1 :(得分:81)
这是一个非常好的文档的链接,解释了解决问题的所有不同方法(尽管由于您无法修改现有的存储过程,因此很多方法都无法使用。)
How to Share Data Between Stored Procedures
Gulzar的答案将起作用(它在上面的链接中有记录),但编写麻烦(你需要在@tablevar(col1,...)语句中指定所有80个列名。)将来,如果将一个列添加到架构中或者输出已更改,则需要在代码中更新它,否则会出错。
答案 2 :(得分:77)
CREATE TABLE #Result
(
ID int, Name varchar(500), Revenue money
)
INSERT #Result EXEC RevenueByAdvertiser '1/1/10', '2/1/10'
SELECT * FROM #Result ORDER BY Name
DROP TABLE #Result
来源:
http://stevesmithblog.com/blog/select-from-a-stored-procedure/
答案 3 :(得分:38)
这对我有用:(即我只需要sp_help_job
返回的30+列中的2列)
SELECT name, current_execution_status
FROM OPENQUERY (MYSERVER,
'EXEC msdb.dbo.sp_help_job @job_name = ''My Job'', @job_aspect = ''JOB''');
在此之前,我需要运行它:
sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
....更新sys.servers
表。 (例如,默认情况下,在OPENQUERY中使用自引用似乎是禁用的。)
根据我的简单要求,我遇到了Lance优秀链接的OPENQUERY section中描述的问题。
罗西尼,如果你需要动态设置这些输入参数,那么使用OPENQUERY会变得更加繁琐:
DECLARE @innerSql varchar(1000);
DECLARE @outerSql varchar(1000);
-- Set up the original stored proc definition.
SET @innerSql =
'EXEC msdb.dbo.sp_help_job @job_name = '''+@param1+''', @job_aspect = N'''+@param2+'''' ;
-- Handle quotes.
SET @innerSql = REPLACE(@innerSql, '''', '''''');
-- Set up the OPENQUERY definition.
SET @outerSql =
'SELECT name, current_execution_status
FROM OPENQUERY (MYSERVER, ''' + @innerSql + ''');';
-- Execute.
EXEC (@outerSql);
我不确定使用sp_serveroption
直接更新现有sys.servers
自引用与使用sp_addlinkedserver
之间的差异(如果有)(如Lance链接中所述) )创建副本/别名。
注1: 鉴于OPENQUERY不需要proc中的连接字符串定义,我更喜欢OPENQUERY而不是OPENROWSET。
注2:
说完这一切:通常我只会使用INSERT ... EXEC :)是的,这是10分钟的额外打字,但是如果我可以帮助它,我宁愿不用摇晃:
(a)引号内的引号内的引号,和
(b)sys表,和/或偷偷摸摸的自引用链接服务器设置(即对于这些,我需要向我们全能的DBA辩护:)
但是在这种情况下,我无法使用INSERT ... EXEC结构,因为sp_help_job
已经使用了一个。 (“INSERT EXEC语句不能嵌套。”)
答案 4 :(得分:10)
了解为何如此困难可能会有所帮助。 存储过程可能只返回文本(打印'文本'),或者可能返回多个表,或者根本不返回任何表。
SELECT * FROM (exec sp_tables) Table1
之类的内容无效
答案 5 :(得分:9)
要实现这一目标,首先要创建一个#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
答案 6 :(得分:9)
如果您能够修改存储过程,则可以轻松地将所需的列定义作为参数并使用自动创建的临时表:
CREATE PROCEDURE sp_GetDiffDataExample
@columnsStatement NVARCHAR(MAX) -- required columns statement (e.g. "field1, field2")
AS
BEGIN
DECLARE @query NVARCHAR(MAX)
SET @query = N'SELECT ' + @columnsStatement + N' INTO ##TempTable FROM dbo.TestTable'
EXEC sp_executeSql @query
SELECT * FROM ##TempTable
DROP TABLE ##TempTable
END
在这种情况下,您无需手动创建临时表 - 它是自动创建的。希望这会有所帮助。
答案 7 :(得分:8)
(假设SQL Server)
在T-SQL中处理存储过程结果的唯一方法是使用INSERT INTO ... EXEC
语法。这使您可以选择插入临时表或表变量,然后从中选择所需的数据。
答案 8 :(得分:7)
快速入侵是添加一个新参数'@Column_Name'
并让调用函数定义要检索的列名。在你的sproc的返回部分,你将有if / else语句并只返回指定的列,或者如果为空 - 返回all。
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
答案 9 :(得分:6)
对于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;
那就是它!
答案 10 :(得分:5)
正如问题中提到的那样,在执行存储过程之前很难定义80列临时表。
所以另一种方法是根据存储过程结果集填充表。
SELECT * INTO #temp FROM OPENROWSET('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;'
,'EXEC MyStoredProc')
如果您收到任何错误,则需要通过执行以下查询来启用即席分布式查询。
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO
要使用这两个参数执行sp_configure
以更改配置选项或运行RECONFIGURE
语句,您必须被授予ALTER SETTINGS
服务器级权限
现在,您可以从生成的表中选择特定列
SELECT col1, col2
FROM #temp
答案 11 :(得分:4)
试试这个
use mydatabase
create procedure sp_onetwothree as
select 1 as '1', 2 as '2', 3 as '3'
go
SELECT a.[1], a.[2]
FROM OPENROWSET('SQLOLEDB','myserver';'sa';'mysapass',
'exec mydatabase.dbo.sp_onetwothree') AS a
GO
答案 12 :(得分:0)
这是一个简单的答案:
SELECT ColA, ColB
FROM OPENROWSET('SQLNCLI','server=localhost;trusted_connection=yes;','exec schema.procedurename')
SQLNCLI 是本机 SQL 客户端,“localhost”将使其使用您正在执行该过程的服务器。
无需构建临时表或任何其他爵士乐。
答案 13 :(得分:0)
创建动态视图并从中获取结果。......
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
答案 14 :(得分:0)
我知道可以从sp执行并插入到临时表或表变量中,但是我认为这不是您的要求。根据您的要求,以下查询语句应该可以正常工作:
Declare @sql nvarchar(max)
Set @sql='SELECT col1, col2 FROM OPENROWSET(''SQLNCLI'', ''Server=(local);uid=test;pwd=test'',
''EXEC MyStoredProc ''''param1'''', ''''param2'''''')'
Exec(@sql)
如果您具有可信任的连接,请在下面的查询语句中使用以下内容:
Declare @sql nvarchar(max)
Set @sql='SELECT col1, col2 FROM OPENROWSET(''SQLNCLI'', ''Server=(local);Trusted_Connection=yes;'',
''EXEC MyStoredProc ''''param1'''', ''''param2'''''')'
Exec(@sql)
如果在运行上述语句时遇到错误,则只需在下面运行此语句即可:
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO
我希望这会对遇到类似问题的人有所帮助。如果有人尝试使用如下所示的临时表或表变量,但是在这种情况下,您应该知道sp返回的列数,那么您应该在临时表或表变量中创建那么多列:
--for table variable
Declare @t table(col1 col1Type, col2 col2Type)
insert into @t exec MyStoredProc 'param1', 'param2'
SELECT col1, col2 FROM @t
--for temp table
create table #t(col1 col1Type, col2 col2Type)
insert into #t exec MyStoredProc 'param1', 'param2'
SELECT col1, col2 FROM #t
答案 15 :(得分:0)
对于拥有SQL 2012或更高版本的任何人,我都可以使用非动态存储过程来实现此目的,并且存储过程每次都输出相同的列。
总体思路是,我构建动态查询以创建,插入,从中选择和删除temp表,并在所有生成后执行该查询。我首先通过retrieving column names and types from the stored procedure动态生成了临时表。
注意:如果您愿意/能够更新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)
答案 16 :(得分:0)
如果您只需要这一次,最简单的方法:
导出到导出和导出向导中的Excel,然后将此excel导入表格。
答案 17 :(得分:-1)
我剪切并粘贴原始SP并删除除了你想要的2之外的所有列。要么。我将结果集带回来,将其映射到一个合适的业务对象,然后LINQ输出两列。