Works > 逆引きSQL比較 > MSSQL > 手続き型言語
MSSQL
[ SQL ]
[ データベースの情報 ]
[ 手続き型言語 ]
[ その他 ]
■手続き型言語
この項で使用するサンプルテーブルについて ▲TOP
ORACLEとSQL Server系の大きな違いとは? ▲TOP
SQL Server系(Sybase, MS)の経験者が初めてORACLEのストアドプロシージャを作った時に、おそらく面食らうであろうと思われるのが『BEGIN~ENDブロック内にSELECT文が書けない』と言う点です。
例えばTransact-SQLやWatcom-SQLでは、
create procedure sp_hogehoge @inum int as
begin
--何かの処理
--その処理結果に基づき変数やテーブルをSELECTする
select * from ksale where empno = @inum
end
と言った書き方が可能です。上記の sp_hogehoge を Access のパススルークエリーから実行する場合、
exec sp_hogehoge 7
とクエリーのSQLに書いておけば単純にテーブルやビューをSELECTした場合と同様にダイナセットを得る事ができ
ます。
しかし、ORACLE では、BEGIN~ENDブロック(PL/SQLブロック)の中に上記のようなSELECT文を書くことができま
せん。INTOを使用した値の代入、カーソル、サブクエリーにのみ使用できます。
そこでストアドを呼び出して複数行の結果を得るためには、PL/SQL表(配列)を使ったり、カーソルをバインドしたりする必要があります。
これをクライアントアプリケーションから実行するとなると、もうODBCではできないので、ミドルウェアにはネイティブなものを選択する必要があります。
(最近のODBCでは、カーソルについては、
API関数を呼ぶ事で実装できるようです)。
逆にORACLEのみをやっている人は、SQL Server系のストアドを初めて作る時に、自前配列を作ったりしないようにしましょう。
END の直前に SELECT文を書けばよいだけなので。
手続き型言語の書き方は?(BEGIN~ENDブロック) ▲TOP
ORACLE MSSQL SSA MySQL
基本的な制御の例を以下に示します。この文はストアドプログラムとしてコンパイルする必要はありません。
--Transact-SQLサンプル
begin
--変数宣言
declare @mystr varchar(20), @mycnt int
--値の代入
select @mycnt = 0
select @mystr = '文字'
--IF文
if (@mycnt = 0)
begin
select @mystr = '文字2'
print @mystr
end
else
print '文字3'
--CASE文
select @mystr = case month(getdate())
when 1 then '1月'
when 2 then '2月'
when 3 then '3月'
when 4 then '4月'
else '1~4月以外'
end
print @mystr
--WHILE-LOOP
while (@mycnt <= 5)
begin
select @mycnt = @mycnt + 1
print @mycnt
end
--BEGIN~ENDブロック内でのSELECT文の発行
select 日付 = getdate()
end
go
ストアドプロシージャのサンプル(カーソルを使用するたLOOP処理) ▲TOP
ORACLE MSSQL SSA MySQL
カーソルを使用するLOOP処理のサンプルです。
入力パラメータで指定した部署番号に該当する社員について、
役職が『スタッフ』である場合は、氏名の横に『営業スタッフ:』と表示します。
--Transact-SQLサンプル(カーソルLOOPを使用するストアドプロシージャ)
if exists (select * from sysobjects where id = object_id('dbo.sp_hoge') and sysstat & 0xf = 4)
drop procedure dbo.sp_hoge
go
create procedure sp_hoge @inum int as
--変数宣言
declare @mystr varchar(50)
--カーソル使用列
declare @empnm varchar(40)
declare @job varchar(20)
--カーソル宣言
deallocate mycur --同一セッション内で使う場合必要
declare mycur cursor for
select empnm,job from kemp where deptno = @inum
--カーソルオープン
open mycur
--FETCH(行の取り出し)
fetch next from mycur into @empnm, @job
--LOOP
while (@@fetch_status <> -1) --エラーまたはEOFでない間
begin
if (@@fetch_status <> -2) --EOFでなければ何か処理をする
begin
if @job = 'スタッフ'
select @mystr = '営業スタッフ:'
else
select @mystr = ''
print @mystr + @empnm
end
--FETCH(行の取り出し)
fetch next from mycur into @empnm, @job
end
--カーソルクローズ
close mycur
return
go
--ストアドプロシージャ実行
exec sp_hoge 1
go
ストアドプロシージャのサンプル(アウトパラメータ) ▲TOP
ORACLE MSSQL SSA
プロシージャで更新を行った後、呼出し側に何らかの情報を返したい場合や、返す情報が複数ある場合、
アウトパラメータを使用します。
※因みにファンクションの中では更新をするべきではありません(RDBMSによっては可能だが好ましくない)。
--Transact-SQLサンプル(OUTパラメータを使用するストアドプロシージャ)
if exists (select * from sysobjects where id = object_id('dbo.sp_hoge_outp') and sysstat & 0xf = 4)
drop procedure dbo.sp_hoge_outp
GO
create procedure sp_hoge_outp @ovar varchar(30)=null output as
--何やかやの処理
--何やかやの処理終わり
--OUTパラメータにセット
select @ovar = 'アウト!'
return
go
--ストアドプロシージャ実行
declare @myout varchar(30)
exec sp_hoge_outp @ovar = @myout output
select @myout
go
ストアドプロシージャのサンプル(動的SQL) ▲TOP
ORACLE MSSQL SSA
プロシージャの中で、条件によって使用するテーブルを変えたい場合など、実行するSQLを動的に生成してSQLを実行します。
以下は、区分:1の時は部署番号に該当する社員名を返し、以外の時は区分:1の時は部署番号に該当する部署名を返す例です。
--Transact-SQLサンプル(動的SQLを使用するストアドプロシージャ)
--EXECUTE(文字列) を使用します ※カッコで括らないとエラーになるので注意
if exists (select * from sysobjects where id = object_id('dbo.sp_hoge_dyna') and sysstat & 0xf = 4)
drop procedure dbo.sp_hoge_dyna
GO
create procedure sp_hoge_dyna
@kbn varchar(1),
@inum int as
--変数宣言
declare @sqlstmt varchar(200)
--SQL文生成(区分:1の時は部署番号に該当する社員名、以外は部署名)
if @kbn = '1'
select @sqlstmt = 'select empnm from kemp where deptno = ' + cast(@inum as varchar(2))
else
select @sqlstmt = 'select deptnm from kdept where deptno = ' + cast(@inum as varchar(2))
--SQL文実行
execute (@sqlstmt)
return
go
--ストアドプロシージャ実行(部署番号:1の社員表示)
exec sp_hoge_dyna @kbn = '1' , @inum = 1
--ストアドプロシージャ実行(部署番号:1の部署名表示)
exec sp_hoge_dyna @kbn = '2' , @inum = 1
go
ストアドプロシージャのサンプル(一時テーブル) ▲TOP
ORACLE MSSQL SSA
ストアドプロシージャの中で一時的に使用するためのテーブルの使い方。
社員名の一覧をプロシージャ内で一時格納し、クライアント側に返す例です。
--Transact-SQLサンプル(一時テーブルを使用するストアドプロシージャ)
--CREATE TABLE #テーブル名 を使用します(テーブル名の先頭に # を付ける)
if exists (select * from sysobjects where id = object_id('dbo.sp_hoge_tmp') and sysstat & 0xf = 4)
drop procedure dbo.sp_hoge_tmp
GO
create procedure sp_hoge_tmp as
--一時テーブル作成
create table #tmpkemp (empnm varchar(40))
--社員マスタから一時テーブルに格納
insert into #tmpkemp select empnm from kemp
--一時テーブルから社員名一覧表示
select empnm from #tmpkemp
return
go
--ストアドプロシージャ実行
exec sp_hoge_tmp
go
ストアドプロシージャのサンプル(外部コマンド・アプリを実行) ▲TOP
ORACLE MSSQL SSA
ストアドプロシージャから外部のコマンドやアプリケーションを実行します。
--Transact-SQLサンプル(外部のコマンドやアプリケーションを使用するストアドプロシージャ)
--システムストアドプロシージャxp_cmdshellを使用します。
--※xp_cmdshellは『悪魔のストアド』です。サンプルを見ればわかると思いますが、データベースユーザーが
-- サーバー上でコマンドで実行できる事は『すべて xp_cmdshell から実行可能』です。
-- ですから、セキュリティ面を考慮して使用不可にしているWEBサイトも多いようです。
if exists (select * from sysobjects where id = object_id('dbo.sp_hoge_cmd') and sysstat & 0xf = 4)
drop procedure dbo.sp_hoge_cmd
GO
create procedure sp_hoge_cmd as
execute xp_cmdshell 'echo MSSQL > c:\xpcmd.txt'
execute xp_cmdshell 'dir c:\*.txt >> c:\xpcmd.txt'
return
go
--ストアドプロシージャ実行
exec sp_hoge_cmd
go
ストアドプロシージャのサンプル(テーブルからテキストファイルへ出力) ▲TOP
ORACLE MSSQL
MSSQL の場合、方法は多数考えられます。
・xp_cmdshell で BCP を呼び出す
・DTS(データ変換サービス)を使用する
・sp_OAxxx(OLE)を使用する
DTS はEnterpriseManagerがないと設定ができないので割愛。
(実行自体はMSDEオンリーでも可能ですが)
sp_OAxxx はファイルシステムに関しては使った事がないので割愛(笑)。
ここでは、xp_cmdshell+BCPについて書きます。
BCP については
こちら及びヘルプを参照の事。
declare @cmdstr varchar(1000)
--BCPコマンドを文字列として生成する
set @cmdstr = 'bcp "select * from misc.dbo.kcust" queryout c:\cust.txt -c -t , -U sa -P -o c:\cust.log'
--生成したコマンド文字列を実行するxp_cmdshellを動的SQLで実行する
execute master.dbo.xp_cmdshell @cmdstr
ストアドプロシージャのサンプル(テキストファイルからテーブルへ入力) ▲TOP
ORACLE MSSQL
MSSQL の場合、方法は多数考えられます。
・xp_cmdshell で BCP を呼び出す
・BULK INSERT
・DTS(データ変換サービス)を使用する
・sp_OAxxx(OLE)を使用する
xp_cmdshell+BCPについては、前述の「ストアドの中でテーブルからテキストファイルへ出力」
を参考にしてください。
DTS はEnterpriseManagerがないと設定ができないので割愛。
(実行自体はMSDEオンリーでも可能ですが)
sp_OAxxx はファイルシステムに関しては使った事がないので割愛(笑)。
ここでは、BULK INSERT について書きます。
以下のテキストファイルnewcust.txtを用意
newcust.txt
101,新規顧客1株式会社
102,新規顧客2株式会社
103,新規顧客3株式会社
104,新規顧客4株式会社
--BULK INSERT を実行(newcust.txtの内容をkcustにINSERTする)
bulk insert kcust
from 'c:\newcust.txt'
with
(
fieldterminator = ',',
rowterminator = '\n'
)
ストアドプロシージャのサンプル(メールを送信する) ▲TOP
ORACLE MSSQL
xp_sendmail を使用します。
--SQL Mailクライアントセッションの起動、プロファイルの設定、等の詳細は
--Books Online参照。
--ローカル システム アカウントではなくドメイン アカウントを使って
--MSSQLServer サービスを起動するように設定する必要がある
exec master.dbo.xp_sendmail
@recipients = 'email@uwaaaa.com;email2@uwaaaa.com;' --宛先
,@subject = '送信テスト' --タイトル
,@copy_recipients = 'email3@uwaaaa.com' --cc
,@blind_copy_recipients = 'email4@uwaaaa.com' --bcc
,@Message = 'このメールはxp_sendmailで送りました' --本文
,@attachments = 'c:\hoge.txt' --添付ファイル
,@query = 'select getdate()' --クエリー
SMTPでよいなら、sp_OAxxx + BASP や xp_cmdshell + コマンドラインメーラー
と言った方法もあります。
ストアドプロシージャのサンプル(COM Automation 呼び出し) ▲TOP
ORACLE MSSQL
MSSQL の場合、Excel への書き込みは DTS を使うのが一般的ですが、
ORACLEとの対比のため Excel を使用した例を挙げます。
/* COM Automation(sp_OAxxx)サンプル */
/* Excelファイルは消しておく必要があります */
DECLARE @hr int
DECLARE @objXls int
DECLARE @workBooks int
DECLARE @workBook int
DECLARE @workSheet int
DECLARE @workSheet1 int
DECLARE @range int
DECLARE @lines int
DECLARE @filename varchar(255)
DECLARE @strExec varchar(255)
DECLARE @source varchar(255)
DECLARE @description varchar(255)
set @filename = 'c:\test\spoa.xls'
/* オブジェクト生成 */
EXEC @hr = sp_OACreate 'Excel.Application', @objXls OUT
/* エラーハンドリング割愛
IF @hr != 0
BEGIN
EXEC @hr = sp_OAGetErrorInfo @objXls, @source OUT, @description OUT
SELECT 'Source: ' + @source
SELECT 'Description: ' + @description
END
*/
EXEC @hr = sp_OAGetProperty @objXls ,'WorkBooks', @WorkBooks OUT
EXEC @hr = sp_OAGetProperty @WorkBooks, 'Add', @WorkBook OUT
/* セルに値をセット */
EXEC @hr = sp_OAGetProperty @objXls, 'Range("A1")', @Range OUT
EXEC @hr = sp_OASetProperty @Range, 'Value', 'EmpCode'
EXEC @hr = sp_OAGetProperty @objXls, 'Range("B1")', @Range OUT
EXEC @hr = sp_OASetProperty @Range, 'Value', 'EmpName'
/* セルに値をセット */
EXEC @hr = sp_OAGetProperty @objXls, 'Range("A2")', @Range OUT
EXEC @hr = sp_OASetProperty @Range, 'Value', 'E001'
EXEC @hr = sp_OAGetProperty @objXls, 'Range("B2")', @Range OUT
EXEC @hr = sp_OASetProperty @Range, 'Value', '山田太郎'
/* 書式変更 */
EXEC @hr = sp_OAGetProperty @objXls,'Range("A1:B1")',@Range OUT
EXEC @hr = sp_OASetProperty @Range,'Font.ColorIndex', 23
EXEC @hr = sp_OASetProperty @Range,'Font.Bold', TRUE
EXEC @hr = sp_OASetProperty @Range,'Font.Name', 'Century'
/* 書式変更終わり */
/* ファイル保存 */
SELECT @strExec = 'SaveAs("' + @filename + '")'
EXEC @hr = sp_OAMethod @WorkBook, @strExec
/* 後処理 */
EXEC @hr = sp_OAMethod @WorkBook, 'Close'
EXEC @hr = sp_OADestroy @objXls
オブジェクトがキレイに破棄されないと、実行時に、EXCEL.EXEのゾンビが残ります。
タスクマネージャなどでも殺せない場合は、リブートするか、
Process Walkerなどのプロセス制御ツールを使う必要があります。
このページの先頭へ
MSSQL
[ SQL ]
[ データベースの情報 ]
[ 手続き型言語 ]
[ その他 ]
Works > 逆引きSQL比較 > MSSQL > 手続き型言語