[SQL Server] カーソル(CURSOR)の使い方

inno
2014-04-27 01:02 3907 0
[SQL Server] カーソル(CURSOR)の使い方

カーソル(CURSOR)について簡単に例文と説明をしたいと思います。
個人的に「CURSOR」はあまり使いません。
でも、どうしてもという場合は使います。

まず、「CURSOR」を使う時の基本的なテンプレートは下記の通りです。
下記の部分で茶色になっている部分だけ修正して使えばいいです。

DECLARE @UserID varchar(25) -- #### 説明1
DECLARE @UserName nvarchar(20)

DECLARE DB_Cursor CURSOR LOCAL FAST_FORWARD FOR

SELECT UserID, UserName FROM dbo.TempData1  -- #### 説明2
 
OPEN DB_Cursor
FETCH NEXT FROM DB_Cursor
INTO @UserID, @UserName -- #### 説明3

WHILE @@FETCH_STATUS = 0
BEGIN

-- #### 説明4 #### Start ####

UPDATE dbo.UserInfo
SET UserName = @UserName
WHERE UserID = @UserID

-- #### 説明4 #### End ####

FETCH NEXT FROM DB_Cursor
INTO @UserID, @UserName -- #### 説明5

END

CLOSE DB_Cursor
DEALLOCATE DB_Cursor

まずは「説明2」部分に「CURSOR」で使う原本データを準備します。
「説明2」は「SELECT UserID, UserName FROM dbo.TempData1」になっています。
例えば、「dbo.TempData1」テーブルに3件のデータがあれば3件データに対して処理を行います。
100件があるとしたら100件のデータを処理することになります。
ここで「dbo.TempData1」テーブルから「UserID」, 「UserName」カラムのデータのみ使用しています。
そしたらこのカラム数に合わせて「説明3」、「説明5」にも変数をしてする必要があります。
もし、カラム数と変数の数が一致しなかったら下記のようなエラーが発生します。
「カーソル フェッチ: INTO リストで宣言する変数の数は、選択される列の数と一致させてください。」

変数名はカラム名と違っても問題ありません。
「説明3」、「説明5」部分で変数を使うためには変数を指定する必要がありますので、
「説明1」で変数を指定しています。
「説明4」部分では「説明2」のデータを利用して「説明4」で処理を行うことです。

上記のSQLの動作を簡単にすると。。
「dbo.TempData1」テーブルにあるUserID, UserNameデータを元に
「dbo.UserInfo」テーブルに「dbo.TempData1」テーブルにある同じUserIDを持つデータのUserNameを変更する。

では、実際にテストしてみましょう。

下記にテスト用のSQLを準備しまいた。

1)UserInfoテーブルを作成及びデータを登録

USE tempdb
GO
-- テーブル作成
CREATE TABLE dbo.UserInfo
(
UserID varchar(25)
, UserName nvarchar(20)
, RegDate datetime
)
GO

-- データ登録
INSERT INTO dbo.UserInfo (UserID, UserName, RegDate)
SELECT 'test01', N'テスト01', '2010-01-01 00:00:00' UNION ALL
SELECT 'test02', N'テスト02', '2011-01-01 00:00:00' UNION ALL
SELECT 'test03', N'テスト03', '2012-01-01 00:00:00' UNION ALL
SELECT 'test04', N'テスト04', '2013-01-01 00:00:00' UNION ALL
SELECT 'test05', N'テスト05', '2014-01-01 00:00:00'
GO

-- データ確認
SELECT * FROM dbo.UserInfo
GO

2)カーソルで使う原本データTempData1テーブルを作成及びデータを登録

-- テーブル作成
CREATE TABLE dbo.TempData1
(
UserID varchar(25)
, UserName nvarchar(20)
)
GO

-- データ登録
INSERT INTO dbo.TempData1 (UserID, UserName)
SELECT 'test02', N'山田' UNION ALL
SELECT 'test03', N'鈴木' UNION ALL
SELECT 'test04', N'木村'
GO

-- データ確認
SELECT * FROM dbo.TempData1
GO

3)「CURSOR」で「dbo.TempData1」テーブルにある
UserIDのtest02, test03, test04のUserNameデータを元に
「dbo.UserInfo」テーブルから一致するUserIDのUserNameデータを修正する。

DECLARE @UserID varchar(25)
DECLARE @UserName nvarchar(20)

DECLARE DB_Cursor CURSOR LOCAL FAST_FORWARD FOR

SELECT UserID, UserName FROM dbo.TempData1
 
OPEN DB_Cursor
FETCH NEXT FROM DB_Cursor
INTO @UserID, @UserName
WHILE @@FETCH_STATUS = 0
BEGIN

UPDATE dbo.UserInfo
SET UserName = @UserName
WHERE UserID = @UserID

FETCH NEXT FROM DB_Cursor
INTO @UserID, @UserName

END

CLOSE DB_Cursor
DEALLOCATE DB_Cursor

それではデータを確認してみましょう。

SELECT * FROM dbo.UserInfo
GO

どうですか?
「dbo.UserInfo」テーブルのtest02, test03, test04のUserNameは変更されたのが確認できましたか?

こういう感じで「CURSOR」が使える範囲は広いです。
だが、使い間違えると処理時間がかかり過ぎたり、負荷がかかり過ぎますので注意して使いましょう。
ここまでが「CURSOR」の説明で、上記の例文を「CURSOR」を使わないで同じ結果がでる処理方法を紹介したいと思います。

UPDATE dbo.UserInfo
SET UserName = B.UserName
FROM dbo.UserInfo AS A
JOIN dbo.TempData1 AS B
ON A.UserID = B.UserID

これで終わりです。
SQLは簡単でしょう?? 
このSQLが上記の「CURSOR」と同じ処理結果が出ます。
こっちの方が負荷もかからないし、処理速度も速いです。

今回は「CURSOR」について基本テンプレートと簡単な例文と一緒に説明をしました。

コメント