Для программирования хранимых процедур MySQL (подробно)

MySQL

Все статьи свода знаний,GitHubОн был записан, добро пожаловать в Star! Еще раз спасибо, я желаю вам войти на завод как можно скорее!

Адрес гитхаба: GitHub.com/zip и треки/…

Хранимая процедура MySQL


Во-первых, хранимая процедура

1.1 Что такое хранимая процедура

Хранимая процедура — это набор операторов SQL в большой системе баз данных для выполнения определенной функции. Она хранится в базе данных и действует постоянно после одной компиляции. Пользователь указывает имя хранимой процедуры и дает параметры (если хранимая процедура с параметрами) для его выполнения. Хранимые процедуры являются важным объектом в базе данных. В случае особенно большого объема данных использование хранимых процедур может повысить эффективность в два раза.

1.2 Программа хранимых процедур базы данных

Когда мы понимаем, что такое хранимая процедура, нам нужно понимать три типа программ типа хранилища базы данных, которые существуют в базе данных, а именно:

  • Хранимая процедура:Хранимая процедура является наиболее распространенным типом хранимой процедуры, хранимая процедура представляет собой программный модуль, который может принимать входные и выходные параметры и может выполняться по запросу.
  • Сохраненная функция:Хранимая функция похожа на хранимую процедуру, но ее выполнение возвращает значение. Что наиболее важно, хранимые функции можно использовать как стандартные операторы SQL, что позволяет программистам эффективно расширять возможности языка SQL.
  • курок:Триггеры — это хранимые процедуры, используемые для реагирования на события, которые активируют или инициируют поведение базы данных. Как правило, триггеры используются для вызова в ответ на языки манипулирования базой данных, а триггеры могут использоваться для проверки данных и автоматического обратного форматирования.

Примечание. Другие базы данных предоставляют дополнительные процедуры хранения данных, включая пакеты и классы. В настоящее время MySQL не предоставляет эту структуру.

1.3 Зачем использовать хранимые процедуры

Хотя мы не используем много сохраненных программ в текущей разработке, это не обязательно отрицается. На самом деле хранимые процедуры дадут нам много преимуществ в использовании и управлении базами данных:

  • Безопаснее использовать хранимые процедуры.
  • Хранимые процедуры предоставляют механизм абстракции для доступа к данным, который может значительно повысить удобство сопровождения вашего кода по мере развития базовых структур данных.
  • Хранимые процедуры могут уменьшить перегрузку сети, поскольку данные относятся к внутренним данным сервера базы данных, что намного быстрее, чем передача данных через Интернет.
  • Хранимые процедуры могут реализовывать подпрограммы совместного доступа для множества периферийных приложений, использующих различные архитектуры, вне зависимости от того, являются ли эти архитектуры внешними или внутренними по отношению к серверу базы данных.
  • Логика, ориентированная на данные, может быть размещена независимо в хранимых процедурах, что может предоставить программистам более высокий и уникальный опыт программирования баз данных.
  • В некоторых случаях использование хранимых процедур может улучшить переносимость приложений. (В других случаях переносимость будет плохой!)

Здесь я кратко объясню вышеупомянутые преимущества использования хранимых процедур:

Нам нужно знать, что в языке Java нам нужно ввести JDBC, чтобы использовать базу данных и код Java для объединения постоянного хранилища. Думая о JDBC, можем ли мы все еще думать о проблемах SQL-инъекций? Хотя использование PreparedStatement для решения проблемы SQL-инъекции действительно абсолютно безопасно? Нет, это не совсем безопасно.

В это время проанализируйте процесс операции соединения между базой данных и кодом Java. В структуре BS браузер обычно обращается к серверу, а затем сервер отправляет оператор SQL в базу данных, компилирует и запускает оператор SQL в базе данных и, наконец, обрабатывает результат через сервер и возвращает его в браузер. Во время этой операции браузер будет вызывать соответствующий оператор SQL для компиляции и выполнения каждый раз, когда он отправляет запрос на операцию с базой данных на сервер, что является пустой тратой производительности.падение производительностиЗатем объясните работу базы данныхнизкая эффективность.

Другая возможность заключается в том, что оператор SQL, который отправляется и передается в этом процессе, является оператором SQL, который работает с реальной таблицей базы данных.Если он будет перехвачен во время процесса передачи и передачи, некоторые преступники сделают вывод на основе перехваченного оператора SQL. структуру библиотечной таблицы в нашей базе данных, которая является большойРиски безопасности.

