MSDE FunClub 現在までのアクセスカウント数 最終更新日 : 2000/08/18
Microsoft Data Engine FunClub
Since 2000.08.18
SQLServer7.0/MSDE 完全トレーニングテキスト(上巻)
【第7章433p 〜 440p掲載】

-- [SQL07_07.SQL]
--             SQLServer7.0  Transact-SQL言語
--             日本技術ソフト開発  堀川 明
--            http://www.horikawa.ne.jp/msde/
--
-- このSQLプログラムは、キーセットドリブンカーソル
-- を使ったページ単位のレコード表示処理です
--

-- カレントデータベースを MySampleTest にする
    USE MySampleTest
GO

-- (件処理されました)のメッセージを抑止する
    SET NOCOUNT ON
GO


-- *********************************************************
--     【指定された名前のストアドプロシージャを削除する】
-- *********************************************************
    IF( (object_id('DELETE_MyPROC') IS NOT NULL) AND
         OBJECTPROPERTY( object_id('DELETE_MyPROC'),'IsProcedure') = 1 )
    BEGIN
             PRINT '既存のストアドプロシージャDELETE_MyPROC を削除しました'
             DROP PROCEDURE DELETE_MyPROC 
    END
GO
    --////////////////////////////////
      CREATE PROCEDURE DELETE_MyPROC
    --////////////////////////////////
             @proc_name    varchar(40) -- ストアドプロシージャの名前
    AS
       IF( (object_id(@proc_name) IS NOT NULL) AND
            OBJECTPROPERTY( object_id(@proc_name),'IsProcedure') = 1 )
       BEGIN
             PRINT '既存のストアドプロシージャ' + @proc_name + 'を削除しました'
             EXECUTE( N'DROP PROCEDURE ' + @proc_name ) 
       END
GO



-- ******************************************
--      【共通ストアドプロシージャ】
--  グローバルカーソル処理で、共通に使われます
-- ******************************************

-- *********************************************************
--             【グローバルカーソルを定義します】
--  カーソル名やSQL文などは、ストアドプロシージャの引数で渡されます
-- *********************************************************

    DELETE_MyPROC 'DEFINE_CURSOR'           -- 既存のものを削除する
GO
   --////////////////////////////////    
      CREATE PROCEDURE DEFINE_CURSOR
   --////////////////////////////////
             @cur_name  varchar(40)  ,      -- グローバルの名前
             @cur_sql   varchar(512) ,      -- カーソルを定義するSQL文
             @cur_up    varchar(128) = ''   -- FOR UPDATE of 句
    AS
     SET NOCOUNT ON
     DECLARE @sql varchar(512)

     -- グローバルカーソルを定義します
     SET @sql = 'DECLARE ' + @cur_name + ' CURSOR ' +
                'GLOBAL SCROLL KEYSET ' +
                'OPTIMISTIC    ' +
                'TYPE_WARNING  ' +
                'FOR ' + @cur_sql + ' ' + @cur_up

     -- グローバルカーソルなので、この接続期間中はどこでも参照OK
     EXECUTE( @sql )
GO


-- *********************************************************
--         【指定位置からのページ単位レコードの取得】
-- *********************************************************

    DELETE_MyPROC 'FETCH_CURSOR'            -- 既存のものを削除する
GO
   --//////////////////////////////    
     CREATE PROCEDURE FETCH_CURSOR
   --//////////////////////////////
             @table_name   varchar(20)  ,   -- 作業用テーブル名
             @fetch_procnm varchar(40)  ,   -- カーソル操作ストアドプロシージャ名
             @start        int          ,   -- レコード表示開始位置
             @total        int              -- 1ページ分に表示するレコード総数

    AS
     DECLARE @sql varchar(512)
     DECLARE @Ret int
     SET NOCOUNT ON

     -- 指定されたページに対応するレコードを作業用テーブルに挿入する
    EXECUTE @Ret = @fetch_procnm  @start , @total

     -- レコードが全然ありませんか?
     IF( @Ret = -1 ) RETURN -1

     -- 作業用テーブルの内容を全部出力します
     -- ここで出力すると連結ができない
     -- Access2000-ADPのことを考え、ここではSELECT文を実行しません
     --** EXECUTE( 'SELECT * FROM ' +  @table_name )
    RETURN @Ret 
GO



-- ******************************************
--      【個別ストアドプロシージャ】
--  グローバルカーソル毎に作成する必要があります
-- ******************************************


