Advertisement
Guest User

Untitled

a guest
May 20th, 2018
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.37 KB | None | 0 0
  1. -- 1. Да се направи така, че при добавяне
  2. -- на нов клас автоматично да се добавя и
  3. -- нов кораб със същото име и с година на
  4. -- пускане на вода = null.
  5. use ships;
  6. go
  7. create trigger t1
  8. on classes
  9. after insert
  10. as
  11. insert into ships(name, class)
  12. select class, class
  13. from inserted;
  14.  
  15. -- тестване:
  16. insert into classes
  17. values('Test', 'bb', 'Bulgaria', 14, 20, 80000);
  18. select * from ships where name = 'Test';
  19. drop trigger t1;
  20.  
  21. -- 2. При изтриване на кораб автоматично да се изтрива и неговият клас, ако
  22. -- няма повече кораби от този клас.
  23. -- Забележка: ако преди това е имало класове без кораби - да не се пипат!
  24. -- Забележка: клас без кораби може да се получи и при update
  25. go
  26.  
  27. create trigger t2
  28. on ships
  29. after delete
  30. as
  31. delete from classes
  32. where class in (select class
  33. from deleted
  34. where class not in (select class
  35. from ships));
  36. -- Забележка: ако не използвахме deleted,
  37. -- а направо ships, щяхме да изтрием и
  38. -- класове, които са били празни и преди
  39. -- съответния delete
  40.  
  41. -- тестване:
  42. -- в предишната задача вече сме добавили нов клас и нов кораб, ще използваме тях
  43. delete from ships
  44. where name = 'Test';
  45. select *
  46. from classes
  47. where class = 'Test';
  48. drop trigger t2;
  49. go
  50.  
  51. -- леко - искаме при изтриване на клас да се изтриват и
  52. -- всички кораби - ами може с on delete cascade
  53.  
  54.  
  55. -- 3. Да се направи така, че ако при
  56. -- добавяне или обновяване на кораб
  57. -- годината му на пускане е по-голяма от
  58. -- текущата година, то годината му да бъде
  59. -- променена на null. (това е задача 3-А от 12.exerciseTriggers.pdf)
  60.  
  61. -- в MSSQL няма BEFORE тригери, затова ще търсим друг начин
  62. create trigger t3
  63. on ships
  64. after insert, update
  65. as
  66. update ships
  67. set launched = null
  68. where name in (select name
  69. from inserted
  70. where launched > year(getdate()));
  71. -- тестване:
  72. insert into ships values('Test','Iowa',2250);
  73. select * from ships where name='Test';
  74. delete from ships where name='Test';
  75. drop trigger t3;
  76. go
  77. -- горното решение ще гръмне, ако има check(launched <= year(getdate()) в ships!
  78.  
  79. -- ако трябва в тялото на тригер да разграничим дали е бил извикан при insert или при update,
  80. -- можем да проверим if exists (select * from deleted)
  81.  
  82. -- ако беше само за insert, можеше да направим instead of insert и всичко щеше да е наред
  83. create trigger t
  84. on ships
  85. instead of insert
  86. as
  87. insert into ships(name, class, launched)
  88. select name, class, case
  89. when launched > year(getdate()) then null
  90. else launched
  91. end
  92. from inserted;
  93.  
  94. -- вариант без case:
  95. -- insert into ships
  96. -- select * from inserted where launched <= year(getdate())
  97. -- union all
  98. -- select name, class, null from inserted where launched > year(getdate());
  99. drop trigger t;
  100. go
  101.  
  102. -- 4. При промяна на черно-бял филм на цветен съответният продуцент да получава $100000.
  103. -- Ако в една UPDATE заявка са били променени няколко филма на един продуцент, той да получи
  104. -- само веднъж 100000.
  105. use movies;
  106. go
  107.  
  108. create trigger t4
  109. on movie
  110. after update
  111. as
  112. update movieexec
  113. set networth = networth + 100000
  114. where cert# in (select i.producerc#
  115. from deleted d
  116. join inserted i on d.title = i.title and d.year = i.year
  117. where d.inColor = 'n' and i.inColor = 'y');
  118.  
  119. drop trigger t4;
  120. go
  121.  
  122. -- Следващият пример е за валидация на данни. Всички задачи от такъв тип може да се решат аналогично.
  123.  
  124. -- 5. Да не се допуска добавянето на ред
  125. -- в OUTCOMES, който да указва, че даден
  126. -- кораб е участвал в битка, преди да бъде
  127. -- пуснат на вода.
  128.  
  129. -- Aко се добавят няколко реда и поне един от тях нарушава условието за коректност,
  130. -- цялата операция ще бъде отменена.
  131. use ships;
  132. go
  133.  
  134. create trigger t5
  135. on outcomes
  136. after insert
  137. as
  138. if exists (select *
  139. from inserted
  140. join ships on ship = ships.name
  141. join battles on battle = battles.name
  142. where launched > year(battles.date))
  143. begin
  144. raiserror('Error: ship is launched after the battle', 16, 10); -- има само едно "е"
  145. rollback;
  146. end;
  147.  
  148. -- проверка:
  149. insert into outcomes(ship, battle, result)
  150. values('Iowa', 'North Atlantic', 'sunk');
  151.  
  152. select * from outcomes
  153. where ship='Iowa';
  154.  
  155. drop trigger t5;
  156. go
  157.  
  158.  
  159. -- С помощта на INSTEAD OF тригерите може да се изпълняват INSERT, UPDATE и DELETE заявки върху всеки изглед.
  160.  
  161. -- 6. Да се създаде изглед за всички
  162. -- потънали кораби (име на кораб и битка), т.е. за всеки
  163. -- потънал кораб да казва в коя битка е потънал,
  164. -- който да позволява insert, update, delete.
  165.  
  166. create view SunkShips
  167. as
  168. select ship, battle
  169. from outcomes
  170. where result = 'sunk';
  171. go
  172.  
  173. -- UPDATE и DELETE могат да се изпълнят безпроблемно,
  174. -- но при INSERT новият ред би имал result = null, което не ни върши работа.
  175.  
  176. create trigger t6
  177. on SunkShips
  178. instead of insert
  179. as
  180. insert into outcomes(ship, battle, result)
  181. select ship, battle, 'sunk'
  182. from inserted;
  183.  
  184. drop trigger t6;
  185.  
  186. -- 7. -- Симулиране на ON DELETE SET NULLS
  187. -- MS SQL не поддържа ON DELETE SET NULLS. Да се реализира с
  188. -- тригери за външния ключ movie.producerc#
  189. go
  190. use movies;
  191. go
  192.  
  193. create trigger t
  194. on movieexec
  195. instead of delete --не може after trigger заради FK;
  196. -- в други СУБД има before тригери
  197. as
  198. begin
  199. update movie
  200. set producerc# = null
  201. where producerc# in (select cert# from deleted);
  202.  
  203. -- следващата операция е тази, която по принцип щеше да се изпълни и без тригер
  204. delete from movieexec
  205. where cert# in (select cert# from deleted);
  206. end;
  207.  
  208. -- ако имаме INSTEAD OF INSERT и искаме да изпълним INSERT заявката, която е била предвидена:
  209. -- INSERT INTO <table>
  210. -- SELECT * FROM INSERTED;
  211.  
  212. go
  213. -- 12.exerciseTriggers.pdf
  214.  
  215. -- Зад. 1. Да се напише тригер за таблицата MovieExec, който не позволява
  216. -- средната стойност на Networth да е по-малка от 500 000 (ако при промени в
  217. -- таблицата тази стойност стане по-малка от 500 000, промените да бъдат
  218. -- отхвърлени).
  219. create trigger t
  220. on movieexec
  221. after insert, update, delete
  222. as
  223. if (select AVG(networth)
  224. from movieexec) < 500000
  225. begin
  226. raiserror('Error: Average networth cannot be < 500000', 16, 10);
  227. rollback;
  228. end;
  229.  
  230. -- 3 Д) - модифицирана версия:
  231. -- При добавяне на нов запис в StarsIn, ако новият кортеж указва несъществуващ
  232. -- филм или актьор, да се добавят липсващите данни в съответната таблица
  233. -- (неизвестните данни да бъдат NULL):
  234. create trigger t
  235. on starsin
  236. instead of insert
  237. as
  238. begin
  239. insert into moviestar(name)
  240. select distinct starname
  241. from inserted
  242. where starname not in (select name from moviestar);
  243.  
  244. insert into movie(title, year)
  245. select distinct movietitle, movieyear
  246. from inserted
  247. where not exists (select * from movie
  248. where title = movietitle and YEAR = movieyear);
  249.  
  250. insert into starsin
  251. select *
  252. from inserted;
  253. end;
  254.  
  255. -- 2 Б) Никой производител на компютри не може да произвежда и принтери;
  256. use pc;
  257. create trigger t
  258. on product
  259. after insert, update
  260. as
  261. if exists (select *
  262. from Product p1
  263. join Product p2 on p1.maker = p2.maker
  264. where p1.type = 'PC' and p2.type = 'Printer')
  265. begin
  266. raiserror('...', 16, 10);
  267. rollback;
  268. end;
  269.  
  270. -- 2 Г) При променяне на данните в таблицата Laptop се уверете, че средната
  271. -- цена на лаптопите за всеки производител е поне 2000;
  272. create trigger t
  273. on laptop
  274. after update
  275. as
  276. if exists (select maker
  277. from laptop
  278. join Product on laptop.model = Product.model
  279. group by maker
  280. having AVG(price) < 2000)
  281. begin
  282. raiserror('...', 16, 10);
  283. rollback;
  284. end;
  285.  
  286. -- 2 Д) - по-добре с CHECK
  287.  
  288. -- 3 В) Никой клас не може да има повече от два кораба;
  289. create trigger t
  290. on ships
  291. after insert, update
  292. as
  293. if exists (select class
  294. from ships
  295. group by class
  296. having COUNT(*) > 2)
  297. begin
  298. raiserror('...', 16, 10);
  299. rollback;
  300. end;
  301.  
  302. -- 3 E) прилича на 2 Г) и 3 В)
  303.  
  304. -- 3 Ж) подобно нещо вече направихме за outcomes, но трябва тригер и за battles
  305.  
  306. create trigger t
  307. on outcomes
  308. after insert, update
  309. as
  310. if exists (select *
  311. from outcomes o1
  312. join battles b1 on o1.battle = b1.name
  313. join outcomes o2 on o1.ship = o2.ship
  314. join battles b2 on o2.battle = b2.name
  315. where o1.result = 'sunk'
  316. and b1.date < b2.date)
  317. begin
  318. raiserror('...', 16, 10);
  319. rollback;
  320. end;
  321. -- същият тригер и за battles, но само за update
  322.  
  323. -- примерни теоретични въпроси...
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement