474

80列と300行を返すストアドプロシージャがあります。それらの列のうちの2つを取得するselectを作成したいと思います。何かのようなもの

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

上記の構文を使用すると、エラーが発生します。

「無効な列名」。

ストアドプロシージャを変更するのが最も簡単な解決策であることはわかっていますが、記述していなかったため、変更できません。

私がやりたいことをする方法はありますか?

  • 結果を入れるための一時テーブルを作成することもできますが、80列あるため、2列を取得するためだけに80列の一時テーブルを作成する必要があります。返されるすべての列を追跡することは避けたかったのです。

  • WITH SprocResults AS ....Markの提案どおりに使用してみましたが、2つのエラーが発生しました

    キーワード「EXEC」の近くの構文が正しくありません。
    ')'の近くの構文が正しくありません。

  • テーブル変数を宣言しようとしましたが、次のエラーが発生しました

    挿入エラー:列名または指定された値の数がテーブル定義と一致しません

  • 試してみる
    SELECT * FROM EXEC MyStoredProc 'param1', 'param2'
    とエラーが発生します:

    キーワード「exec」の近くの構文が正しくありません。

4

19 に答える 19

202

クエリを分割できますか?ストアドプロシージャの結果をテーブル変数または一時テーブルに挿入します。次に、テーブル変数から2つの列を選択します。

Declare @tablevar table(col1 col1Type,..
insert into @tablevar(col1,..) exec MyStoredProc 'param1', 'param2'

SELECT col1, col2 FROM @tablevar
于 2008-10-16T16:48:54.683 に答える
88

これは、問題を解決するためのさまざまな方法をすべて説明している非常に優れたドキュメントへのリンクです (ただし、既存のストアド プロシージャを変更できないため、それらの多くは使用できません)。

ストアド プロシージャ間でデータを共有する方法

Gulzar の回答は機能しますが (上記のリンクに記載されています)、記述するのは面倒です (@tablevar(col1,...) ステートメントで 80 列すべての名前を指定する必要があります。また、将来的には列がスキーマに追加された場合、または出力が変更された場合、コードで更新する必要があります。そうしないと、エラーが発生します。

于 2008-10-16T17:37:27.533 に答える
81
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/

于 2010-10-18T22:38:46.960 に答える
41

これは私にとってはうまくいきます:(つまり、によって返された30以上の列のうち2列だけが必要ですsp_help_job

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 セクションで説明されている問題に遭遇しませんでした。

Rossini さん、これらの入力パラメータを動的に設定する必要がある場合は、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更新する場合と、 (Lance のリンクで説明されているように) を使用して複製/エイリアスを作成する場合の違い (もしあれば) はわかりません。sys.serverssp_addlinkedserver

注 1: OPENQUERY は proc 内で接続文字列の定義を必要としないため、OPENROWSET よりも OPENQUERY を好みます。


注 2: 以上のことをすべて言いましたが、通常は INSERT ... EXEC を使用するだけです:) はい、10 分の余分な入力ですが、私がそれを助けることができれば、次のように動かしたくない:引用符、および
(b)sysテーブル、および/または卑劣な自己参照リンクサーバーセットアップ(つまり、これらについては、全能のDBAに私の主張を訴える必要があります:)

sp_help_jobただし、この例では、既に使用されている INSERT ... EXEC 構成を使用できませんでした。(「INSERT EXEC ステートメントはネストできません。」)

于 2011-02-04T03:06:49.797 に答える
11

ストアド プロシージャを変更できる場合は、必要な列の定義をパラメーターとして簡単に配置し、自動作成された一時テーブルを使用できます。

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

この場合、一時テーブルを手動で作成する必要はありません。自動的に作成されます。お役に立てれば。

于 2015-01-31T03:21:45.007 に答える
11

なぜこれが難しいのかを知ることは役に立つかもしれません。ストアド プロシージャは、テキストのみを返すか (print 'text')、複数のテーブルを返すか、テーブルをまったく返さない場合があります。

したがって、次のようなものは機能しSELECT * FROM (exec sp_tables) Table1 ません

于 2010-06-24T15:03:49.707 に答える
9

(SQL Server を想定)

T-SQL でストアド プロシージャの結果を操作する唯一の方法は、INSERT INTO ... EXEC構文を使用することです。これにより、一時テーブルまたはテーブル変数に挿入し、そこから必要なデータを選択するオプションが提供されます。

于 2008-10-16T18:09:25.397 に答える
8

簡単なハックは、新しいパラメーターを追加し'@Column_Name'、呼び出し元の関数で取得する列名を定義することです。sproc の return 部分には、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
于 2012-01-28T00:48:22.813 に答える
8

質問で言及されているように、ストアド プロシージャを実行する前に 80 列の一時テーブルを定義するのは困難です。

したがって、これを回避するもう 1 つの方法は、ストアド プロシージャの結果セットに基づいてテーブルを作成することです。

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
于 2016-02-24T06:02:21.317 に答える
7

データの手動検証のためにこれを行う場合は、LINQPadを使用してこれを行うことができます。

LinqPadでデータベースへの接続を作成してから、次のようなC#ステートメントを作成します。

DataTable table = MyStoredProc (param1, param2).Tables[0];
(from row in table.AsEnumerable()
 select new
 {
  Col1 = row.Field<string>("col1"),
  Col2 = row.Field<string>("col2"),
 }).Dump();

参照http://www.global-webnet.net/blogengine/post/2008/09/10/LINQPAD-Using-Stored-Procedures-Accessing-a-DataSet.aspx

于 2012-11-09T01:17:13.967 に答える
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
于 2010-01-05T12:48:12.797 に答える
0

これが一度だけ必要な場合の最も簡単な方法:

インポートおよびエクスポート ウィザードで Excel にエクスポートし、この Excel をテーブルにインポートします。

于 2013-07-23T14:12:04.733 に答える
-1

元の SP をカット アンド ペーストして、必要な 2 つを除くすべての列を削除します。または。結果セットを戻し、それを適切なビジネス オブジェクトにマップしてから、LINQ で 2 つの列を取り出します。

于 2013-09-16T20:23:09.477 に答える