この章では、MySQL ビュー、ストアド プロシージャ、トリガーなどのいくつかのストレージ オブジェクトを紹介することを目的としており、ビューとは何か、ストアド プロシージャとは何か、トリガーとは何かを紹介します。また、ビュー、ストアド プロシージャ、トリガーを作成、クエリ、変更、削除するにはどうすればよいでしょうか? そして、対応する例を通してその活用方法をさらに紹介し、理解を深めていきます。
1. 見る
ビューとは何ですか?
View(ビュー)は仮想テーブルです。ビュー内のデータは実際にはデータベースに存在しません。行と列のデータはカスタム ビューのクエリで使用されるテーブルから取得され、ビューの使用時に動的に生成されます。
平たく言えば、ビューはクエリの SQL ロジックのみを保存し、クエリ結果は保存しません。したがって、ビューを作成するときの主な作業は、この SQL クエリ ステートメントの作成になります。
これを言うのは少し青白く、まだよく理解していないと思います。ビューを作成、変更、削除することでさらに説明しましょう。
①ビューを作成する
-- [ WITH [ CASCADED | LOCAL ] CHECK OPTION ] 是视图检查选项, 后面会讲到
CREATE [OR REPLACE] [force] VIEW 视图名称[(列名列表)] AS SELECT语句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ] [with read only]
-- 示例:创建一个查询tb_user表的视图user_v_1, 查询字段是id,name
create or replace view user_v_1 as select id,name from tb_user where id <= 10;
注: ここでのビューは仮想テーブルであり、実際のテーブルではなく、select ステートメントの論理カプセル化です。
②クエリ ビュー
-- 查看创建视图语句
SHOW CREATE VIEW 视图名称;
-- 查看视图数据
SELECT * FROM 视图名称 ...... ;
③ビューを変更する
-- 方式一:和创建视图语句一致, 但这里必须使用 [OR REPLACE]
CREATE [OR REPLACE] VIEW 视图名称[(列名列表)] AS SELECT语句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
-- 方式二
ALTER VIEW 视图名称[(列名列表)] AS SELECT语句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
④ビューの削除
DROP VIEW [IF EXISTS] 视图名称 [,视图名称] ...
チェックオプションの表示
try to check オプションを紹介する前に、try to check? を使用する必要がある理由を示す例を見てみましょう。
-- 为tb_user表创建一个视图
create or replace view user_v_1 as select id,name from tb_user where id <= 10;
-- 查询该视图的数据(id<=10)
select * from user_v_1;
-- 向视图插入两条数据
insert into user_v_1 values(6,'Tom');
insert into user_v_1 values(17,'Tom22');
-- 查询tb_user表的数据, 这两条数据都能成功的在 tb_user 表中查看到
select * from tb_user;
-- 再次查询该视图的数据, 能看到id=6的数据, 不能看到id=17的数据
select * from user_v_1;
ビューで id=17 のデータが見つからないのはなぜですか?
ビューの作成時に指定された条件は id<=10 であり、id 17 のデータは適格ではないため、クエリは実行されませんが、このデータは実際にベース テーブルに正常に挿入されています。ビューを定義するときに条件を指定すると、データの挿入、変更、削除を行うときに、条件を満たした場合のみ動作し、そうでない場合は動作できないのでしょうか。答えは「はい」です。これには、ビューの検査オプションの助けが必要です。
解決:
ビューを作成するステートメントの最後に[WITH [ CASCADED | LOCAL ] CHECK OPTION ]チェック オプションを追加すると、MySQL は挿入、更新、削除など、ビューを通じて変更されている各行をチェックします。ビューの定義に準拠するようにします。定義が満たされていない場合、次のエラーが報告され、操作は失敗します。
さらに、MySQL では、別のビューに基づいてビューを作成でき、依存するビュー内のルールの一貫性もチェックされます。チェックの範囲を決定するために、mysql にはCASCADEDとLOCALの 2 つのオプションが用意されています。デフォルト値は CASCADED です。次に、2 つのオプションについて説明します。
① CASCADED(カスケード)
たとえば、v2 ビューの作成時にチェック オプションがカスケードとして指定されているが、v1 ビューの作成時にチェック オプションが指定されていない場合、v2 ビューは v1 ビューに基づきます。次に、v2 をチェックすると、v2 の限定されたスコープがチェックされるだけでなく、v1 に関連付けられたビュー v1 の限定されたスコープもカスケードされます。
②LOCAL(ローカル)
たとえば、v2 ビューは v1 ビューに基づいており、v2 ビューの作成時にチェック オプションがローカルとして指定されます (1) v1 ビューの作成時にチェック オプションが指定されていない場合、v2 のみがチェックされますv2 の限定された範囲のチェックを実行すると、v2 の関連ビュー v1 はチェックされません (2) v1 ビューの作成時にチェック オプションが指定されている場合、v2 の限定された範囲をチェックすると、その限定された範囲はチェックされませんv1 のものも同時にチェックされます。(MySQL 8.0が有効です)
CASCADED と LOCAL の主な違いは、
どちらもビューを再帰的に検索することです。違いは、
CASCADED は前のビューにチェック オプションがあるかどうかに関係なく、限られた範囲で実行するのに対し、
LOCAL は前のビューにチェック オプションがあるかどうかをチェックすることです。 , ある場合は限定された範囲で実施されますが、ない場合は実施されません。
ビューのデータは気軽に更新できない!!!
ビューを更新(データの挿入、削除、更新など)するには、ビュー内の行と基になるテーブル内の行の間に 1 対 1 の関係が必要です。ビューに次のいずれかが含まれている場合、ビューは更新できません。
- 集計関数またはウィンドウ関数 (SUM()、MIN()、MAX()、COUNT() など)
- 明確な
- グループ化
- 持っている
- UNION または UNION ALL
上記のいずれかを使用すると、ビューの行データまたはフィールドとベース テーブルの行データまたはフィールドの間に 1 対 1 の対応がなく、更新操作は失敗します。!!!
ビューについて、最後にその機能を見てみましょう。
- Simplicity
View は、ユーザーのデータの理解を簡素化するだけでなく、操作も簡素化します。頻繁に使用するクエリをビューとして定義できるため、ユーザーは後続の操作のすべての条件を毎回指定する必要がありません。 - セキュリティ
データベースは認証できますが、データベースの特定の行および特定の列に対しては認証できません。ビューを通じて、ユーザーは表示できるデータのみをクエリおよび変更できます。 - データの独立性
ビューは、ユーザーがベース テーブルの構造の変更による影響を防ぐのに役立ちます。つまり、ベース テーブルのフィールド名が変更された場合でも、プログラムのニーズを満たすビューを作成するときに、エイリアスを使用してフィールド名の変更をシールドできます。
2 番目に、ストアド プロシージャ
ストアド プロシージャとは何ですか?
ストアド プロシージャは、事前にコンパイルされてデータベースに保存されている SQL ステートメントの集合です。ストアド プロシージャを呼び出すと、アプリケーション開発者の多くの作業が簡素化され、データベースとアプリケーション サーバー間のデータ転送が削減され、効率が向上します。データ処理の良好です。一言でまとめると、ストアド プロシージャはコードをカプセル化し、データベースの SQL 言語レベルで再利用します。
ストアド プロシージャの特徴は何ですか?
- カプセル化と再利用: 特定のビジネス SQL をストアド プロシージャにカプセル化し、必要に応じて直接呼び出すことができます。
- パラメータを受け取り、データを返すことができます: ストアド プロシージャでは、パラメータを渡し、戻り値を受け取ることができます。
- ネットワークの相互作用を減らし、効率を向上させる: 複数の SQL が関係する場合、各実行はネットワーク送信になります。また、ストアド プロシージャにカプセル化されている場合は、ネットワークとの対話は 1 回だけで済みます。
同様に、ビューの作成、呼び出し、表示、削除によってさらに進みます (次の 4 つの手順で、最初のボックスは構文であり、残りのボックスまたは図は例です)。
① ストアドプロシージャを作成する
CREATE PROCEDURE 存储过程名称 ([ 参数列表 ])
BEGIN
-- SQL语句
END ;
-- 示例:创建一个存储过程p1, 用来封装查询tb_user表数据总量的SQL语句
create procedure p1()
begin
select count(*) from tb_user;
end;
② ストアドプロシージャを呼び出す
CALL 名称 ([ 参数 ]);
③ ストアドプロシージャを参照する
-- 查询某个存储过程的定义
SHOW CREATE PROCEDURE 存储过程名称 ;
-- 查询指定数据库的存储过程及状态信息
SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = 'xxx';
-- 示例:查询存储过程p1的定义
show create procedure p1;
-- 示例:查询itcast数据库的存储过程及状态信息
select * from information_schema.ROUTINES where ROUTINE_SCHEMA = 'itcast';
④ ストアドプロシージャを削除する
DROP PROCEDURE [ IF EXISTS ] 存储过程名称;
知らせ:
コマンドラインでストアドプロシージャを作成するSQLを実行する場合、SQL文の終了文字をキーワード区切り文字で指定する必要があります。
デフォルトでは、コマンド ラインは ; で終わり、クエリと削除を実行する SQL ステートメントも ; で終わるため、コマンド ラインで実行プロセスを作成するステートメントが途中で終了するのを防ぐために、コマンド ラインのターミネータは変更される。
上記のストアド プロシージャを作成する場合は、単純なクエリ ステートメントのみを使用しますが、複雑なビジネス システムで複雑なストアド プロシージャを設計する場合は、多くの文法構造を関与させる必要があります。ストアド プロシージャの文法構造を分析してみましょう。
ストアド プロシージャの文法構造 --- 変数
MySQL には、システム変数、ユーザー定義変数、ローカル変数の 3 種類の変数があります。
1. システム変数
システム変数は、ユーザー定義ではなく MySQL サーバーによって提供され、サーバー レベルに属します。グローバル変数(GLOBAL)とセッション変数(SESSION)に分かれます。
- グローバル変数 (GLOBAL): すべてのセッションのグローバル変数。
- セッション変数 (SESSION): セッション変数は 1 つのセッションに固有であり、別のセッション ウィンドウでは有効になりません。
SESSION / GLOBAL が指定されていない場合、デフォルトは SESSION セッション変数です。
① システム変数を表示する
-- 查看所有系统变量
SHOW [ SESSION | GLOBAL ] VARIABLES;
-- 可以通过LIKE模糊匹配方 式查找变量
SHOW [ SESSION | GLOBAL ] VARIABLES LIKE '......';
-- 查看指定变量的值 123
SELECT @@[SESSION.|GLOBAL.]系统变量名;
-- 示例:
show session variables ; -- 查看当前会话的系统变量
show global variables ; -- 查看全局的系统变量
show variables like 'auto%'; -- 查看当前会话以'auto'开头的系统变量
select @@session.autocommit; -- 查看当前会话的autocommit变量的值
select @@global.autocommit; -- 查看全局的autocommit变量的值
② システム変数を設定する
SET [SESSION|GLOBAL] 系统变量名 = 值 ;
SET @@[SESSION.|GLOBAL.]系统变量名 = 值 ;
2. ユーザー定義変数
ユーザー定義変数は、ユーザーが必要に応じて定義する変数であり、事前に宣言する必要がなく、使用時に「@変数名」で直接使用できます。そのスコープは現在の接続です。(注: @@ システム変数は 2 つあり、次に紹介するローカル変数はありません)
① ユーザー定義変数に値を代入する
-- 方式一
SET @var_name = expr [, @var_name = expr] ... ;
SET @var_name := expr [, @var_name := expr] ... ;
-- 赋值时,可以使用 = ,也可以使用 :=
-- 方式二
-- 查询的同时为其赋值
SELECT @var_name := expr [, @var_name := expr] ... ;
-- 将某表的某个字段的数据赋值给变量
SELECT 字段名 INTO @var_name FROM 表名;
-- 示例:
set @myname = 'itcast'; -- 设置自定义变量myname的值为itcast
set @mygender := '男',@myhobby := 'java';
select @mycolor := 'red'; -- 设置自定义变量mycolor的值为red,并使用
select count(*) into @mycount from tb_user; -- 从tb_user表的总数据量并赋值给mycount变量
② ユーザー定義変数を使用する
SELECT @var_name ;
注:
ユーザー定義変数は宣言や初期化の必要がなく、直接代入することができますが、代入せずに直接使用した場合、取得される値は NULL になります。
3. ローカル変数
ローカル変数とは、ローカルに定義され、必要に応じて有効になる変数で、アクセスする前にDECLARE文が必要です。ストアド プロシージャ内のローカル変数および入力パラメータとして使用できます。ローカル変数のスコープは、ローカル変数が宣言されている BEGIN ... END ブロックです。
CREATE PROCEDURE 表名()
BEGIN
-- 声明一个局部变量
DECLARE 变量名 变量类型 [DEFAULT ... ] ;
-- 变量类型就是数据库字段类型:INT、BIGINT、CHAR、VARCHAR、DATE、TIME等。
-- DEFAULT 是局部变量的默认值,选用
-- 为局部变量赋值
SET 变量名 = 值 ;
SET 变量名 := 值 ;
SELECT 字段名 INTO 变量名 FROM 表名 ... ;
END
-- 示例:
create procedure p2()
begin
declare stu_count int default 0; -- 声明局部变量stu_count,值默认为0
select count(*) into stu_count from student; -- 为局部变量stu_count赋值
select stu_count; -- 使用/输出局部变量stu_count
end;
call p2(); -- 调用存储过程
ストアド プロシージャの文法構造 --- if 判定
if が条件判断に使用される場合、具体的な文法構造は次のとおりです。
IF 条件1 THEN
.....
ELSEIF 条件2 THEN -- 可选
.....
ELSE -- 可选
.....
END IF;
ストアド プロシージャの文法構造 --- パラメータ
CREATE PROCEDURE 存储过程名称 ([ IN/OUT/INOUT 参数名 参数类型 ])
BEGIN
-- SQL语句
END ;
例を見てみましょう:
-- 示例:根据传入参数score,判定当前分数对应的分数等级,并返回。
-- score >= 85分,等级为优秀。
-- score >= 60分 且 score < 85分,等级为及格。
-- score < 60分,等级为不及格。
create procedure p4(in score int, out result varchar(10))
begin
if score >= 85 then
set result := '优秀';
elseif score >= 60 then
set result := '及格';
else
set result := '不及格';
end if;
end;
-- 定义用户变量 @result来接收返回的数据, 用户变量可以不用声明
call p4(18, @result);
select @result;
ストアド プロシージャの文法構造 --- case
case はフロー制御関数に似ており、次の 2 つの構文形式があります。
文法 1:
-- 含义: 当case_value的值为 when_value1时,执行statement_list1,当值为 when_value2时, 执行statement_list2, 否则就执行 statement_list
CASE case_value
WHEN when_value1 THEN statement_list1
[ WHEN when_value2 THEN statement_list2]
...
[ ELSE statement_list ]
END CASE;
文法 2:
-- 含义: 当条件search_condition1成立时,执行statement_list1,当条件search_condition2成 立时,执行statement_list2, 否则就执行 statement_list
CASE
WHEN search_condition1 THEN statement_list1
[WHEN search_condition2 THEN statement_list2]
...
[ELSE statement_list]
END CASE;
知らせ:
判定条件が複数ある場合は、and または or を使用して複数の条件を接続できます。
ストアド プロシージャの文法構造 --- ループ
MySQL には、while、repeat、loop という 3 つの主なタイプのループがあります。以下では、それらを 1 つずつ紹介します。
一方
while ループは条件付きループ制御ステートメントです。条件が満たされた後、ループ本体内の SQL ステートメントを実行します。具体的な構文は次のとおりです。
-- 先判定条件,如果条件为true,则执行逻辑,否则,不执行逻辑
WHILE 条件 DO
SQL逻辑...
END WHILE;
繰り返す
repeat は条件付きループ制御ステートメントであり、until で宣言された条件が満たされると、ループは終了します。具体的な構文は次のとおりです。
-- 先执行一次逻辑,然后判定UNTIL条件是否满足,如果满足,则退出。如果不满足,则继续下一次循环
REPEAT
SQL逻辑...
UNTIL 条件
END REPEAT;
ループ
LOOP は単純なループを実装します。SQL ロジックにループを終了する条件を追加しない場合、これを使用して単純な無限ループを実装できます。
LOOP は、次の 2 つのステートメントで使用できます。
- LEAVE: ループを終了するためにループとともに使用されます。
- ITERATE: ループ内で使用する必要があり、その機能は、現在のループの残りのステートメントをスキップし、次のループに直接入ることです。
[begin_label:] LOOP
SQL逻辑...
LEAVE label; -- 退出指定标记的循环体
ITERATE label; -- 直接进入下一次循环
END LOOP [end_label];
-- 上述语法中出现的 begin_label,end_label,label 指的都是我们所自定义的标记。
ストアド プロシージャの文法構造 --- カーソル カーソル
カーソル (CURSOR) は、クエリ結果セットを格納するために使用されるデータ型であり、ストアド プロシージャや関数を循環するために使用できます。カーソルの使用には、カーソルの OPEN、FETCH、および CLOSE の宣言が含まれます。その構文は次のとおりです。
①宣言 カーソル
DECLARE 游标名称 CURSOR FOR 查询语句 ;
-- 其和声明局部变量相似, 是不过这里的数据类型为 cursor,且后面带有查询语句
② カーソルを開く
OPEN 游标名称 ;
③ カーソルレコードを取得する
FETCH 游标名称 INTO 变量 [, 变量 ] ;
④ カーソルを閉じる
CLOSE 游标名称 ;
ストアド プロシージャの文法構造 - 条件ハンドラー
条件ハンドラー (Handler) を使用して、フロー制御構造の実行中に問題が発生した場合に、対応する処理ステップを定義できます。具体的な構文は次のとおりです。
DECLARE handler_action HANDLER FOR condition_value [, condition_value] ... statement ;
handler_action 的取值:
CONTINUE: 继续执行当前程序
EXIT: 终止执行当前程序
condition_value 的取值:
SQLSTATE sqlstate_value: 状态码,如 02000
SQLWARNING: 所有以01开头的SQLSTATE代码的简写
NOT FOUND: 所有以02开头的SQLSTATE代码的简写
SQLEXCEPTION: 所有没有被SQLWARNING 或 NOT FOUND捕获的SQLSTATE代码的简写
例を通して、カーソルと条件ハンドラーの具体的な使用法を見てみましょう。
-- 示例: 根据传入的参数uage,来查询用户表tb_user中,所有的用户年龄小于等于uage的用户姓名(name)和专业(profession),
-- 并将用户的姓名和专业插入到所创建的一张新表(id,name,profession)中。
create procedure p(in uage int)
begin
declare uname varchar(100);
declare upro varchar(100);
-- A. 声明游标, 存储查询结果集
declare u_cursor cursor for select name,profession from tb_user where age <= uage;
-- B. 声明条件处理程序 : 当SQL语句执行抛出的状态码为02000时,将关闭游标u_cursor,并退出
declare exit handler for SQLSTATE '02000' close u_cursor;
-- C. 准备: 创建表结构
drop table if exists tb_user_pro;
create table if not exists tb_user_pro(
id int primary key auto_increment,
name varchar(100),
profession varchar(100)
);
-- D. 开启游标
open u_cursor;
while true do
-- E. 获取游标中的记录
fetch u_cursor into uname,upro;
-- F. 插入数据到新表中
insert into tb_user_pro values (null, uname, upro);
end while;
-- G. 关闭游标
close u_cursor;
end;
-- 调用执行过程
call p(30);
上記の場合、条件ハンドラーが宣言されていない場合、while ループ条件が true で終了条件がないため、実行プロセスが呼び出されたときに「02000」エラーが報告されます (null ポインター例外と同様)。呼び出し結果は引き続き成功する可能性があります。つまり、要件は正常に完了できます。
この時点で、ストアド プロシージャに関する知識は学習しました。次に、ストアド プロシージャに似たストアド関数を見てみましょう。
ストアド関数
ストアド関数は戻り値を持つストアド プロシージャであり、ストアド関数のパラメータは IN 型のみにすることができます。具体的な構文は次のとおりです。
CREATE FUNCTION 存储函数名称 ([ 参数列表 ])
RETURNS 返回类型 [characteristic ...]
BEGIN
-- SQL语句
RETURN ...;
END ;
特性の説明 (必須):
- DETERMINISTIC: 同じ入力パラメータは常に同じ結果を生成します
- NO SQL : SQL ステートメントが含まれません。
- READS SQL DATA: データを読み取るステートメントは含まれますが、データを書き込むステートメントは含まれません。
ストアド関数について詳しく学ぶために例を見てみましょう。
-- 计算从1累加到n的值,n为传入的参数值。
create function fun1(n int)
returns int deterministic
begin
declare total int default 0;
while n>0 do
set total := total + n;
set n := n - 1;
end while;
return total;
end;
select fun1(50);
3. トリガー
トリガーはテーブルに関連するデータベース オブジェクトであり、挿入/更新/削除の前 (BEFORE) または後 (AFTER) にトリガーで定義された一連の SQL ステートメントをトリガーして実行します。トリガーのこの機能は、アプリケーションがデータの整合性、ログ記録、データ検証、およびデータベース側でのその他の操作を保証するのに役立ちます。
他のデータベースと同様に、トリガー内の変更されたレコードの内容を参照するには、別名 OLD および NEW を使用します。現在、トリガーは行レベルのトリガーのみをサポートしており、ステートメントレベルのトリガーはサポートしていません。
① トリガーを作成する
CREATE TRIGGER trigger_name
BEFORE/AFTER INSERT/UPDATE/DELETE ON tbl_name FOR EACH ROW -- 行级触发器
BEGIN
trigger_stmt ;
END;
② トリガーを表示する
SHOW TRIGGERS ;
③ トリガーの削除
DROP TRIGGER [schema_name.]trigger_name ; -- 如果没有指定 schema_name,默认为当前数据库 。
例を通してトリガーの使用方法を見てみましょう。
要件: トリガーを通じて tb_user テーブルのデータ変更ログを記録し、追加、変更、削除を含めて変更ログをログ テーブル user_logs に挿入します。
a. まずログテーブル user_logs を作成します。
create table user_logs(
id int(11) not null auto_increment,
operation varchar(20) not null comment '操作类型, insert/update/delete',
operate_time datetime not null comment '操作时间',
operate_id int(11) not null comment '操作的ID',
operate_params varchar(500) comment '操作参数',
primary key(`id`)
)engine=innodb default charset=utf8;
b. データ挿入のトリガーを定義する
create trigger tb_user_insert_trigger
after insert on tb_user for each row
begin
insert into user_logs(id, operation, operate_time, operate_id, operate_params)
values(null, 'insert', now(), new.id,
concat('插入的数据内容为: id=', new.id, ',name=', new.name, ',phone=', new.phone, ',email=', new.email, ',profession=', new.profession));
end;
テスト挿入データ:
c. データを変更するトリガーを定義する
create trigger tb_user_update_trigger
after update on tb_user for each row
begin
insert into user_logs(id, operation, operate_time, operate_id, operate_params)
values(null, 'update', now(), new.id,
concat('更新之前的数据: id=', old.id, ',name=', old.name, ',phone=', old.phone, ',email=', old.email, ',profession=', old.profession,
' | 更新之后的数据: id=', new.id, ',name=', new.name, ',phone=', new.phone, ',email=', new.email, ',profession=', new.profession));
end;
テスト更新データ:
知らせ:
update tb_user set age = 18 where id <= 5 ステートメントを使用すると、現在のトリガーが行レベルをサポートしているため、5 個のデータが更新され、この時点で 5 個のログ データが user_logs テーブルに挿入されます。トリガー。
d. データを削除するトリガーを定義する
create trigger tb_user_delete_trigger
after delete on tb_user for each row
begin
insert into user_logs(id, operation, operate_time, operate_id, operate_params)
values(null, 'update', now(), old.id,
concat('删除之前的数据: id=', old.id, ',name=', old.name, ',phone=', old.phone, ',email=', old.email, ',profession=', old.profession));
end;
データの削除をテストします。