Mysql
 sql >> база данни >  >> RDS >> Mysql

Работа с тригери в база данни на MySQL - урок

Задействане е предварително дефинирана SQL команда, която се изпълнява автоматично, когато се появят конкретни действия в базата данни. Може да се задейства преди или след INSERT , UPDATE или DELETE събитие.

Тригерите се използват главно за поддържане на софтуерната логика в MySQL сървъра и имат няколко предимства:

  • Тригерите помагат да се поддържат централизирани глобални операции на едно място.

  • Те намаляват кода от страна на клиента и помагат да се сведат до минимум пътуванията до сървъра на базата данни.

  • Те помагат да се направят приложенията по-мащабируеми в различни платформи.

Някои често срещани случаи на използване на задействания включват регистриране на одит, предварително изчисляване на стойности на базата данни (напр. кумулативни суми) и налагане на сложни правила за целостта на данните и валидиране.

В това ръководство ще научите:

  • Как е структуриран синтаксисът за тригер.

  • Как да създадете тригери, които се изпълняват преди да възникнат други събития в базата данни.

  • Как да създадете тригери, които се изпълняват след възникване на други събития в базата данни.

  • Как да изтриете тригери.

Преди да започнете

  1. Ако все още не сте го направили, създайте акаунт в Linode и Compute Instance. Вижте нашите ръководства Първи стъпки с Linode и Създаване на изчислителен екземпляр.

  2. Следвайте нашето ръководство за настройка и осигуряване на изчислителен екземпляр, за да актуализирате вашата система. Може също да пожелаете да зададете часовата зона, да конфигурирате името на хоста си, да създадете ограничен потребителски акаунт и да укрепите SSH достъпа.

  3. MySQL сървър и клиент, инсталирани на сървъра на Linode. Ръководствата за инсталиране на MySQL са налични за различни дистрибуции в нашия раздел MySQL.

Подгответе базата данни

За да разберем по-добре как работят тригерите, ще създадем примерна база данни и ще добавим примерни данни в нея. По-късно ще създадем различни тригери в базата данни като доказателство за упражнение на концепцията.

  1. Първо, влезте във вашия MySQL сървър:

    mysql -u root -p
    

    След това въведете root паролата на вашия MySQL сървър и натиснете Enter за да продължите.

  2. След това ще видите подкана за MySQL, подобна на показаната по-долу:

    mysql >
  3. Създайте test_database като изпълните командата по-долу:

    CREATE DATABASE test_database;
    

    Изход:

    Query OK, 1 row affected (0.02 sec)
  4. Превключете към базата данни:

    USE test_database;
    

    Изход:

    Database changed
  5. След като базата данни бъде избрана, ще създадем някои таблици, които ще използваме за демонстриране на тригери. Ще започнем със създаване на stores маса. Тази таблица ще съдържа информация за два примерни магазина/офиси, от които работи нашият хипотетичен бизнес:

    CREATE TABLE stores
    (
    store_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    store_name VARCHAR(50)
    ) ENGINE=InnoDB;
    

    Изход:

    Query OK, 0 rows affected (0.07 sec)
  6. След това добавете два записа към stores таблица, като изпълните командите по-долу:

    INSERT INTO stores (store_name) VALUES ('Philadelphia');
    INSERT INTO stores (store_name) VALUES ('Galloway');
    

    След всяка команда ще получите следния изход:

    Query OK, 1 row affected (0.08 sec)
    ...
  7. Потвърдете записите, като изпълните командата по-долу:

    SELECT * FROM stores;
    

    Изход:

    +----------+--------------+
    | store_id | store_name   |
    +----------+--------------+
    |        1 | Philadelphia |
    |        2 | Galloway     |
    +----------+--------------+
    2 rows in set (0.01 sec)
  8. След това създайте products маса. Таблицата ще съдържа различни продукти, които се предлагат в магазина:

    CREATE TABLE products
    (
    product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    product_name VARCHAR(40),
    cost_price DOUBLE,
    retail_price DOUBLE,
    availability VARCHAR(5)
    ) ENGINE=InnoDB;
    

    Изход:

    Query OK, 0 rows affected (0.13 sec)
    • Всеки продукт ще бъде уникално идентифициран чрез product_id .

    • product_name полето ще посочи имената на елементите.

    • cost_price и retail_price полета ще определят съответно покупната и продажната цена.

    • availability колона ще определи наличността на продукта в различните магазини. Ако продуктът се предлага само в нашия местен магазин (Филаделфия), ние ще го обозначим с LOCAL стойност. В противен случай ще използваме стойността на ALL за означаване на продукт, който се предлага и в двата магазина (Филаделфия и Галоуей).

  9. Добавете примерни данни към products таблица:

    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('WIRELESS MOUSE', '18.23', '30.25','ALL');
    
    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('8 MP CAMERA', '60.40', '85.40','ALL');
    
    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('SMART WATCH', '189.60', '225.30','LOCAL');
    

    Ще получите изхода, показан по-долу след всяка команда за вмъкване:

    Query OK, 1 row affected (0.02 sec)
    ...
  10. Потвърдете дали продуктите са били вмъкнати, като изпълните командата по-долу:

    SELECT * FROM products;
    

    Изход:

    +------------+----------------+------------+--------------+--------------+
    | product_id | product_name   | cost_price | retail_price | availability |
    +------------+----------------+------------+--------------+--------------+
    |          1 | WIRELESS MOUSE |      18.23 |        30.25 | ALL          |
    |          2 | 8 MP CAMERA    |       60.4 |         85.4 | ALL          |
    |          3 | SMART WATCH    |      189.6 |        225.3 | LOCAL        |
    +------------+----------------+------------+--------------+--------------+
    3 rows in set (0.00 sec)
  11. След това наличността на продуктите ще бъде съпоставена с друга таблица с име products_to_stores . Тази таблица просто ще препраща към product_id от products таблица и store_id от stores таблица, където артикулът е наличен.

    Създайте products_to_stores таблица, като изпълните кода по-долу:

    CREATE TABLE products_to_stores
    (
    ref_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    product_id BIGINT,
    store_id BIGINT
    ) ENGINE=InnoDB;
    

    Изход:

    Query OK, 0 rows affected (0.14 sec)
  12. След това ще създадем archived_products маса. Таблицата ще съдържа информация за изтрити продукти за бъдещи справки:

    CREATE TABLE archived_products
    (
    product_id BIGINT PRIMARY KEY ,
    product_name VARCHAR(40),
    cost_price DOUBLE,
    retail_price DOUBLE,
    availability VARCHAR(5)
    ) ENGINE=InnoDB;
    

    Изход:

    Query OK, 0 rows affected (0.14 sec)
  13. И накрая, ще създадем products_price_history таблица за проследяване на различните цени на всеки продукт във времето:

    CREATE TABLE products_price_history
    (
    product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    price_date DATETIME,
    retail_price DOUBLE
    ) ENGINE=InnoDB;
    

    Изход:

    Query OK, 0 rows affected (0.14 sec)

