Өгөгдлийн сангийн триггер

## Триггер 
### Триггертэй ажиллах 
** isql ** нь триггер болон алдааг үүсгэх, өөрчлөх, устгах боломжтой.
#### Триггерийг байгуулах 
Триггерийг CREATE TRIGGER командаар байрлуулах бөгөөд тэр нь толгой (header) болон их бие (body) гэсэн хоёр хэсгээс бүрдэнэ.
##### Триггерийн толгой нь дараах зүйл агуулна : 
 1. Мэдээллийн санд давтагдашгүй триггерийн нэр
 2. Триггерт холбоотой хүснэгтийн нэр
 3. Триггер ажиллах үйлдлийн нэр
 4. Локал хувьсагчуудыг нэр ба тодорхойлолтууд
 5. BEGIN, END оператораар хязгаарлагдсан командууд. Командууд нь триггерийн хийх үйлдлүүдийг заана. Их бие нь дотроо өөр блок хэрэглэж 
     болох ба блокуудын үеийн тоог маш олон байж болно.
** Чухал **

Триггер доторх командуудыг цэг таслалаар хязгаарладаг болохоор триггер өөрийг нь хязгаарлах өөр тэмдэгт оруулах шаардлагатай. ** isql** -д үүний тулд CREATE TRIGGER-ын өмнө SET TERM команд хэрэглэж хязгаарлагч тэмдэгтийг өөрчилдөг. Триггерийн их бие дууссаны дараа дахин SET TERM хэрэглэж хязгаарлагчийн хэвийн байдалд (цэг таслал)-д оруулна.
#### Триггерийг байгуулах синтакс 
```postgresql
CREATE TRIGGER name FOR table
[ACTIVE | INACTIVE]
{BEFORE | AFTER}  {DELETE | INSERT | UPDATE}
[POSITION number]
AS

 = 
[]

 =
DECLARE VARIABLE variable datatype;
[DECLARE VARIABLE variable datatype; . . .]

 =
BEGIN

[ . . .]
END

 =
{ | statement;}
```

##### Триггерийг байгуулах командын аргумент 
#### InterBase-ын процедур ба триггерийн хэл 
InterBase-ын процедур ба триггерийн хэл нь хадгалдаг процедур болон триггер бичихэд зориулагдсан програмчлалын төгс хэл юм. Хэл нь дараах зүйлээс бүрдэнэ:

SQL-ын мэдээллийн боловсруулах командууд : INSERT, UPDATE, DELETE ганцаарчилсан (дан-singleton) SELECT.

SQL-ын оператор болон илэрхийлэл, хэрэглэгчийн тодорхойлсон мэдээллийн сервер болон генераторуудын холбоос.

SQL- хэлний бүхэл бололцоо : утга авх оператор, нөхцөл, шалгуурт операторууд, контекстийн хувьсагчууд, event боловсруулах командууд, алдааны командууд.

Хадгалдаг процедур, триггер хоёр өөр өөр үүрэг зорилготой хэдий ч хоёулаа энэ хэлийг ашигладаг. Харин процедур ба триггерийн хэлийг хэрэглэхдээ дараах хязгаарлалттай: Триггерийн хувьд контекстийн хувьсагчууд (context variables) давтагдашгүй байх ёстой

Хадгалдаг процедурын хувьд хариу эргүүлж өгдөг SUSPEND, EXIT командууд, оролт, гаралтын параметрүүд давтагдашгүй байна.
##### Процедур ба триггерийн хэлний өргөтгөлүүд (extension) 
### SET TERM -ыг ** isql ** -д ашиглах 
Триггерийн команд болгон цэг таслалаар хязгаарлагддаг болохоор триггерийг өөрийн хязгаарладаг тэмдэгт хэрэгтэй болно. iql -д үүний тулд CREATE TRIGGER командын өмнө SET TERM гэдэг үгийг хэрэглэж хязгаарлагчийг өөр тэмдэгтээр солино. Триггер дууссаны дараа дахин SET TERM -ыг ашиглан хязгаарлагчийг буцааж цэг таслал болгоно.
SET TERM энэ хоёр үгний хооронд ёул зай байх ёстой. SET TERM -ыг өөрийн хэрэглэж байгаа (current) тэмдэгтээр хязгаарлана.
#### Триггер дахь синтакс (үг, үсгийн) алдаанууд 
CREATE TRIGGER - командад үг үсгийн алдаа байвал InterBase нь энэ тухай мэдээлнэ. 