Что касается улучшения ремонтопригодности, здесь моделируется сценарий. Обычно базой данных управляет администратор базы данных в компании.Если администратор базы данных, который управлял базой данных в течение многих лет, уходит в отставку, база данных будет управляться следующим администратором базы данных. Здесь возникает проблема: такое количество данных и операторов SQL в базе данных явно не очень удобно для следующего менеджера. Даже DBA, управляющий много лет, что-то забудет, если долго не будет проверять базу. Поэтому нам необходимо ввести хранимые процедуры для унифицированного написания и компиляции операторов SQL,облегчает техническое обслуживание. (Вообще, я думаю, что этот пример не является ярким и разумным, но чтобы все поняли, пожалуйста, поймите!)

Я говорил об эволюции преимуществ многих хранимых программ.Один или несколько фрагментов скомпилированных операторов SQL необходимо поместить в хранимую программу на стороне базы данных, чтобы решить вышеуказанные проблемы и облегчить прямые вызовы разработчиками.

Во-вторых, использование хранимых процедур.

2.1 Идея развития хранимой процедуры

Хранимая процедура является важным объектом базы данных. Она может инкапсулировать набор операторов SQL, который можно использовать для выполнения более сложной бизнес-логики, а также может вводить параметры (параметры) и выходные параметры (возвращаемые параметры). Это очень похоже к способу упаковки в Java сходство.

Более того, он будет предварительно скомпилирован и сохранен при создании, и последующие вызовы разработчиками не нужно будет компилировать заново.

2.2 Преимущества и недостатки хранимых процедур

Преимущества и недостатки использования хранимых процедур фактически упоминаются в преимуществах 1.3. Здесь я кратко перечисляю преимущества и недостатки хранимых процедур.

  • преимущество:
    • В производственной среде бизнес-логика или ошибки могут быть изменены путем прямого изменения хранимой процедуры без перезапуска сервера.
    • Скорость выполнения высокая.После того как хранимая процедура скомпилирована, она будет намного быстрее, чем компиляция и выполнение один за другим.
    • Уменьшите сетевой трафик.
    • Его удобно использовать и поддерживать разработчикам или администраторам баз данных.
    • Улучшенная переносимость с тем же синтаксисом базы данных.
  • недостаток:
    • Процедурное программирование, стоимость обслуживания сложных бизнес-процессов высока.
    • Неудобно отлаживать.
    • Поскольку синтаксис разных баз данных несовместим, переносимость между разными базами данных плохая.

2.3 Официальная документация по хранимым процедурам MySQL

Друзья, хорошо владеющие английским или способные, могут обратиться к официальной документации. Если вы не ссылаетесь на официальную документацию, это не имеет значения.Я также подробно опишу различные точки знаний о хранимых процедурах MySQL ниже.

https://dev.mysql.com/doc/refman/5.6/en/preface.html

2.3 Синтаксис использования хранимых процедур

create PROCEDURE 过程名( in|out|inout 参数名 数据类型 , ...)
begin
	sql语句;
end;
call 过程名(参数值);

inключевое слово, определяющее входящий параметр.outключевое слово, определяющее параметр.inoutЯвляется ли для определения параметра, который можно ввести или выйти. Если в скобках ничего не определено, это означает, что хранимая процедура является функцией без параметров. Далее будет подробное тематическое исследование.

Уведомление:Терминатор по умолчанию для операторов SQL:;, поэтому при использовании вышеуказанной хранимой процедуры будет сообщено о синтаксической ошибке 1064. мы можем использоватьDELIMITERВременное объявление ключевого слова изменяет терминатор оператора SQL на//,следующее:

-- 临时定义结束符为"//"
DELIMITER //
create PROCEDURE 过程名( in|out 参数名 数据类型 , ...)
begin
	sql语句;
end//
-- 将结束符重新定义回结束符为";"
DELIMITER ;

Например:Используйте хранимую процедуру для запроса зарплаты сотрудника (без параметров)

Уведомление:Если в особых необходимых обстоятельствах, мы также можем передатьdelimiterключевые слова будут;Терминатор объявлен обратно в использование, в следующем случае я не объявлял терминатор обратно в исходный;Пожалуйста, обратите внимание на это ~

Почему я предоставляю дроп здесь?

Это связано с тем, что если нам нужно изменить содержимое хранимой процедуры при ее использовании, нам нужно сначала удалить существующую хранимую процедуру, а затем создать ее снова.

# 声明结束符为//
delimiter //

# 创建存储过程(函数)
create procedure se()
begin
    select salary from employee;
end //

# 调用函数
call se() //

# 删除已存在存储过程——se()函数
drop procedure if exists se //

Три, переменные хранимой процедуры и назначения

3.1 Локальные переменные

Объявить синтаксис локальной переменной: declare var_name type [default var_value];

Синтаксис назначения:

Уведомление:Определение локальных переменных, действительных в начальных/конечных блоках.

Используйте set для присвоения значений параметрам

# set赋值

# 声明结束符为//
delimiter //
    
# 创建存储过程
create procedure val_set()
begin
    # 声明一个默认值为unknown的val_name局部变量
    declare val_name varchar(32) default 'unknown';
	# 为局部变量赋值
    set val_name = 'Centi';
	# 查询局部变量
    select val_name;
end //

# 调用函数
call val_set() //

Используйте into для получения параметров

delimiter //
create procedure val_into()
begin
    # 定义两个变量存放name和age
    declare val_name varchar(32) default 'unknown';
    declare val_age int;
    # 查询表中id为1的name和age并放在定义的两个变量中
    select name,age into val_name,val_age from employee where id = 1;
    # 查询两个变量
    select val_name,val_age;
end //

call val_into() //

3.2 Пользовательские переменные

Пользовательская переменная, действующая для текущего сеанса (соединения). Подобно переменным-членам в Java.

  • грамматика: @val_name
  • Уведомление:Пользовательскую переменную не нужно объявлять заранее, она объявляется при использовании.
delimiter //
create procedure val_user()
begin
    # 为用户变量赋值
    set @val_name = 'Lacy';
end //

# 调用函数
call val_user() //

# 查询该用户变量
select @val_name //

3.3 Переменные сеанса

Переменные сеанса предоставляются системой и действительны только в текущем сеансе (соединении).

грамматика: @@session.val_name

# 查看所有会话变量
show session variables;
# 查看指定的会话变量
select @@session.val_name;
# 修改指定的会话变量
set @@session.val_name = 0;

Здесь я получаю все переменные сеанса, там около 500 записей переменных сеанса. После того, как мы подробно изучим MySQL, мы поймем роль каждого значения переменной сеанса и сможем изменить значение переменной сеанса в соответствии с требованиями и сценариями.

delimiter //
create procedure val_session()
begin
    # 查看会话变量
    show session variables;
end //

call val_session() //

image-20200610112512964

3.4 Глобальные переменные

Глобальные переменные предоставляются системой и действительны на всем сервере MySQL.

грамматика: @@global.val_name

# 查看全局变量中变量名有char的记录
show global variables like '%char%' //
# 查看全局变量character_set_client的值
select @@global.character_set_client //

3.5 Входные параметры и выходные параметры

Синтаксис входных и выходных параметров упоминался в начале статьи, но демонстрации нет, здесь я продемонстрирую использование входных и выходных параметров.

грамматика: in|out|inout 参数名 数据类型 , ...

inопределить параметры;outопределить входные параметры;inoutОпределите исходящие и входящие параметры.

из женьшеня

При использовании параметра in нам нужно передать параметры, где параметры можно изменить. Проще говоря, in отвечает только за передачу параметров в хранимые процедуры, аналогично формальным параметрам в Java.

delimiter //
create procedure val_in(in val_name varchar(32))
begin
    # 使用用户变量出参(为用户变量赋参数值)
    set @val_name1 = val_name;
end //

# 调用函数
call val_in('DK') //

# 查询该用户变量
select @val_name1 //

входной параметр выход

При использовании out вам необходимо передать параметр. Этот параметр эквивалентен возвращаемому значению, и содержимое этого параметра можно получить путем вызова и приема. Проще говоря, out отвечает только за возвращаемое значение.

delimiter //
# 创建一个入参和出参的存储过程
create procedure val_out(in val_id int,out val_name varchar(32))
begin
    # 传入参数val_id查询员工返回name值(查询出的name值用出参接收并返回)
    select name into val_name from employee where id = val_id;
end //

# 调用函数传入参数并声明传入一个用户变量
call val_out(1, @n) //

# 查询用户变量
select @n //

входной параметр

Ключевое слово inout объединяет вход и выход в одно ключевое слово. Параметры, изменяемые ключевыми словами, могут быть как выходными, так и входными параметрами.

