otrdiena, 2011. gada 1. marts

DML trigeri

DML (Data Manipulation Language) trigeri ir pats senākais un biežāk izmantotais trigeru veids SQL Server. Šajā rakstā aprakstītas manuprāt svarīgākās lietas.

Kas ir DML trigeris?
Trigeris ir speciāls saglabātās procedūras veids, kura tiek izpildīta kā reakcija uz kādu notikumu. DML trigeri tiek izsaukti datu modificēšanas notikumu rezultātā (Insert, Update, Delete). DML trigerus var izveidot uz datu bāzes tabulām un skatiem (ar izņēmumiem. Piemēram, ja skats veidots ar "With Check Option").

DML trigeri tiek izmantoti lai nodrošinātu datu integritāti un specifiskas biznesa prasības SQL Server datu bāzē. Tik nevajadzētu aizmirst, ka ir arī citi datu integritātes nodrošināšanas mehānismi (ierobežojumi, indeksi. plašāk Datu integritāte SQL Server). 

Gadījumi, kad trigeri varētu uzskatīt kā labāko risinājumu datu integritātes nodrošināšanai:
- lai nodrošinātu referenciālo integritāti ar tabulu citā datu bāzē;
- uzturētu datus kādā kopsavilkumu tabulā (kas, piemēram, tiek izmantota pārskatiem)
- atgrieztu lietotājam specifisku kļūdas paziņojumu (pārbaudes ierobežojumiem nevar pielāgot ziņojuma saturu)
- kad nepieciešams noteikt veiktās izmaiņas, salīdzinot jaunās vērtības ar iepriekšējām.
- .. un droši vien ir vēl ..

Vēl daži gadījumi, kad trigeri ir noderīgi:
- Lai skatu, kurš atgriež datus no vairākām tabulām, varētu mainīt (izmantojot insert, update, delete).
- Lai veiktu datu mainīšanas auditu (piefiksētu kādas izmaiņas un kad veicis lietotājs).

Kad trigeris tiek izsaukts?
Kā jau minēts, DML trigeris izpildās kā rekcija uz datu modificēšas notikumiem- Insert, Update, Delete. DML trigeri var definēt kā reakciju gan uz vienu konkrētu, gan arī uz vairākām/visām datu modificēšanas darbībām. Tātad, piemēram:
- var izveidot trigeri, kas tiek izsaukts tikai ievietojot jaunu rindu datu bāzes tabulā;
- var izveidot trigeri, kas tiek izsaukts gan rindas ievietošanas gan rindas dzēšanas gadījumos.

Vēl var definēt DML trigera izsaukšanas brīdi. Ir divi varianti:
- "Pēc" (After trigeris), kas tiek izsaukts pēc tam, kad konkrētā DML darbība ir veikta (piemēram, pēc rindas dzēšanas no datu bāzes tabulas).
- "Tā vietā" (Instead of trigeris), kas tiek izsaukts konkrētās DML darbības vietā (piemēram, tā vietā, lai rindu dzēstu no datu bāzes, tiek izpildīts trigeris).

Kas notiek trigera iekšienē?
Trigeris ir saglabātās procedūras speciālgadījums. Trigeri var uzskatīt par procedūru, kurai nav ieejas parametru un kura neatgriež vērtību. Trigerim nevar definēt lietotāja tiesības (ja lietotājam ir tiesības veikt konkrēto DML darbību tabulai vai skatam- tad veicot konkrēto darbību arī tiks izsaukts trigeris).

Atšķirībā no procedūrām, trigera iekšienē ir izmantojamas speciālas tabulas- Inserted un Deleted. Tāpat arī ir pieejamas dažas iebūvētās funkcijas, kas izmantojamas vienīgi trigera iekšienē

Inserted un Deleted tabulas pēc idejas ir vienkāršas, tomēr mulsinošas (msdn šeit).
Abas šīs tabulas ir ar tādu pašu struktūru, kā tabula vai skats, uz kuru tiek veikta DML darbība. Abas tabulas eksistē trigera iekšienē un to saturs nav maināms.
[2011-05-17 papildināts: šīs tabulas var izmantot arī T-SQL Output klauza]