** Жишээ **

```postgresql
Statement failed, SQLCODE = -104
Dynamic SQL Error
-SQL error code = - 104
-Token unknow - line 4, char 9
-tmp
```

Мөрний дугаар нь командын файлын эхлэлээс биш гагцхүү CREATE TRIGGER командын эхлэлээс хойших дугаар.
#### Триггерийн толгой 
CREATE TRIGGER командын AS операторын өмнө орсон бүх зүйл нь триггерийн толгой юм. Толгой нь заавал триггерийн нэр, холбогдох хүснэгтийн юм уу харах хүснэгтийн нэртэй байна. Хүснэгт буюу харах хүснэгт нь триггерээс өмнө байгуулагдсан байх ёстой.
Дараахь операторууд нь триггерыг ажиллах нөхцөл, мөчийг тодорхойлно:

Триггерийн статус ACTIVE, INACTIVE триггерийг ажиллах эсэхийг заана. Суурь статус нь ACTIVE - триггер нөхцөл мөч нь бий болсон үед биелэгдэнэ. Туршилтын үед ALTER TRIGGER -аар статусыг INACTIVE болгож болно.

Триггерийн биелэгдэх мөч BEFORE, AFTER нь триггерийг хэзээ ажиллах вэ гэдгийг заана. BEFORE нь үйлдлийн өмнө хийгдэнэ, AFTER нь үйлдлийн дараа.

Триггерийн үйлдэл INSERT, DELETE, UPDATE нь триггер ямар үйлдэл болоход ажиллах вэ гэдгийг заана. Дээрх гурван үйлдлийн аль нэг нь заавал заагдсан байх ёстой. Нэг үйлдэл дээр олон өөр нэртэй триггер байж болно.

Биелэгдэх дэс дарааллын дугаар POSITION number гэдэг нь адил үйлдэл дээр тодорхойлогдсон триггерүүдийн эхэлж ажиллах дарааллыг заана. Дугаар нь 0-оос 32767 хүртэл бүхэл тоо, суурь утга нь тэг, бага дугаартай триггер эхэлж ажиллана, адил дугаартай триггерүүд санамсаргүй дарааллаар ажиллана.
##### Доорх жишээнд дарааллын дугаарыг яаж заахыг үзүүлнэ 
```postgresql
CREATE TRIGGER A FOR ACCOUNTS BEFORE UPDATE POSITION 5 AS . . .
CREATE TRIGGER B FOR ACCOUNTS BEFORE UPDATE POSITION 0 AS . . .
CREATE TRIGGER C FOR ACCOUNTS AFTER  UPDATE POSITION 5 AS . . .
CREATE TRIGGER D FOR ACCOUNTS AFTER  UPDATE POSITION 3 AS . . .
```

#### Триггерийн их бие 
CREATE TRIGGER командын AS операторын хойно орсон бүх зүйлийг триггерийн их бие гэнэ. Их бие нь BEGIN ба END -н хооронд байрласан InterBase-ын процедур ба триггерийн хэлний командуудаас бүрдэнэ.

InterBase-ын процедур ба триггерийн хэлний онцлог командууд нь :

Утга өгөх команд (локал хувьсагчуудад утга өгнө)

Нөхцөлт командууд - IF . . . THEN, WHILE . . . DO, FOR SELECT . . . DO

Хадгалдаг процедур дуудах EXECUTE PROCEDURE команд 