След като структурата на нашата база данни е на мястото си, вече можем да продължим напред и да научим основния синтаксис на задействане на MySQL база данни, за да създадем първата си извадка.

Синтаксис на задействане

Както беше посочено по-рано, тригерите се задействат автоматично преди или след изпълнение на SQL команда в базата данни. Основният синтаксис за създаване на тригери е както следва:

CREATE TRIGGER TRIGGER_NAME

TRIGGER_TIME TRIGGER_EVENT

ON TABLE_NAME FOR EACH ROW

[TRIGGER BODY];
  • TRIGGER_NAME :Всеки тригер трябва да има уникално име и трябва да го дефинирате тук.

  • TRIGGER_TIME :Или BEFORE или AFTER .

  • TRIGGER_EVENT :Трябва да посочите събитието в базата данни, което ще извика тригера:INSERT , UPDATE или DELETE .

  • TRIGGER BODY :Това посочва действителната SQL команда (или команди), която искате да се изпълняват от вашия тригер.

Ако едно тригерно тяло има повече от един SQL израз, трябва да го затворите в BEGIN...END блок. Освен това ще трябва временно да промените DELIMITER което сигнализира края на тялото на тригера към нова стойност. Това гарантира, че изразите в тялото няма да бъдат интерпретирани преждевременно от вашия MySQL клиент. Пример за това изглежда по следния начин:

DELIMITER &&

CREATE TRIGGER TRIGGER_NAME

TRIGGER_TIME TRIGGER_EVENT

ON TABLE_NAME FOR EACH ROW

BEGIN

[TRIGGER BODY]

END &&

DELIMITER ;
Забележка Последният ред от този пример променя DELIMITER обратно към ; по подразбиране стойност.

Създаване преди задействане на събитие

В този раздел ще разгледаме различните типове тригери, които се задействат преди операция с база данни. Те включват BEFORE INSERT , BEFORE UPDATE и BEFORE DELETE тригери.

Създаване на тригер преди вмъкване

