1. ホーム
  2. データベース

01. プロシージャの結果セットを持つ一時テーブルへのSELECT INTO

2022-02-09 07:32:18
原文のままです。 01. プロシージャの結果セットから一時テーブルへSELECT INTO

開発中には、結果セットを一時テーブルに格納したいと思うことが多々ありますが、これには2つの一般的な方法があります。

I. SELECT INTO
1. select into を使って、事前にテンポラリテーブルを作成することなく、自動的に生成される

select * into #temp from sysobjects
select * from #temp

<スパン 2. 現在のセッションに同名のテンポラリーテーブルが既に存在する場合

select * into #temp from sysobjects

もう一度実行すると、'%1!'という名前のオブジェクトがすでにデータベースに存在するというエラーが報告されます。
Msg 2714, Level 16, State 6, Line 2
データベースに '#temp' という名前のオブジェクトがすでに存在します。

select intoを使う前に、次のような判断をすることができます。

if OBJECT_ID('tempdb... #temp') is not null
drop table #temp

select * into #temp from sysobjects 
select * from #temp

3. select into を使って空のテーブルを生成する
データを含まない空のテーブル構造を生成するには、次のように定数不等式を与えればよい。

select * into #temp from sysobjects where 1=2
select * from #temp

II. INSERT INTO
1. insert into を使用するには、まず手動でテンポラリテーブルを作成する必要がある

1.1 select文から返された結果セットを保存する

create table test_getdate(c1 datetime) insert into test_getdate select GETDATE() select * from test_getdate

1.2 ストアドプロシージャから返された結果セットを保存する

create table #helpuser
(
UserName nvarchar(128),
RoleName nvarchar(128),
LoginName nvarchar(128),
DefDBName nvarchar(128),
DefSchemaName nvarchar(128),
UserID smallint,
SID smallint
)

insert into #helpuser exec sp_helpuser

select * from #helpuser

1.3 ダイナミック・ステートメントから返された結果セットの保存

create table test_dbcc
(
TraceFlag varchar(100),
Status tinyint,
Global tinyint,
Session tinyint
)

insert into test_dbcc exec('DBCC TRACESTATUS')

select * from test_dbcc

動的SQLや、DBCCのような型破りなSQL文では、このように結果セットを保存することができます。

2. insert exec文はネストできません

2.1 sp_help_jobの結果セットを一時テーブルに保存しようとする次の例では、エラーが発生します。

create table #JobInfo
(
job_id uniqueidentifier,
originating_server nvarchar(128),
name nvarchar(128),
enabled tinyint,
description nvarchar(512),
start_step_id int,
category nvarchar(128),
owner nvarchar(128),
notify_level_eventlog int,
notify_level_email int,
notify_level_netsend int,
notify_level_page int ,
notify_email_operator nvarchar(128),
notify_netsend_operator nvarchar(128),
notify_page_operator nvarchar(128),
delete_level int,
date_created datetime,
date_modified datetime,
version_number int,
last_run_date int,
last_run_time int,
last_run_outcome int,
next_run_date int,
next_run_time int,
next_run_schedule_id int,
current_execution_status int,
current_execution_step nvarchar(128),
current_retry_attempt int,
has_step int,
has_schedule int,
has_target int,
type int
)

insert into #JobInfo exec msdb..sp_help_job

エラーメッセージを返します。INSERT EXEC文はネストできません。
Msg 8164, Level 16, State 1, Procedure sp_get_composite_job_info, Line 72
INSERT EXEC文は入れ子にできません。

エラーメッセージのストアドプロシージャを展開してください。

exec sp_helptext sp_get_composite_job_info

内部に SQL Server が構文的にサポートしていない別の INSERT INTO...EXEC ネストされた呼び出しを発見しました。

INSERT INTO @xp_results 
EXECUTE master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner, @job_id

2.2 この問題は、以下のような分散型クエリで回避することができます。 この書き方は、著者がINSIDE SQL Server 2005で言及している
(1) まず、オープンサーバーのオプションのアドホック分散クエリにアクセスします。

exec sp_configure 'show advanced options',1
RECONFIGURE
GO
exec sp_configure 'Ad Hoc Distributed Queries',1
RECONFIGURE
GO

(2) OPENROWSETでローカルマシンに接続し、プロシージャを実行し、結果セットを取得する。
Windows認証の利用

select * into #JobInfo_S1
from openrowset('sqloledb', 'server=(local);trusted_connection=yes','exec msdb.dbo.sp_help_job')

select * from #JobInfo_S1

SQL Server 認証を使用する

SELECT * INTO #JobInfo_S2
FROM OPENROWSET('SQLOLEDB','127.0.0.1';'sa';'sa_password','exec msdb.dbo.sp_help_job')

SELECT * FROM #JobInfo_S2

これは、手動でテーブルを構築する必要がなく、insert execがネストできない問題を回避するように書かれています。ほとんどすべてのSQL文が使用可能です。

--dbcc cannot be run directly
SELECT a.* into #t
FROM OPENROWSET('SQLOLEDB','127.0.0.1';'sa';'sa_password',
'dbcc log(''master'',3)') AS a

-- can be adapted
SELECT a.* into #t
FROM OPENROWSET('SQLOLEDB','127.0.0.1';'sa';'sa_password',
'exec(''DBCC LOG(''''master'''',3)')') AS a