Алдааны мэдээлэл өгдөг, алдаа боловсруулдаг тодорхой алдаа заадаг WHEN команд 

Баганын хуучин ба шинэ утгыг илэрхийлэх NEW ба OLD контекстийн хувьсагч.

Давтагдашгүй утга гаргах генератор.

** Тайлбар **

 Контекстийн хувьсагчаас бусад бүх командуудыг триггер болон процедурын аль алинд нь хэрэглэнэ.

** “Хадгалдаг процедуртай ажиллах”-аас дэлгэрэнгүй харна уу? **

```postgresql
NEW and OLD Context variable
NEW and OLD Context variable
```

Триггер нь контекстийн хоёр хувьсагч ашигладаг NEW ба OLD. 
NEW нь INSERT ба UPDATE командад баганын шинэ утгыг илэрхийлсэн контекстийн хувьсагч, OLD нь UPDATE ба DELETE командад баганын хуучин утгыг илэрхийлсэн контекстийн хувьсагч юм.
* Контекстийн хувьсагчийн синтакс

```postgresql
NEW.column
OLD.column
```

column нь дурын баганын нэр. Контекстийн хувьсагчийг ердийн хувьсагчийн хэрэглэхтэй адил.

Баганын шинэ утгыг зөвхөн үйлдлийн өмнө өөрчилж болно. Хэрвээ триггер INSERT-ын дараа (AFTER) гэж тодорхойлогдсон бол NEW-ийн утгыг өөрчлөх нь ямар нөлөө үзүүлэхгүй. Доорх жишээнд EMPLOYEE хүснэгтийн триггер нь өөрчлөлт орсны дараа шинэ ба хуучин утгуудын жишээ байна. Хэрвээ salary баганад өөрчлөлт орсон бол SALARY_HISTORY хүснэгтэд бичилт нэмнэ.

```postgresql
SET TERM !! ;
CREATE TRIGGER SAVE_SALARY_CHANGE FOR EMPLOYEE
AFTER UPDATE AS
BEGIN
IF (OLD.salary <> NEW.salary) THEN
INSERT INTO SALARY_HISTORY
(EMP_NO,CHANGE_DATE,UPDATER_ID,OLD_
SALARY,PERCENT_CHANGE)
VALUES (OLD.emp_no, “now”, USER, OLD.salary,
 (NEW.salary - OLD.salary) * 100 / OLD.salary);
END !!
SET TERM ; !!
```

** Тайлбар: ** SQL-ын командаас бусад тохиолдолд контекстийн хувьсагчид цэг тэмдэгтийг ашиглахгүй.
### Генераторыг ашиглах 
Генератор гэдэг нь дуудах бүрт автоматаар нэмэгддэг GEN_ID() функц юм. Генераторыг процедур, триггертэй төстэй application-уудад хэрэглэдэг ба unique баганын утгуудыг гаргадаг триггерт голчлон ашигладаг.  
Генераторыг CREATE GENERATOR ашиглаж үүсгээд SET GENERATOR -аар тохируулдаг. Тохируулга хийгээгүй бол генераторын утга 0-с эхэлнэ.  “Language Reference”-с дэлгэрүүлж үзнэ үү. 
GEN_ID() функцээр генераторыг дуудахаас өмнө CREATE GENERATOR -аар үүсгэсэн байх хэрэгтэй. Синтакс:
	GEN_ID(genname, step)
genname - генераторын нэр
step	- генераторын утгыг нэмэгдүүлэх алхам, бүхэл тоо байж болохоос гадна бүхэл тоо гаргадаг илэрхийлэл байж болно.
Дараах ** жишээнд ** CUSTOMER хүснэгтэд утга нэмэхээс(insert) өмнө шинэ үйлчлүүлэгчийн дугаарыг гаргахад GEN_ID() функцийг ашиглаж байна:

```postgresql
SET TERM !!;
CREATE TRIGGER SET_CUST_NO FOR CUSTOMER
BEFORE INSERT AS
BEGIN
     NEW.cust_no = GEN_ID(CUST_NO_GEN, 1);
END!!
SET TERM ;!!
```

### Триггерийг өөрчлөх 
Триггерийг өөрчлөхдөө ALTER TRIGGER ашиглана. Триггерийг зөвхөн үүсгэсэн хүн өөрчилнө. 
ALTER TRIGGERS ашиглаж зөвхөн дараах зүйлүүдийг өөрчилж болно:
* Зөвхөн толгой (Энд: event, триггерийн дугаар, trigger activation status)
* Зөвхөн их бие (AS -аас хойш орсон)
* Толгой ба их бие . Энэ тохиолдолд хуучин мэдээлэл нь шинэ мэдээллээр солигдоно.
#### Триггерийн толгойг өөрчлөх 
Триггерийн толгойг өөрчлөхдөө ALTER TRIGGER -ийн триггерийн нэрийн дараа ганц өөрчлөлтийг бичнэ. Илүү байгаа өөрчлөлтүүдийг хийхгүй.

** Эхлээд триггерийг идэвхгүй болгоно: **

```postgresql
ALTER TRIGGER SAVE_SALARY_CHANGE INACTIVE;
```

#### Триггерийн их биеийг өөрчлөх 
Триггерийн биеийг өөрчлөхдөө хуучин их бие шинэ тодорхойлолтоор солигдоно. Триггерийн зөвхөн их биеийг өөрчлөх бол ALTER TRIGGER -т триггерийн нэрээс өөр толгойн ганц ч мэдээллийг агуулаагүй байх ёстой.

** Триггерийн их биеийг өөрчлөхдөө: ** Мэдээлэл агуулсан файлыг (data definition file) хуулж хадгална. Үүнтэй адилаар ISQL - extract командаар триггерийг мэдээллийн сангаас файл руу задална.
CREATE -г ALTER болгож триггерийн нэр ба AS -н хооронд орших толгойн мэдээллийг арилгана.

Дараах ** жишээнд ** SET_CUST_NO триггерийн их биеийг өөрчилж, шинэ үйлчлүүлэгч бүрийн мэдээллийг NEW_CUSTOMER хүснэгтэд нэмдэг болгож байна.

```postgresql
SET TERM !!;
ALTER TRIGGER SET_CUST_NO
BEFORE INSERT AS
BEGIN
      new.cust_no = GEN_ID(CUST_NO_GEN, 1)
      INSERT INTO NEWCUSTOMER(new.cust_no, TODAY)
END!!
SET TERM ;!!
```

#### Триггерийг устгах 
Триггерийг бүрмөсөн (permanently) устгахдаа DROP TRIGGERS ашиглана.
Триггерийг устгахад дараах хязгаарлалтууд байдаг: Триггерийг үүсгэсэн хүн л устгаж болно.
Хэрэглэгдэж байгаа триггерийг устгаж чадахгүй.
Триггерийг түр зуур арилгах (temporarily remove) шаардлагатай бол ALTER TRIGGER -ийн INACTIVE -г ашиглах хэрэгтэй.
##### Триггерийг устгах синтакс 
```postgresql
DROP TRIGGER name;
```

name нь оршин байгаа триггерийн нэр. ** Жишээ: **

```postgresql
DROP TRIGGER SET_CUST_NO;
```