-- ***************************************************************
--                  【グローバルカーソルを破棄する】
--    カーソルが未定義状態で呼び出されてもいいように対応すること
--      My_cur_initの中で呼び出されるので、先に記述しましょう
-- ***************************************************************
    DELETE_MyPROC 'My_cur_term'      -- 既存のものを削除する
GO
   --//////////////////////////////
      CREATE PROCEDURE My_cur_term
   --//////////////////////////////
  AS
    SET NOCOUNT ON
    DECLARE @ST SMALLINT

    --グローバルカーソルの状況を取得する
    SELECT @ST = CURSOR_STATUS( 'global' , 'My_cur' )
    
    -- グローバルカーソルを閉じる
    IF( @ST >= 0 )  CLOSE  My_cur

   -- 参照関係を解除する
    IF( @ST >= -1 ) DEALLOCATE My_cur
GO
-- ***************************************************************
--                【グローバルカーソルを作成します】
-- ***************************************************************
    DELETE_MyPROC 'My_cur_init'      -- 既存のものを削除する
GO
  --//////////////////////////////
     CREATE PROCEDURE My_cur_init
  --//////////////////////////////
             @st    int ,            -- 検索開始番号
             @ed    int              -- 検索終了番号
   AS
    SET NOCOUNT ON
    DECLARE @sql varchar(512)

    -- 既存のグローバルカーソルが有効のときは、それを破棄します
    EXECUTE  My_cur_term

    -- カーソルを定義するSQL文を作成します
    SET @sql = 'SELECT 社員コード,フリガナ,氏名 FROM MySampleTest..社員 ' +
           'WHERE ( 社員コード BETWEEN ' + STR(@st) + ' AND ' + STR(@ed) + ') ' +
           'ORDER BY 社員コード '

    -- カーソルを定義する
    EXECUTE DEFINE_CURSOR 'My_cur' , @sql

    -- グローバルカーソルを開く
    OPEN  My_cur

    -- グローバルカーソルにあるレコード総数をクライアント側に出力します
    -- カーソルは、同期カーソルです
    SELECT @@CURSOR_ROWS AS 検索結果レコード件数

    --関数値でも、その値を戻します
    RETURN @@CURSOR_ROWS
GO



-- ***************************************************************
--       【グローバルカーソルのページ単位操作オペレーション】
--  1)このストアドプロシージャは、グローバルカーソル毎に個別作成が
--    必要です
--  2)このプロシージャは、グローバルカーソルの指定位置から指定された
--    レコード数を一時テーブルに記憶します。
--  3)一時テーブルに記憶されたレコードを、SELECT文で出力します
--【注意】
--  グローバルカーソルが未定義状態で呼び出されてもいいように対応すること
-- ***************************************************************

    DELETE_MyPROC 'Main_GetRecord_From_My_cur'      -- 既存のものを削除する
GO
  --////////////////////////////////////////////
    CREATE PROCEDURE Main_GetRecord_From_My_cur
  --////////////////////////////////////////////
             @fetch_procnm varchar(40)  ,   -- カーソル操作を実際に行なうストアドプロシージャ名
             @start        int          ,   -- レコード表示開始位置
             @total        int              -- 1ページ分に表示するレコード個数
  AS
     -- Access2000 ADPプロジェクトで、このストアドプロシージャが返す
     -- レコードセットの列名リストを、Accessに教えます
     -- GOTO文とラベルの間に、ストアドプロシージャのレコードセットと
     -- 同じものを定義してください
     GOTO  L100
           SELECT 社員.社員コード , 社員.フリガナ , 社員.氏名 FROM 社員
L100:
      --**** プログラム開始 ****

      DECLARE @Ret int

    --グローバルカーソルが作成済みですか?
      IF CURSOR_STATUS( 'global' , 'My_cur' ) = -3
        BEGIN
               RETURN -1    -- カーソルが存在しません
        END

      -- Test
      --raiserror('START=%d total=%d',16,1,@start , @total)
      --return

      -- カーソルから取得したレコードを記憶する一時テーブルを作成する
      -- この一時テーブルは、このストアドプロシージャが終わると自動消滅します
      CREATE TABLE #TMP_My_cur(
                       社員コード  int   ,
                       フリガナ    varchar(80) ,
                       氏名        varchar(40)
      )

     -- 共通SP(ストアドプロシージャFETCH_CURSOR)の中で全部処理します
     -- 一時テーブルが共通SPの中では作成できないため、このSPが必要です
     -- また一時テーブルは下位SPの中まで有効なことを活用します
     EXECUTE  @Ret = FETCH_CURSOR
                   '#TMP_My_cur'    ,   -- 上で作成した作業用テーブル名
                   @fetch_procnm    ,   -- カーソル操作を実際に行なうストアドプロシージャ名
                   @start           ,   -- レコード表示開始位置
                   @total               -- 1ページ分に表示するレコード個数

    --ここで連結する
    SELECT 社員.社員コード, 社員.フリガナ , 社員.氏名  FROM 社員
          INNER JOIN  #TMP_My_cur on 社員.社員コード = #TMP_My_cur.社員コード

    -- FETCH_CURSORストアドプロシージャの結果を戻す
    RETURN @Ret
