ホームページ  >  記事  >  データベース  >  Mysql プロシージャのパラメータが NULL である問題の分析

Mysql プロシージャのパラメータが NULL である問題の分析

高洛峰
高洛峰オリジナル
2016-12-02 14:48:261577ブラウズ

最近、プロシージャを作成しているときに興味深いことに気づきました。Mysql プロシージャには、パラメータを渡すときにいくつかの「不正な」パラメータを処理する独自の方法があります。たとえば、最初に int として定義されたパラメータが null
として渡された場合、MySQL プロシージャは通常どおり実行されます。
ライブラリテーブル構造:
データベースdb5を作成します;

use db5;

テーブルが存在する場合は削除します t;
テーブルを作成します t(
id int 主キー auto_increment,
value int
);

テーブルを作成 t2(
id int主キー auto_increment,
value float
);
プロシージャの作成:
デリミタ //
CREATE PROCEDURE p14 (IN パラメータ 1 INT)
BEGIN
DECLARE 変数 1 INT;
SET 変数 1 = パラメータ 1 + 1;
INSERT INTO t(value) VALUES (variable1);
END;
//
delimiter ;

演算結果:


mysql> call p14(5);
クエリ OK、1 行が影響を受ける (0.02 秒)

mysql> select * from t;
+----+------+
| 値 |
+----+------+
| -----+
セット内の 1 行 (0.00 秒)

mysql> call p14(null);
クエリ OK、影響を受ける 1 行 (0.04 秒)

mysql> select * from t;
+--- -+------+
| 値 |
+------+
| 6 |
+---+ -------+
セット内の 2 行 (0.00 秒)


パラメーターparameter1に5に等しい値が渡されると、6がテーブルに挿入され、データは正常であることに気づきましたか。
パラメータparameter1がnullとして渡されると、テーブルにNULLが挿入されるのはなぜですか?

この点については、変数を宣言するためのステートメントを参照してください。このドキュメントでは、次のように説明されています。declare ステートメントは、ローカル変数を宣言するために使用されます。変数にデフォルト値を指定するには、DEFAULT 句を含めます。値は式として指定でき、定数である必要はありません。 DEFAULT 句がない場合、初期値は NULL になります。

上記のことから、NULL=NULL+1 という新たな疑問が生じます。ははは、この時点で SET variable1 =parameter1 + 1; について合理的に説明できるのは何でしょうか。

これは Wang 先生による説明です (2 番目の説明は非常に古典的です ~~~):
1 null+1=null
null は「ポインター」のように動作する、つまり「アドレスの内容」を指すからです。 0" の場合、コンテンツが "null" の場合、null として動作します。そのため、INT の指定も空になります。ただし、「コンテンツ」に値がある場合、MYSQL の場合は「乱数」または 0 になります。このアドレスのコンテンツが格納されると、値は固定されます。 =B+1 、A は B が null の場合にのみ NULL になります。SET A=B+1 は SET (B+1) として理解できます。A は「現在」で置き換えられているため、A が誰であるかは問題ではありません。重要なのは B+ 1 です。
主に SET を分離できないため、このアイデアは検証されていません。mysql5 のドキュメントではこのステートメントがサポートされていますが、英語版では中国語の「set」表現の代わりに「replacement」が使用されています。意味がより近い気がします! (SET)

新しい質問: A=1/B および B=0 の場合、正常に実行できますか?

mysql>

delimiter //
CREATE PROCEDURE p15 (IN パラメータ 1 INT)
BEGIN
declare variable2 float(5,3);
SET 変数 2 =1/ パラメータ 1;
INSERT INTO t2(value) VALUES (variable2);
END;
//
delimiter ;

実行結果:

mysql> call p15(0);
Query OK、1 行が影響を受ける (0.03 秒)

mysql> select * from t2;
+---- +-----+
| 値 |
+----+------+
| 1 | +
セット内の 1 行 (0.00 秒)

mysql> call p15(1);
クエリ OK、1 行が影響を受ける (0.03 秒)