delimiter //
create procedure val_inout(in val_name varchar(32), inout val_age int)
begin
    # 声明一个a变量
    declare a int;
    # 将传入的参数赋值给a变量
    set a = val_age;
    # 通过name查询age并返回val_age
    select age into val_age from employee where name = val_name;
    # 将传入的a与-和查询age结果字符串做拼接并查询出来(concat——拼接字符串)
    select concat(a, '-', val_age);
end //

# 声明一个用户变量并赋予参数为40
set @ages = '40' //
# 调用函数并传入参数值
call val_inout('Ziph', @ages) //
# 执行结果
# 40-18

В-четвертых, управление процессом в хранимой процедуре

4.1 если условное суждение (рекомендуется)

Расширение: timestampdiff(unit, exp1, exp2)Разность получается для exp2 - exp1, а единицей является единица. (обычно используется для дат)

Расширенный пример: select timestampdiff(year,’2020-6-6‘,now()) from emp e where id = 1;

Пример расширения пояснения:Запросите возраст сотрудника, чей идентификатор равен 1 в таблице сотрудников, а exp2 может быть датой рождения сотрудника, которая рассчитывается в годах.

грамматика:

IF 条件判断 THEN 结果
    [ELSEIF 条件判断 THEN 结果] ...
    [ELSE 结果]
END IF

Пример:Введите параметр id для запроса стандарта заработной платы (s=15000 - это стандартный стандарт высокой заработной платы)

delimiter //
create procedure s_sql(in val_id int)
begin
    # 声明一个局部变量result存放工资标准结果
    declare result varchar(32);
    # 声明一个局部变量存放查询得到的工资
    declare s double;
    # 根据入参id查询工资
    select salary into s from employee where id = val_id;
    # if判断的使用
    if s <= 6000 then
        set result = '低工资标准';
    elseif s <= 10000 then
        set result = '中工资标准';
    elseif s <= 15000 then
        set result = '中上工资标准';
    else
        set result = '高工资标准';
    end if;
    # 查询工资标准结果
    select result;
end //

# 调用函数,传入参数
call s_sql(1);

4.2 состояние дела

Что касается оператора case, его можно использовать не только в хранимых процедурах, но и в базовых операторах запросов MySQL. Это эквивалентно оператору switch в Java.

грамматика:

# 语法一
CASE case_value
    WHEN when_value THEN 结果
    [WHEN when_value THEN 结果] ...
    [ELSE 结果]
END CASE
    
# 语法二(推荐语法)
CASE
    WHEN 条件判断 THEN 结果
    [WHEN 条件判断 THEN 结果] ...
    [ELSE 结果]
END CASE

Пример:

# 语法一
delimiter //
create procedure s_case(in val_id int)
begin
    # 声明一个局部变量result存放工资标准结果
    declare result varchar(32);
    # 声明一个局部变量存放查询得到的工资
    declare s double;
    # 根据入参id查询工资
    select salary into s from employee where id = val_id;
    case s
        when 6000 then set result = '低工资标准';
        when 10000 then set result = '中工资标准';
        when 15000 then set result = '中上工资标准';
        else set result = '高工资标准';
    end case;
    select result;
end //

call s_case(1);

# 语法二(推荐)
delimiter //
create procedure s_case(in val_id int)
begin
    # 声明一个局部变量result存放工资标准结果
    declare result varchar(32);
    # 声明一个局部变量存放查询得到的工资
    declare s double;
    # 根据入参id查询工资
    select salary into s from employee where id = val_id;
    case
        when s <= 6000 then set result = '低工资标准';
        when s <= 10000 then set result = '中工资标准';
        when s <= 15000 then set result = '中上工资标准';
        else set result = '高工资标准';
    end case;
    select result;
end //

call s_case(1);

4.3 петля петля

Цикл бесконечный, нам нужно выйти из цикла вручную, мы можем использоватьleaveчтобы выйти из цикла

Отпуск можно рассматривать как перерыв в Java, ему соответствуютiterate(Продолжить цикл) также можно рассматривать как продолжение Java.

грамматика:

[别名:] LOOP
    循环语句
END LOOP [别名]

Примечание. Псевдонимы и псевдонимы управляют одной и той же меткой.

Пример 1:Напечатайте 1~10 в цикле (выход из цикла контролируется отпуском)