Ще създадем нашия първи BEFORE INSERT задействане. Задействането ще гарантира, че цената на дребно на даден продукт е по-висока от себестойността, когато артикулите се вмъкват в products маса. В противен случай потребителят на базата данни ще получи грешка.

  1. Докато все още сте в mysql > подкана, въведете командата по-долу:

    DELIMITER $$
    
    CREATE TRIGGER price_validator
    
    BEFORE INSERT
    
    ON products FOR EACH ROW
    
    IF NEW.cost_price>=NEW.retail_price
    
    THEN
    
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Retail price must be greater than cost price.';
    
    END IF $$
    
    DELIMITER ;
    
    • Горният код дефинира името на тригера (price_validator ), време (BEFORE ), събитие (INSERT ), и таблицата (products ) да бъдат засегнати.

    • Нашият тригер използва NEW ключова дума, за да проверите cost_price и retail_price преди да се вмъкне запис в products таблица, като използвате IF...THEN...END IF изявление.

    • Ако cost_price е по-голямо или равно на retail price , нашите тригери казват на MySQL да изведе персонализирано изключение, инструктиращо потребителя да коригира грешката.

  2. За да тествате задействането по-горе, опитайте да вмъкнете продукт, който нарушава правилото за валидиране:

    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');
    

    Изход:

    ERROR 1644 (45000): Retail price must be greater than cost price.

    Горните команди за вмъкване трябва да се провалят, защото retail_price (144,00) не е по-голямо от cost_price (145,00).

Създаване на тригер преди актуализиране

След това ще създадем BEFORE UPDATE задействане. Този тригер ще попречи на потребителите на база данни да редактират име на продукт, след като продуктът е вмъкнат в базата данни. Ако имате няколко потребители, работещи в базата данни, BEFORE UPDATE тригерът може да се използва за правене на стойности само за четене и това може да попречи на злонамерени или невнимателни потребители да променят ненужно записи.

  1. Създайте нов product_name_validator задействайте с командата по-долу:

    DELIMITER $$
    
    CREATE TRIGGER product_name_validator
    
    BEFORE UPDATE
    
    ON products FOR EACH ROW
    
    IF NEW.product_name<>OLD.product_name
    
    THEN
    
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Product name is read-only and it can not be changed.';
    
    END IF $$
    
    DELIMITER ;
    

    Този тригер сравнява стойностите на новия product_name (NEW.product_name ) и старото име, което вече е в базата данни (OLD.product_name ). Ако има несъответствие, се създава изключение.

  2. За да извикате product_name_validator тригер, можем да се опитаме да актуализираме името на продукта с идентификатор 1 :

    UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';
    

    Изход:

    ERROR 1644 (45000): Product name is read-only and it can not be changed.

Дефиниране на тригер преди изтриване

В този раздел ще видите как можете да дефинирате BEFORE DELETE тригер, за да попречи на потребителите да изтриват конкретни записи от таблица.

  1. За да създадете prevent_delete тригер, изпълнете командата по-долу:

    DELIMITER $$
    
    CREATE TRIGGER prevent_delete
    
    BEFORE DELETE
    
    ON products FOR EACH ROW
    
    IF OLD.availability='ALL'
    
    THEN
    
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'The product can not be deleted because it is available in ALL stores.';
    
    END IF $$
    
    DELIMITER ;
    

    Това задействане ще предотврати продукти, маркирани със стойност ALL в колоната наличност от изтриване.

  2. След това опитайте да изтриете първия продукт от таблицата с продукти и вижте дали тригерът ще бъде извикан:

    DELETE FROM products WHERE product_id='1';
    

    Изход:

    ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores.

Разгледахме различните тригери, които се извикват преди операция с база данни. След това ще разгледаме другите типове тригери, които се задействат след събития в базата данни.

Създаване на тригери след събитие

В производствена среда може да искате някои тригери да се изпълняват автоматично след възникване на събитие в базата данни (например вмъкване на записи в различни таблици). Примерите по-долу показват как тези видове тригери могат да се използват в нашата примерна база данни.

Създаване на тригер след вмъкване

Този пример създава тригер с име product_availability който вмъква записи за съпоставяне в products_to_stores маса. Този тригер се използва за налагане на бизнес логиката; по-специално, това помага да се определи наличността на продукти за различните магазини.

  1. Изпълнете кода по-долу, за да създадете product_availability задействане. Тъй като имаме няколко реда код в тялото на тригера, ще използваме BEGIN...END блок:

    DELIMITER $$
    
    CREATE TRIGGER product_availability
    
    AFTER INSERT
    
    ON products FOR EACH ROW
    
    BEGIN
    
    IF NEW.availability='LOCAL' then
    
    INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '1');
    
    ELSE
    
    INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '1');
    
    INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '2');
    
    END IF;
    
    END $$
    
    DELIMITER ;
    
    • Когато даден артикул се вмъква в products таблица, тригерът ще провери availability поле.

    • Ако е маркиран с LOCAL стойност, продуктът ще бъде наличен само в един магазин.

    • Всяка друга стойност ще инструктира тригера да направи продукта достъпен за двата магазина, които създадохме по-рано.

  2. За да видите product_availability тригера в действие, вмъкнете двата записа в таблицата с продукти:

    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('BLUETOOTH KEYBOARD', '17.60', '23.30','LOCAL');
    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('DVB-T2 RECEIVE', '49.80', '53.40','ALL');
    
  3. След това потърсете products_to_stores таблица:

    SELECT * FROM products_to_stores;
    

    Трябва да видите изход, подобен на показания по-долу:

    +--------+------------+----------+
    | ref_id | product_id | store_id |
    +--------+------------+----------+
    |      1 |          4 |        1 |
    |      2 |          5 |        1 |
    |      3 |          5 |        2 |
    +--------+------------+----------+
    3 rows in set (0.00 sec)