GO


-- *********************************************************************
--  【グローバルカーソル My_cur の現在行の内容を一時テーブルに記憶する】
--  1)このストアドプロシージャは、グローバルカーソル毎に個別作成が
--    必要です
--  2)このプロシージャは、グローバルカーソルの指定位置から指定された
--    レコード数を一時テーブルの中に書き込む実務作業を担当します。
-- *********************************************************************

    DELETE_MyPROC 'GetRecord_From_My_cur'      -- 既存のものを削除する
GO
  --/////////////////////////////////////////    
     CREATE PROCEDURE GetRecord_From_My_cur
  --/////////////////////////////////////////
             @pos       int ,                  -- 読み込み開始位置
             @rec_page  int                    -- 読み込みレコード数   
    AS
      SET NOCOUNT ON
      DECLARE @社員コード int
      DECLARE @フリガナ   varchar(80)
      DECLARE @氏名       varchar(40)
      DECLARE @Ret        int
      DECLARE @Flag       int

      -- 指定された行番号に移動する
      FETCH ABSOLUTE @pos FROM My_cur INTO @社員コード , @フリガナ , @氏名

      -- 移動が成功したらその内容を一時テーブルに挿入する
      SET @Flag =  @@FETCH_STATUS
      IF( @Flag = -1 )
          BEGIN
                RETURN -1     -- そのレコード番号は存在しません
          END

      IF( @Flag = 0 )         -- 正常に指定位置に移動ができました
         BEGIN 
            INSERT INTO #TMP_My_cur VALUES( @社員コード , @フリガナ,@氏名 )
            SET @rec_page = @rec_page - 1
         END

      -- 残りのレコードを読み込む
      WHILE( @rec_page <> 0 )
        BEGIN
              -- 1行読み込む
              FETCH NEXT FROM My_cur INTO @社員コード , @フリガナ , @氏名

              SET @Flag = @@FETCH_STATUS
              IF( @Flag = 0 )
                  BEGIN
                        -- 正常読み込み
                        INSERT INTO #TMP_My_cur VALUES( @社員コード , @フリガナ , @氏名 )
                        SET @rec_page = @rec_page - 1
                  END
              ELSE IF( @Flag = -1 )
                  RETURN -2  -- EOF? を検出しました(レコードが途中で無くなりました)
        END
     RETURN 0
GO


-- *********************************************************
--                【プログラム使用見本例】
-- *********************************************************

    -- グローバルカーソルを作成します
    EXECUTE My_cur_init 100 , 400


  GOTO L1000

    PRINT '1行目から5行目の出力(1)'
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 1 , 5

    PRINT '1行目から5行目の出力(2)'
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 1 , 1
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 2 , 1
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 3 , 1
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 4 , 1
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 5 , 1

    PRINT '1行目から5行目の出力(3)'
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 1 , 2
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 3 , 2
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 5 , 1

L1000:

    PRINT '1行目から15行目の出力(1)'
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 1 , 15

    PRINT '1行目から15行目の出力(2)'
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 1  , 10
    EXECUTE Main_GetRecord_From_My_cur  'GetRecord_From_My_cur' , 11 , 5

    -- グローバルカーソルを破棄します
    EXECUTE My_cur_term
GO




技術評論社の書籍ガイドへ
上巻:ISBN4-7741-0965-7

ウィンドウを閉じる


(株)日本技術ソフト開発 責任編集:堀川 明
MSDE FunClubに関するご意見・ご要望等ございましたら、 msdefun@horikawa.ne.jp までご連絡下さい。
HOME: http://www.horikawa.ne.jp/msde/


MSDE FunClubの運営は、マイクロソフト社とは一切の関係はありません