Примечание. Цикл цикла является бесконечным циклом. Мы проверили число 1–10, равное i. В бесконечном цикле он настроен на остановку цикла, когда он больше или равен 10, то есть содержимое в цикл выполняется 10 раз, и результат запрашивается 10 раз, было сгенерировано 10 результатов (1~10).

delimiter //
create procedure s_loop()
begin
    # 声明计数器
    declare i int default 1;
    # 开始循环
    num:
    loop
        # 查询计数器记录的值
        select i;
        # 判断大于等于停止计数
        if i >= 10 then
            leave num;
        end if;
        # 计数器自增1
        set i = i + 1;
    # 结束循环
    end loop num;
end //

call s_loop();

распечатать результат:

image-20200610191639524

Пример 2:Цикл печати 1 ~ 10 (итерация и выход из цикла управления)

Примечание. Здесь мы используем результат счетчика конкатенации строк, и условие должно быть i

delimiter //
create procedure s_loop1()
begin
    # 声明变量i计数器
    declare i int default 1;
    # 声明字符串容器
    declare str varchar(256) default '1';
    # 开始循环
    num:
    loop
        # 计数器自增1
        set i = i + 1;
        # 字符串容器拼接计数器结果
        set str = concat(str, '-', i);
        # 计数器i如果小于10就继续执行
        if i < 10 then
            iterate num;
        end if;
        # 计数器i如果大于10就停止循环
        leave num;
    # 停止循环
    end loop num;
    # 查询字符串容器的拼接结果
    select str;
end //

call s_loop1();

image-20200610193153512

4.4 повторный цикл

Цикл повторения аналогичен циклу do while в Java, который не завершит цикл, пока условие не будет выполнено.

грамматика:

[别名:] REPEAT
    循环语句
UNTIL 条件
END REPEAT [别名]

Пример:цикл печати 1 ~ 10

delimiter //
create procedure s_repeat()
begin
    declare i int default 1;
    declare str varchar(256) default '1';
    # 开始repeat循环
    num:
    repeat
        set i = i + 1;
        set str = concat(str, '-', i);
    # until 结束条件
    # end repeat 结束num 结束repeat循环
    until i >= 10 end repeat num;
    # 查询字符串拼接结果
    select str;
end //

call s_repeat();

4.5 пока цикл

Цикл while очень похож на цикл while в Java.

грамматика:

[别名] WHILE 条件 DO
    循环语句
END WHILE [别名]

Пример:цикл печати 1 ~ 10

delimiter //
create procedure s_while()
begin
    declare i int default 1;
    declare str varchar(256) default '1';
    # 开始while循环
    num:
	# 指定while循环结束条件
    while i < 10 do
        set i = i + 1;
        set str = concat(str, '+', i);
    # while循环结束
    end while num;
    # 查询while循环拼接字符串
    select str;
end //

call s_while();

4.6 Операторы управления потоком (продолжение, конец)

Что касается продолжения и завершения управления потоком, мы использовали его раньше. Вот еще один список.

оставить: аналогично перерыву в Java;

leave 标签;

iterate: похоже на continue; в Java

iterate 标签;

5. Курсор и обработчик

5.1 Курсоры

Курсор может получать результирующий набор и обрабатывать данные построчно. Построчная работа курсора приводит к тому, что курсор используется редко!

грамматика:

DECLARE 游标名 CURSOR FOR 查询语句
-- 打开语法
OPEN 游标名
-- 取值语法
FETCH 游标名 INTO var_name [, var_name] ...
-- 关闭语法
CLOSE 游标名

Зная синтаксис курсоров, давайте начнем использовать курсоры. следующее:

Пример:Используйте курсор для запроса идентификатора, имени и зарплаты.

delimiter //
create procedure f()
begin
    declare val_id int;
    declare val_name varchar(32);
    declare val_salary double;

    # 声明游标
    declare emp_flag cursor for
    select id, name, salary from employee;

    # 打开
    open emp_flag;

    # 取值
    fetch emp_flag into val_id, val_name, val_salary;

    # 关闭
    close emp_flag;

    select val_id, val_name, val_salary;
end //

call f();

Результаты:

image-20200610203622749

Из-за построчной операции курсора мы можем использовать курсор только для запроса строки записей. Как улучшить код для запроса всех записей? Умные друзья придумали использовать петли. Да, давайте попробуем использовать цикл.