mysql> select * from t2;
+---+--- ----+
| 値 |
+----+------+
| 1 |
| 読者は気づきましたか? これも正常に機能します。実際、この問題は、mysql の SQL サーバー モード パラメーターの詳細で見つかります。
MySQL サーバーはさまざまな SQL モードで動作でき、さまざまなモードをさまざまなクライアントに適用できます。このようにして、各アプリケーションは独自のニーズに応じてサーバーの動作モードをカスタマイズできます。
スキーマは、MySQL がどの SQL 構文をサポートする必要があるか、およびどのような種類のデータ検証チェックを実行する必要があるかを定義します。これにより、さまざまな環境や他のデータベース サーバーで MySQL を簡単に使用できるようになります。
--sql-mode="modes" オプションを使用して mysqld を起動することで、デフォルトの SQL モードを設定できます。リセットしたい場合は、この値を空のままにすることもできます (--sql-mode = "")。
SET [SESSION|GLOBAL] sql_mode='modes' ステートメントを使用して sql_mode 変数を設定し、起動後に SQL モードを変更することもできます。 GLOBAL 変数を設定するには SUPER 権限が必要であり、その時点から接続されているすべてのクライアントの動作に影響します。 SESSION 変数の設定は、現在のクライアントにのみ影響します。どのクライアントでも、セッションの sql_mode 値をいつでも変更できます。
Modesis は、カンマ (「,」) で区切られた一連の異なるモードです。 SELECT @@sql_mode ステートメントを使用して、現在のモードをクエリできます。デフォルト値は空です (モードが設定されていません)。
STRICT_TRANS_TABLES
すべてのストレージ エンジンに対して厳密モードを有効にします。不正なデータ値は拒否されます。詳細な手順は後ほど説明します。
· STRICT_TRANS_TABLES
トランザクション ストレージ エンジン、および場合によっては非トランザクション ストレージ エンジンに対してストリクト モードを有効にします。詳細な手順は後ほど説明します。
厳密モードは、MySQL が不正な入力値または欠落している入力値を処理する方法を制御します。値が不正になる理由はいくつかあります。たとえば、データ型が間違っている、列に収まらない、範囲外であるなどです。新しく挿入された行に DEFAULT 句が明示的に定義されていない列の値が含まれていない場合、その値は失われます。
トランザクション テーブルの場合、STRICT_ALL_TABLES または STRICT_TRANS_TABLES モードが有効になっている場合、ステートメントに不正な値または欠落している値があるとエラーが発生します。ステートメントは破棄され、ロールされます。
非トランザクションテーブルの場合、挿入または更新の行 1 に不正な値が発生した場合、どちらのモードも同じように動作します。ステートメントは破棄され、テーブルは変更されないままになります。ステートメントが複数の行を挿入または変更し、不正な値が 2 行目以降の行に発生する場合、結果はどの strict オプションが有効になっているかによって異なります:
ERROR_FOR_DIVISION_BY_ZERO
strict モードでは、INSERT または UPDATE 中に、ゼロで除算した場合 (またはMOD (X, 0))、エラーが発生します (それ以外の場合は警告)。モードが指定されていない場合、MySQL はゼロで除算するときに NULL を返します。 INSERT IGNORE または UPDATE IGNORE で使用すると、MySQL はゼロ除算の警告を生成しますが、操作結果は NULL になります。
他のパラメータもあります。読者は mysql ドキュメントを参照してください。

ERROR_FOR_DIVISION_BY_ZERO パラメータを sql_mode に追加すると、mysql を再起動します
mysql> 'sql_mode';
+----------------------- のような変数を表示します。 ----------------------- -------------------------------------- ---------- -----
---------------+
| 変数名 | - --------+---------------------------------------- - ----------------------
-------------------------- - -+
| sql_mode | STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_
USER,NO_ENGINE_SUBSTITUTION |
+--------------+-------------- -- --------------------------------------
- ---------- ----------+
セット内の 1 行 (0.00 秒)

mysql> select 1/0;
+-- ----+
|
+------+
| NULL |
+------+
セット内 1 行、1 つの警告 (0.00 秒)

1 つの警告が表示されます。この警告を見てみましょう。
mysql> 警告を表示;
+-----+-----+--------------+
|
+-- ----------+------+--------------+
| 0 による除算 | ----------+--------------+
セット内の 1 行 (0.00 秒)

mysql> exit
Bye
sql_mode から ERROR_FOR_DIVISION_BY_ZERO パラメータを削除したら、mysql を再起動します試してください:

C:Documents and SettingsAdministrator>net stop mysql
MySQL サービスが停止しています。
MySQL サービスは正常に停止されました。


C:Documents and SettingsAdministrator>net start mysql

MySQL サービスが正常に開始されました。


mysql> 1/0;
+-----+
| 1/0 |
+------+
| 1 行in set (0.00 sec)

mysql> show warnings;
Empty set (0.02 sec)
現時点では、警告の内容は空です。
この時点で、読者もその理由を知っています。時間があれば、他のデータベースを試して、同じかどうか確認してください

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:MySQLデータ形式次の記事:MySQLデータ形式