** Санамж: ** CHECK дотор хэрэглэгдэж байгаа триггерийг (a system-defined trigger) устгаж чадахгүй. ALTER TABLE ашиглаж CHECK -г өөрчил.
### Триггерийг ашиглах 
Триггер нь янз бүрийн зорилгоор ашиглаж болох хүчтэй хэрэгсэл юм. Триггерийг ашиглах янз бүрийн тохиолдлууд байна:
Хамааралтай өөрчлөлтүүд хийх. (Correlated updates). Жишээ нь мэдээллийн сан буюу хүснэгтийн өөрчлөлтийн log файл үүсгэх
Хүснэгтэд зөвхөн зөв өгөгдлийг оруулах хязгаарлалт хийх. 
Event ашиглаж мэдээллийн сангийн өөрчлөлтийн талаар мэдээлэх
Шат дараалсан өөрчлөлтүүдийг хийх (cascading referencial integrity updates)
 Триггер нь хадгалагдсан процедур, exception -уудын адилаар мэдээллийн сангийн нэг хэсэг болон хадгалагдана.ACTIVE байдалд байгаа бол устгах(DROP TRIGGER), идэвхгүй болгох(ALTER TRIGGER INACTIVE) хүртэл идэвхтэй байсаар байна. 
Триггерийг шууд дууддаггүй. Тухайн хүснэгтэд тухайн үйлдэл (action) болох үед триггер автоматаар ажиллана.
* Анхаар: Тухайн нэг триггер нь өөрийгөө ажиллуулах үйлдэл хийдэг- эсвэл өөрийг нь ажиллуулдаг өөр триггерийг ажиллуулах үйлдэл хийдэг бол төгсгөлгүй үргэлжилсэн үр дүн гарна. Ийм учраас шаардлагагүй бол триггерийн үйлдэл нь өөр триггерийг ажиллуулах нөхцөл болохгүй байх нь чухал юм.
### Триггер ба транзакци 
Триггер нь үйлдэл хийх үедээ программын транзакцийн контексттэй ажилладаг. Триггер нь дуудаж буй программын (calling program) ажлын нэг хэсэг нь болно. Хэрэв триггер нь транзакцид ажилладаг бол транзакц дууссаны дараа триггерийн үйлдэл мөн дуусна.
### Триггер ба нууцлал 
Триггер нь процедур ба хэрэглэгчийн нэгэн адилаар хүснэгтийг ашиглах эрхтэй байна. Гэхдээ GRANT TO username гэж бичихийн  оронд TO TRIGGER trigger_name гэж бичнэ. REVOKE мөн адил. 

Хэрэглэгч триггерийг ажиллуулах үйлдэл хийхэд:
* триггер тухайн үйлдлийг хийх эрхтэй бол
* хэрэглэгч тухайн үйлдлийг хийх эрхтэй бол гэсэн тохиолдлуудад триггер үйлдлийг хийх эрхтэй байна.
** Жишээ нь: ** Хэрэв нэг хэрэглэгч A хүснэгт дээр UPDATE хийдэг ба В хүснэгтэд INSERT хийдэг триггерийн ажиллах нөхцөл болдог бол хэрэглэгч INSERT хийх эрхтэй тохиолдолд л триггер нь INSERT хийх эрхтэй болно.
Триггер тухайн үйлдлийг хийх эрхгүй бол Interbase SQLCODE алдааны дугаарыг буцаана. Триггер нь WHEN командын тусламжтайгаар алдааг боловсруулж болно. Хэрэв алдааг боловсруулдаггүй бол application -д алдааны мэдээлэл очих ба триггерийн үйлдэл хийгдэхгүй.
### Триггерээр event үүсгэх 
Триггер нь мэдээллийн санд өөрчлөлт хийгдсэн үед event үүсгэж болно. ** Жишээ нь: **

```postgresql
SET TERM !!;
CREATE TRIGGER POST_NEW_ORDER FOR SALES
AFTER INSERT AS
BEGIN
     POST_EVENT ”new_order”;
END!!
SET TERM;!!
Триггер event-ийн нэрэнд хувьсагч хэрэглэж болно:
POST_EVENT :event_name;
```

### Алдааны мэдээлэл 
Exception  гэдэг нь хадгалагдсан процедур, триггерээс гарах алдааны мэдээлэл юм. Exception-г CREATE EXCEPTION-аар үүсгэж,  ALTER EXCEPTION-аар өөрчилж, DROP EXCEPTION-аар устгана.
* Хүснэгтэд өөрчлөлт хийхэд хэрэв шинэ цалин нь хуучнаас 50-аас дээш хувиар нэмэгдсэн тохиолдолд гардаг алдааны мэдээлэл байж болох юм. ** Жишээ нь: **