delimiter //
create procedure f()
begin
    declare val_id int;
    declare val_name varchar(32);
    declare val_salary double;

    # 声明游标
    declare emp_flag cursor for
    select id, name, salary from employee;

    # 打开
    open emp_flag;

    # 使用循环取值
    c:loop
    	# 取值
        fetch emp_flag into val_id, val_name, val_salary;
    end loop;

    # 关闭
    close emp_flag;

    select val_id, val_name, val_salary;
end //

call f();

image-20200610204034224

После того, как мы использовали цикл, мы обнаружили, что есть проблема, потому что цикл является бесконечным циклом, мы не добавляем условия для завершения цикла, курсор всегда будет запрашивать записи, а когда записи не найдены, исключение будет брошен1329:未获取到选择处理的行数.

Что, если бы мы нашли способ указать условия для завершения цикла?

В это время вы можете объявить тег логического типа. Если true, запросите набор результатов, если false, завершите цикл.

delimiter //
create procedure f()
begin
    declare val_id int;
    declare val_name varchar(32);
    declare val_salary double;

    # 声明flag标记
    declare flag boolean default true;

    # 声明游标
    declare emp_flag cursor for
    select id, name, salary from employee;

    # 打开
    open emp_flag;

    # 使用循环取值
    c:loop
        fetch emp_flag into val_id, val_name, val_salary;
        # 如果标记为true则查询结果集
        if flag then
            select val_id, val_name, val_salary;
        # 如果标记为false则证明结果集查询完毕,停止死循环
        else
            leave c;
        end if;
    end loop;

    # 关闭
    close emp_flag;

    select val_id, val_name, val_salary;
end //

call f();

Вы обнаружите, что приведенный выше код не закончен, он оставляет очень серьезную проблему. Цикл можно завершить, когда flag = false. Но когда флаг будет ложным?

Итак, MySQL предоставляет намhandlerручка. Это может помочь нам решить это сомнение.

синтаксис дескриптора обработчика: declare continue handler for 异常 set flag = false;

Дескриптор обработчика можно использовать для перехвата исключений, то есть в этом сценарии, когда перехваченный1329:未获取到选择处理的行数, измените значение флага flag на false. Это использует дескриптор обработчика для решения проблемы завершения цикла. Давайте попробуем!

Пример редукса:Решены многострочные запросы и проблемы с завершением цикла.

delimiter //
create procedure f()
begin
    declare val_id int;
    declare val_name varchar(32);
    declare val_salary double;

    # 声明flag标记
    declare flag boolean default true;

    # 声明游标
    declare emp_flag cursor for
    select id, name, salary from employee;

    # 使用handler句柄来解决结束循环问题
    declare continue handler for 1329 set flag = false;

    # 打开
    open emp_flag;

    # 使用循环取值
    c:loop
        fetch emp_flag into val_id, val_name, val_salary;
        # 如果标记为true则查询结果集
        if flag then
            select val_id, val_name, val_salary;
        # 如果标记为false则证明结果集查询完毕,停止死循环
        else
            leave c;
        end if;
    end loop;

    # 关闭
    close emp_flag;

    select val_id, val_name, val_salary;
end //

call f();

Результаты:

image-20200610210925964

В результатах выполнения видно, что результаты запроса распределяются в виде нескольких запросов и отображаются в каждом окне результатов запроса.

Уведомление:В грамматике объявление переменной, объявление курсора и объявление обработчика должны быть написаны по порядку, иначе при создании хранимой процедуры возникает ошибка.

5.2 рукоятка обработчика

грамматика:

DECLARE handler操作 HANDLER
    FOR 情况列表...(比如:异常错误情况)
    操作语句

Примечание. Исключения могут записывать коды ошибок исключений, псевдонимы исключений или коды SQLSTATE.

работа обработчика:

  • ПРОДОЛЖАТЬ:Продолжать
  • ВЫХОД:покидать
  • ОТМЕНИТЬ:отозвать

Список исключений:

  • mysql_error_code
  • SQLSTATE [VALUE] sqlstate_value
  • condition_name
  • SQLWARNING
  • NOT FOUND
  • SQLEXCEPTION

Уведомление:Различные коды исключений, коды ошибок, псевдонимы и коды SQLSTATEM в MySQL см. в официальной документации:

Dev.MySQL.com/doc/Furious/…

Пример написания:

	DECLARE exit HANDLER FOR SQLSTATE '3D000' set flag = false;
	DECLARE continue HANDLER FOR 1050 set flag = false;
	DECLARE continue HANDLER FOR not found set flag = false;