Kādi dati ir šajās tabulās?
Inserted- "Pēc" trigera gadījumā- kāda(s) jaunā(s) rinda(s) izskatās datu bāzē. "Tā vietā" trigera gadījumā- kāda(s) jaunā(s) rinda(s) izskatītos datu bāzē, ja trigera nebūtu (ar "jaunās" saprotot gan no jauna ievietotās, gan mainītās rindas).
Deleted- Kāda(s) rinda(s) bija datu bāzē pirms DML trigera izsaukšanas.

Tālāk ar attēliem parādīts, kā izskatās Inserted un Deleted tabulas katras DML darbības gadījumā.
Insert
Šajā gadījumā trigera iekšienē Inserted tabulā ir jaunā rinda. Deleted tabula ir tukša. Pieņemot, ka ID ir identity lauks- tajā jau ir uzģenerēta jaunā vērtība.

Delete
Deleted tabulā ir dzēstā rinda, bet Inserted tabula ir tukša.


Update 
Rinda kāda bija pirms izmaiņām ir Deleted tabulā, savukārt rinda ar jaunajām vērtībām ir Inserted tabulā

Kā jau minēts iepriekš, trigera iekšienē var izmantot dažas unikālas funkcijas (līdztekus visām citām funkcijām). Ties gan, gadījumi, kad tās izmanto, ir salīdzinoši reti. (msdn skatīt šeit)
* Update(Kolonas_Nosaukums) - funkcija atgriež 1, ja tiek mainīta/piešķirta kolonnas vērtība, savukārt 0, ja kolonna netiek mainīta (update gadījumā netiek salīdzināta iepriekšējā vērtība ar esošo vērtību, līdz ar to tiks atgriezts 1 pat tad, ja kolonas vērtība faktiski netiek mainīta- tas manuprāt šo funkciju padara mazāk lietojamu).
* Columns_Updated() - līdzīgi kā iepriekš, tikai var pārbaudīt uzreiz vairākas kolonnas, izmantojot bitu masku.
* Eventdata() - plašāk pielietojumu funkcijai var skatīt rakstos par DDL un Pieteikšanās trigeriem.
* Trigger_Nestlevel() - cik trigeru ir izsaukti konkrētajai DML komandai.

Trigeru rekursija un izpildes secība
Trigeri var būt rekursīvi, tomēr (par laimi) to parasti neizmanto. Lai trigeri varētu kļūt rekursīvi, ir nepieciešams datu bāzē atļaut trigeru rekursiju. Manuprāt tā nav diez ko laba doma.

Trigeru izpildes secību daļēji var definēt, nosakot kurš trigeris būs pirmais, kurš- pēdējais. Tātad- ja ir vairāk kā 3 trigeri, var uzstādīt pirmo un pēdējo trigeri, bet nevari zināt kādā secībā izpildīsies pārējie trigeri. Subjektīvi liekas, ka ar izpildes secību nevajadzētu aizrauties. Trigeros ir viegli sastrādāt nepatīkamas un grūti atkļūdojamas lietas, tādēļ nevajadzētu visu vēl vairāk sarežģīt sadalot loģiku pa vairākiem trigeriem.

1 komentārs:

  1. Nja... teikšu godīgi! Šīs raksts tagad ir mans favorīts, jo ir rakstīts ļoti profesionāli! Beidzot ir raksts, kas ir labi skaidrs, viegli lasāms un noderīgs arī cilvēkam, kas ikdienā nestrādā un nav tik bieži saskaries ar SQL Serveriem. Patīka gan ievads, kurā labi izskaidrots, kas ir trigeri, kad un kādam nolukam tos lieto, gan arī iztirzājums par trigieru lietojumu, piemēri un izpildes process.

    AtbildētDzēst