Дефиниране на тригер след актуализиране

Задействане може също да се задейства след UPDATE събитие. Ще видим как можем да използваме този тип задействане, за да следим промените в цените в нашия магазин с течение на времето.

  1. Създайте product_history_updater задействате, като изпълните командата по-долу:

    CREATE TRIGGER product_history_updater
    
    AFTER UPDATE
    
    ON products FOR EACH ROW
    
    INSERT INTO products_price_history (product_id, price_date, retail_price) VALUES (OLD.product_id, NOW(), NEW.retail_price);
    

    Това задействане записва промени в retail_price на продукт в products_price_history таблица.

    Забележка За разлика от предишните примери, този тригер има само един израз в тялото на тригера, така че не е необходимо да променяме DELIMITER .
  2. След това опитайте да актуализирате цената на първия продукт, като изпълните командата по-долу:

    UPDATE products SET retail_price='36.75' WHERE product_id='1';
    
  3. След това потърсете products_price_history таблица, за да видите дали промяната на цената е регистрирана:

    SELECT * FROM products_price_history;
    

    Ако тригерът работи както се очаква, трябва да получите следния изход:

    +------------+---------------------+--------------+
    | product_id | price_date          | retail_price |
    +------------+---------------------+--------------+
    |          1 | 2020-01-28 11:46:21 |        36.75 |
    +------------+---------------------+--------------+
    1 row in set (0.00 sec)

Създаване на тригер след изтриване

В някои случаи може да искате да регистрирате операции за изтриване след извършено конкретно действие в базата данни. Можете да постигнете това, като използвате AFTER DELETE задействане.

  1. Създайте нов product_archiver задействайте с командата по-долу:

    CREATE TRIGGER product_archiver
    
    AFTER DELETE
    
    ON products FOR EACH ROW
    
    INSERT INTO archived_products (product_id, product_name, cost_price, retail_price, availability) VALUES (OLD.product_id, OLD.product_name, OLD.cost_price, OLD.retail_price, OLD.availability);
    

    Това задейства архивиране на изтритите продукти в отделна таблица с име archived_products . Когато даден артикул се изтрие от основните products таблица, нашият тригер автоматично ще го регистрира в archived_products таблица за бъдещи справки.

  2. След това изтрийте продукт от products таблица и вижте дали тригерът ще бъде извикан:

    DELETE FROM products WHERE product_id='3';
    
  3. Сега, ако проверите archived_products таблица, трябва да видите един запис:

    SELECT * FROM archived_products;
    

    Изход:

    +------------+--------------+------------+--------------+--------------+
    | product_id | product_name | cost_price | retail_price | availability |
    +------------+--------------+------------+--------------+--------------+
    |          3 | SMART WATCH  |      189.6 |        225.3 | LOCAL        |
    +------------+--------------+------------+--------------+--------------+
    1 row in set (0.00 sec)

Изтриване на тригер

Виждали сте различните видове тригери и как те могат да се използват в производствена среда. Понякога може да искате да премахнете тригер от базата данни.

Можете да изтриете задействане, ако не искате да го използвате повече, като използвате синтаксиса по-долу:

DROP TRIGGER IF EXISTS TRIGGER_NAME;
Забележка IF EXISTS ключовата дума е незадължителен параметр, който изтрива само тригер, ако съществува.

Например, за да изтриете product_archiving тригер, който дефинирахме по-горе, използвайте командата по-долу:

DROP TRIGGER IF EXISTS product_archiver;

Изход:

Query OK, 0 rows affected (0.00 sec)
Внимание Бъдете внимателни, когато изтривате таблици, свързани с тригери. След като таблица бъде изхвърлена от базата данни MySQL, свързаните тригери също се изтриват автоматично.

Повече информация

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

  • Синтаксис и примери за задействане на MySQL

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Каква е разликата между използването на INDEX срещу KEY в MySQL?

  2. Преглед на репликацията от клъстер към клъстер

  3. UTC_TIMESTAMP() Примери – MySQL

  4. Потребителски права на MySQL на споделени сървъри

  5. Как да получите броя дни на разлика между две дати в MySQL?