```postgresql
New salary exceeds old by more than 50%. Cannot update record.
```

* ** Чухал: ** Процедур, триггерийн адилаар exception нь мэдээллийн санд үүс ч, хадгалагдах ба мэдээллийн сангийн аль ч процедур, триггерт ашиглагдаж болно. Exception-г триггерт ашиглахаас өмнө мэдээллийн санд үүс ч, хадгалагдсан байх ёстой.
#### Триггер дотор алдааны мэдээлэл гаргах 
##### Триггер дотор алдааны мэдээлэл гаргахдаа дараах синтакстай бичнэ: 
```postgresql
EXCEPTION name;
```

name - мэдээллийн сан дээр оршин байгаа алдааны мэдээлэл. Алдааны мэдээлэл гаргахад:
Триггерийн үйлдлийг буцааж, ажиллагааг зогсооно.
Триггерийг ажиллуулж буй application-д алдааны мэдээллийг буцаана. Хэрэв ISQL командаар триггерийг ажиллуулсан бол дэлгэцэн дээр алдааны мэдээлэл гарна.
* ** Чухал: ** WHEN командаар алдааг боловсруулдаг бол дээрхээс арай ялгаатай байна.
#### Триггер дотор алдааг боловсруулах 
Триггер дотор алдаа, алдааны мэдээллийг WHEN командаар боловсруулж болно. Алдааны мэдээллийг WHEN командаар боловсруулдаг бол application-д мэдээлэл буцахгүй ба триггерийн үйл ажиллагааг заавал таслах албагүй юм.
Триггерийн алдааны боловсруулалт (error handling) нь хадгалагдсан процедуртай адилхан ажиллана: WHEN хүртэл хийгдсэн үйлдлүүд нь буцах (undone) бөгөөд WHEN команд ажиллана.
#### MSSQL датабаазын хүснэгт дээр триггер бичих 
* ** Insert Trigger **

```postgresql
CREATE TRIGGER trigger_insert1
ON table1
FOR INSERT
AS
BEGIN
UPDATE table2
    SET field_total = field_total + inserted.field_name1
END
```

* ** Update Trigger **

```postgresql
CREATE TRIGGER trigger_update1
ON table1
INSTEAD OF UPDATE
AS
BEGIN
SELECT t1.*, i.* FROM table1 t1
    JOIN inserted i ON t1.field_id = i.field_id
END
```

* ** Delete Trigger **

```postgresql
CREATE TRIGGER trigger_delete1
ON table1
FOR DELETE
AS
BEGIN
INSERT INTO logTableName
    SELECT * FROM deleted
END
```

* ** Trigger Event **
deleted - DELETE trigger үед дата нь deleted гэсэн хүснэгт хэлбэрээр байна.

inserted - INSERT, UPDATE trigger үед дата нь inserted гэсэн хүснэгт хэлбэрээр байна.
* ** Trigger Time **
FOR DELETE – Устгахаас өмнө

FOR INSERT – Нэмэхээс өмнө

FOR UPDATE – Засахаас өмнө

FOR INSERT, UPDATE – Нэмж, Засахаас өмнө

AFTER DELETE – Устгасны дараа

AFTER INSERT – Нэмсний дараа

AFTER UPDATE – Зассаны дараа

AFTER INSERT, UPDATE – Нэмж, Зассаны дараа

INSTEAD OF DELETE – Устгахын оронд

INSTEAD OF INSERT – Нэмэхийн оронд

INSTEAD OF UPDATE – Засахын оронд

INSTEAD OF INSERT, UPDATE – Нэмж, Засахын оронд

Ангилал:Өгөгдлийн менежмент