Шесть, цикл для создания таблицы

необходимость:Создайте таблицу, соответствующую каждому дню следующего месяца, и формат созданной таблицы:comp_2020_06_01、comp_2020_06_02、...

описывать:Нам нужно использовать определенную таблицу для записи большого количества данных, таких как запись поведения поиска и покупки определенного пользователя (обратите внимание, что предполагается, что база данных хранится здесь). Нам нужно разделить таблицы. Наше требование состоит в том, что нам нужна одна таблица в день для хранения статистических данных за день, и нам нужно производить эти таблицы заранее - создавать таблицу на каждый день следующего месяца в конце каждого месяца!

Предварительно скомпилировано: PREPARE 数据库对象名 FROM 参数名

воплощать в жизнь: EXECUTE 数据库对象名 [USING @var_name [, @var_name] ...]

Создайте или удалите таблицы из объектов базы данных: {DEALLOCATE | DROP} PREPARE 数据库对象名

Заявление об обработке времени:

-- EXTRACT(unit FROM date)  			 截取时间的指定位置值
-- DATE_ADD(date,INTERVAL expr unit)     日期运算
-- LAST_DAY(date) 					     获取日期的最后一天
-- YEAR(date)					         返回日期中的年
-- MONTH(date)   						 返回日期的月
-- DAYOFMONTH(date)   					 返回日

Код:

-- 思路:循环构建表名 comp_2020_06_01 到 comp_2020_06_30;并执行create语句。
delimiter //
create procedure sp_create_table()
begin
	# 声明需要拼接表名的下一个月的年、月、日
	declare next_year int;
	declare next_month int;
	declare next_month_day int;
	
	# 声明下一个月的月和日的字符串
	declare next_month_str char(2);
	declare next_month_day_str char(2);
	
	# 声明需要处理每天的表名
	declare table_name_str char(10);
	
	# 声明需要拼接的1
	declare t_index int default 1;
	# declare create_table_sql varchar(200);
	
	# 获取下个月的年份
	set next_year = year(date_add(now(),INTERVAL 1 month));
	# 获取下个月是几月 
	set next_month = month(date_add(now(),INTERVAL 1 month));
	# 下个月最后一天是几号
	set next_month_day = dayofmonth(LAST_DAY(date_add(now(),INTERVAL 1 month)));
	
	# 如果下一个月月份小于10,就在月份的前面拼接一个0
	if next_month < 10
		then set next_month_str = concat('0',next_month);
	else
		# 如果月份大于10,不做任何操作
		set next_month_str = concat('',next_month);
	end if;
	
	# 循环操作(下个月的日大于等于1循环开始循环)
	while t_index <= next_month_day do
		
		# 如果t_index小于10就在前面拼接0
		if (t_index < 10)
			then set next_month_day_str = concat('0',t_index);
		else
			# 如果t_index大于10不做任何操作
			set next_month_day_str = concat('',t_index);
		end if;
		
		# 拼接标命字符串
		set table_name_str = concat(next_year,'_',next_month_str,'_',next_month_day_str);
		# 拼接create sql语句
		set @create_table_sql = concat(
					'create table comp_',
					table_name_str,
					'(`grade` INT(11) NULL,`losal` INT(11) NULL,`hisal` INT(11) NULL) COLLATE=\'utf8_general_ci\' ENGINE=InnoDB');
		# 预编译
		# 注意:FROM后面不能使用局部变量!
		prepare create_table_stmt FROM @create_table_sql;
		# 执行
		execute create_table_stmt;
		# 创建表
		DEALLOCATE prepare create_table_stmt;
		
		# t_index自增1
		set t_index = t_index + 1;
		
	end while;	
end//

# 调用函数
call sp_create_table()

7. Другое

7.1 characteristic

