カーソル-コンテキストメモリ領域へのリンク。 SQLプログラミング言語の一部の実装(Oracle、Microsoft SQL Server)では、クエリの実行時に取得される結果セットとそれに関連付けられた現在のレコードポインター。 カーソルは、代替データウェアハウスを表す仮想テーブルだと思います。 同時に、カーソルを使用して、通常の配列のデータとしてデータにアクセスできます。
カーソルはストアドプロシージャで使用されます。 かなりの理論、例を見てみましょう。
データベースがあります(データベースは少し良くありません、これは私の研究室の仕事の1つですが、データベースの先生はそのような構造を主張しました)
/* */
CREATE TABLE `bank` (
`BankId` INTEGER (11) NOT NULL ,
`BankName` VARCHAR (50) COLLATE utf8_bin NOT NULL DEFAULT '' ,
`Address` VARCHAR (50) COLLATE utf8_bin NOT NULL DEFAULT '' ,
`Phone` VARCHAR (50) COLLATE utf8_bin NOT NULL DEFAULT '' ,
PRIMARY KEY (`BankId`)
)ENGINE=InnoDB
CHARACTER SET 'utf8' COLLATE 'utf8_bin' ;
/* */
CREATE TABLE `bankdistribution` (
`BankId` INTEGER (11) NOT NULL ,
`Persent` INTEGER (11) DEFAULT NULL ,
`ContributeAmount` DECIMAL (10,0) NOT NULL ,
`ClientId` INTEGER (11) NOT NULL ,
PRIMARY KEY (`BankId`, `ClientId`),
KEY `BankId` (`BankId`),
KEY `ClientId` (`ClientId`),
CONSTRAINT `bankdistribution_fk` FOREIGN KEY (`BankId`) REFERENCES `bank` (`BankId`),
CONSTRAINT `bankdistribution_fk1` FOREIGN KEY (`ClientId`) REFERENCES `client` (`ClientId`)
)ENGINE=InnoDB
/* */
CREATE TABLE `client` (
`ClientId` INTEGER (3) NOT NULL AUTO_INCREMENT,
`CreditCardId` BIGINT(10) NOT NULL ,
`Surname` VARCHAR (50) COLLATE utf8_bin NOT NULL DEFAULT '' ,
`Name` VARCHAR (50) COLLATE utf8_bin NOT NULL DEFAULT '' ,
`FirstName` VARCHAR (50) COLLATE utf8_bin NOT NULL DEFAULT '' ,
`Phone` VARCHAR (50) COLLATE utf8_bin NOT NULL DEFAULT '' ,
`Address` VARCHAR (50) COLLATE utf8_bin NOT NULL DEFAULT '' ,
`SafeId` INTEGER (5) NOT NULL ,
PRIMARY KEY (`ClientId`, `CreditCardId`),
KEY `ClientId` (`ClientId`)
)ENGINE=InnoDB
AUTO_INCREMENT=11 CHARACTER SET 'utf8' COLLATE 'utf8_bin'
* This source code was highlighted with Source Code Highlighter .
このリクエストに対応するために、各銀行を順番に受け取り、いくつかのアクションを実行する必要があるとします
。 したがって、LIMIT NUMBER_NOUCH_WRITE_NAME、1を使用して、サイクル内の各レコードをバンクテーブルから順番に抽出し、NUMBER_NOUGH_NAME_WORDの値を1ずつ増やしながら、必要なアクションを実行します。Select `bank`.* FROM `bank` LIMIT ___,1
Begin
/* */
Declare vBankId integer ;
Declare vBankName VARCHAR (50);
Declare vAddress VARCHAR (50);
Declare vPhone VARCHAR (50);
/* hadler - a*/
Declare done integer default 0;
/* */
Declare BankCursor Cursor for Select `bank`.`BankId`,`bank`.`BankName`,`bank`.`Address`,`bank`.`Phone`, FROM `bank` where 1;
/*HANDLER , */
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
/* */
Open BankCursor;
/* */
WHILE done = 0 DO
FETCH BankCursor INTO vBankId,vBankName,vAddress,vPhone;
END WHILE ;
/* */
Close BankCursor;
END ;
* This source code was highlighted with Source Code Highlighter .
ここでさらに詳しく説明しましょう。 最初のハンドラーは、例外を処理するために必要です-データが終了したときの処理(つまり、カーソルが空になります)。 したがって、エラーメッセージではなくデータが終了すると、done変数の値が1に設定され、最初にdone = 0になります。 SQLSTATEの詳細はこちら-dev.mysql.com/doc/refman/5.1/en/error-messages-server.html;
エラー:1329 SQLSTATE:02000(ER_SP_FETCH_NO_DATA)
メッセージ:データなし-フェッチ、選択、または処理されたゼロ行
SQLSTATE:02000は、カーソルの最後に到達したとき、またはselectまたはupdateが空の文字列を返したときに起動します。
次の行では、カーソルDECLARE cursor_name CURSOR FOR select_statementを宣言しました。
カーソルを開くcursor_nameを開きます。
次に、カーソルの最後に到達するまで(WHILE done = 0 DO)、データを抽出して処理します。
ストアドプロシージャを終了する前にカーソルを閉じる必要があります。 cursor_nameを閉じます。
複雑なことは何もないようです。 しかし、SQLSTATE '02000'では、多くの落とし穴があります。
WHILE done = 0 DO
FETCH BankCursor INTO vBankId,vBankName,vAddress,vPhone;
/* */
Select (ContributeAmount) INTO vContributeAmountSUM FROM bankdistribution where BankId = vBankId limit 1;
END WHILE ;
* This source code was highlighted with Source Code Highlighter .
構文の点ではすべてが適切で正しいです。 しかし、論理的な観点からは、ありません。 投資家が銀行の口座を開設せずに、Select(ContributeAmount)INTO vContributeAmountSUM FROM bankdistributionの場合、BankId = vBankId limit 1; SQLSTATE:02000は機能し、done変数は1に設定され、whileループは予想より早く終了します。 これは、以下を行うことで回避できます
WHILE done = 0 DO
FETCH BankCursor INTO vBankId,vBankName,vAddress,vPhone;
/* */
Select ount(ContributeAmount) INTO vContributeAmountSUM FROM bankdistribution where BankId = vBankId limit 1;
/* */
if (vContributeAmountSUM > 0) then
/* */
Select ContributeAmount INTO vContributeAmountSUM FROM bankdistribution where BankId = vBankId limit 1;
end if ;
END WHILE ;
* This source code was highlighted with Source Code Highlighter .
貢献があるかどうかを確認した最初の要求(ない場合はvContributeAmountSUM == 0)、ある場合のみデータを取得します。
レベルアップ
ここで、各クライアントの異なる銀行の口座の合計金額を消去する必要があるとしましょう
選択合計のClientSummCursorカーソルを宣言
Declare ClientSummCursor Cursor for Select sum (`bankdistribution`.`ContributeAmount`),`bankdistribution`.`ClientId` FROM `bankdistribution` Inner Join client on (client.ClientId = bankdistribution.`ClientId`) where 1 group by `bankdistribution`.`ClientId`;
Open ClientSummCursor;
WHILE done = 0 DO
FETCH BankCursor INTO vBankId,vBankName,vAddress,vPhone;
/* */
Select ount(ContributeAmount) INTO vContributeAmountSUM FROM bankdistribution where BankId = vBankId limit 1;
/* */
if (vContributeAmountSUM > 0) then
/* */
Select ContributeAmount INTO vContributeAmountSUM FROM bankdistribution where BankId = vBankId limit 1;
end if ;
/* */
FETCH ClientSummCursor INTO vSum,vClientId;
.
END WHILE ;
* This source code was highlighted with Source Code Highlighter .
BankCursor、SQLSTATE:02000のデータが失敗する前にClientSummCursorカーソルのデータが終了し、done変数が1に設定され、whileループが予想より早く終了した場合にも、同じ状況が発生する可能性があります。 これは、以下を行うことで回避できます
Open ClientSummCursor;
WHILE done = 0 DO
FETCH BankCursor INTO vBankId,vBankName,vAddress,vPhone;
/* */
Select ount(ContributeAmount) INTO vContributeAmountSUM FROM bankdistribution where BankId = vBankId limit 1;
/* */
if (vContributeAmountSUM > 0) then
/* */
Select ContributeAmount INTO vContributeAmountSUM FROM bankdistribution where BankId = vBankId limit 1;
end if ;
/* sqlstate */
SET old_status = done;
/* */
FETCH ClientSummCursor INTO vSum,vClientId;
/* , sqlstate 0200 */
if (done = 0 ) then
.
end if ;
/* while done */
set done = old_status;
END WHILE ;
* This source code was highlighted with Source Code Highlighter .
この場所を読んでくれたすべての人に感謝します。これが誰かに役立つと思います。