В хранимых процедурах MySQL, если нет явного определения характеристики, будет неявно определен набор значений по умолчанию для характеристик для создания хранимой процедуры.

  • LANGUAGE SQL

    • Язык хранимой процедуры, по умолчанию — sql, что указывает на то, что хранимая процедура написана на языке sql, в настоящее время поддерживается только sql, а в будущем могут поддерживаться и другие языки.
  • NOT DETERMINISTIC

    • Является ли детерминированный ввод детерминированным выводом, по умолчанию НЕ ДЕТЕРМИНИСТИЧЕСКИЙ, только для того же ввода, вывод тот же, текущее значение не использовалось
  • CONTAINS SQL

    • Предоставляет внутреннюю информацию о данных, используемых подпрограммой.Эти значения характеристик в настоящее время предоставляются серверу и не ограничивают фактическое использование данных процессом на основе этих значений характеристик. Доступны следующие варианты:
      • CONTAINS SQL указывает, что подпрограмма не содержит инструкций для чтения или записи данных.
      • NO SQL означает, что подпрограмма не содержит sql
      • READS SQL DATA указывает, что подпрограмма содержит инструкции для чтения данных, но не для записи данных.
      • MODIFIES SQL DATA указывает, что подпрограмма содержит операторы, которые записывают данные.
  • SQL SECURITY DEFINER

    • Хранимые процедуры MySQL указываются путем указания предложения SQL SECURITY, чтобы указать фактического пользователя, выполняющего хранимую процедуру. Таким образом, вторичное значение используется для указания того, выполняется ли хранимая процедура с разрешения создателя или с разрешения исполнителя.Значение по умолчанию — DEFINER.
      • Идентификатор создателя DEFINER вызывается для текущего пользователя: если разрешение на выполнение хранимой процедуры и у создателя есть разрешение на доступ к таблице, текущий пользователь может успешно выполнить вызов процедуры.
      • Выполняется удостоверение вызывающего INVOKER Для текущего пользователя: если разрешение на выполнение хранимой процедуры состоит в доступе к таблице с текущим удостоверением, если текущее удостоверение не имеет разрешения на доступ к таблице, даже если оно имеет разрешение на выполнение процедуры, она по-прежнему не может быть успешно выполнена вызов процедуры.
  • COMMENT ''

    • Комментарий к хранимой процедуре записывается в COMMENT, где это может быть только одна строка текста, многострочный текст будет удален на возврат каретки, перевод строки и т. д.

7.2 Обработка бесконечного цикла

Если есть бесконечный цикл, вы можете просмотреть и убить (завершить) с помощью следующей команды

show processlist;
kill id;

7.3 Запись case в операторе select

select 
	case
		when 条件判断 then 结果
		when 条件判断 then 结果
		else 结果
	end 别名,
	*
from 表名;

7.4 Копирование таблиц и данных

CREATE TABLE dept SELECT * FROM procedure_demo.dept;
CREATE TABLE emp SELECT * FROM procedure_demo.emp;
CREATE TABLE salgrade SELECT * FROM procedure_demo.salgrade;

7.5 Временные таблицы

create temporary table 表名(
&emsp;&emsp;字段名 类型 [约束],
&emsp;&emsp;name varchar(20) 
)Engine=InnoDB default charset utf8;

-- 需求:按照部门名称查询员工,通过select查看员工的编号、姓名、薪资。(注意,此处仅仅演示游标用法)
delimiter ?
create procedure sp_create_table02(in dept_name varchar(32))
begin
	declare emp_no int;
	declare emp_name varchar(32);
	declare emp_sal decimal(7,2);
	declare exit_flag int default 0;
	
	declare emp_cursor cursor for
		select e.empno,e.ename,e.sal
		from emp e inner join dept d on e.deptno = d.deptno where d.dname = dept_name;
	
	declare continue handler for not found set exit_flag = 1;
	
	-- 创建临时表收集数据
	CREATE temporary TABLE `temp_table_emp` (
		`empno` INT(11) NOT NULL COMMENT '员工编号',
		`ename` VARCHAR(32) NULL COMMENT '员工姓名' COLLATE 'utf8_general_ci',
		`sal` DECIMAL(7,2) NOT NULL DEFAULT '0.00' COMMENT '薪资',
		PRIMARY KEY (`empno`) USING BTREE
	)
	COLLATE='utf8_general_ci'
	ENGINE=InnoDB;	
	
	open emp_cursor;
	
	c_loop:loop
		fetch emp_cursor into emp_no,emp_name,emp_sal;
		
		
		if exit_flag != 1 then
			insert into temp_table_emp values(emp_no,emp_name,emp_sal); 
		else
			leave c_loop;
		end if;
		
	end loop c_loop;
	
	select * from temp_table_emp;
	
	select @sex_res; -- 仅仅是看一下会不会执行到
	close emp_cursor;
	
end?

call sp_create_table02('RESEARCH');

Статьи с разными адресами GitHub: GitHub.com/zip и треки/…Добро пожаловать Звезда!