kish-dev

instead of insert

Apr 23rd, 2022 (edited)
447
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PL/SQL 11.26 KB | None | 0 0
  1. CREATE TABLE stables
  2. (
  3.     id      BIGSERIAL,
  4.     name    TEXT NOT NULL,
  5.     motor   TEXT NOT NULL,
  6.     country TEXT NOT NULL,
  7.     rubber  TEXT NOT NULL,
  8.  
  9.     PRIMARY KEY (id)
  10. );
  11.  
  12. CREATE TABLE stages
  13. (
  14.     id         BIGSERIAL,
  15.     attendance INT  NOT NULL,
  16.     country    TEXT NOT NULL,
  17.     name       TEXT NOT NULL,
  18.     lap_length INT  NOT NULL,
  19.     DATE       DATE NOT NULL,
  20.  
  21.     PRIMARY KEY (id),
  22.     CHECK ( lap_length >= 1)
  23. );
  24.  
  25. CREATE TABLE results
  26. (
  27.     id             BIGSERIAL,
  28.     stable_id      BIGINT,
  29.     stage_id       BIGINT,
  30.     laps_count     INT      NOT NULL,
  31.     pilot_name     TEXT     NOT NULL,
  32.     race_time      INTERVAL NOT NULL,
  33.     pit_stop_count INT      NOT NULL,
  34.     place          INT      NOT NULL,
  35.  
  36.     PRIMARY KEY (id),
  37.     FOREIGN KEY (stable_id) REFERENCES stables (id),
  38.     FOREIGN KEY (stage_id) REFERENCES stages (id),
  39.     CHECK ( pit_stop_count >= 0 ),
  40.     CHECK ( place >= 1 ),
  41.     CHECK ( laps_count >= 1 )
  42. );
  43.  
  44. INSERT INTO stables(id, name, motor, country, rubber)
  45. VALUES (1, 'Ferrari', 'Ferrari', 'Italy', 'Pirelli'),
  46.        (2, 'Mercedes-Benz', 'Mercedes-AMG F1 M11 EQ', 'Germany', 'Michelin'),
  47.        (3, 'ASTON MARTIN RED BULL RACING', 'Honda', 'Great Britain', 'Michelin'),
  48.        (4, 'MCLAREN F1 TEAM', 'Renault', 'England', 'Michelin'),
  49.        (5, 'RENAULT DP WORLD F1 TEAM', 'Renault', 'French', 'Michelin'),
  50.        (6, 'SCUDERIA ALPHATAURI HONDA', 'Honda', 'Japan', 'Michelin'),
  51.        (7, 'BWT RACING POINT F1 TEAM', 'Mercedes', 'Germany', 'Michelin'),
  52.        (8, 'ALFA ROMEO RACING', 'Ferrari', 'Italy', 'Pirelli'),
  53.        (9, 'WILLIAMS RACING', 'Mercedes', 'Germany', 'Michelin'),
  54.        (10, 'HAAS F1 TEAM', 'Ferrari', 'Italy', 'Michelin');
  55.  
  56. ALTER SEQUENCE stables_id_seq restart WITH 11;
  57.  
  58. INSERT INTO stables(name)
  59. VALUES ('Ferrari');
  60.  
  61.  
  62. INSERT INTO stages(id, attendance, country, name, lap_length, DATE)
  63. VALUES (1, 15000, 'Germany', 'Germany-grand-prix', 5689, '2003-09-28'),
  64.        (2, 16000, 'Italy', 'Germany-grand-prix', 6451, '2003-10-28'),
  65.        (3, 17000, 'Spain', 'Spain-grand-prix', 3957, '2003-11-28'),
  66.        (4, 18000, 'Russia', 'Russia-grand-prix', 2805, '2003-12-28'),
  67.        (5, 19000, 'Monaco', 'Monaco-grand-prix', 2581, '2004-01-28'),
  68.        (6, 20000, 'Great Britain', 'Great Britain-grand-prix', 8321, '2004-02-28'),
  69.        (7, 21000, 'France', 'France-grand-prix', 2500, '2004-03-28'),
  70.        (8, 22000, 'Poland', 'Poland-grand-prix', 2483, '2004-04-28'),
  71.        (9, 23000, 'Portugal', 'Portugal-grand-prix', 8391, '2004-05-28'),
  72.        (10, 24000, 'Germany', 'Germany-grand-prix', 5689, '2004-09-28');
  73.  
  74. ALTER SEQUENCE stages_id_seq restart WITH 11;
  75.  
  76.  
  77. INSERT INTO results(id, stable_id, stage_id, laps_count, pilot_name, race_time, pit_stop_count, place)
  78. VALUES (1, 1, 1, 50, 'Lewis', '3:12:5', 2, 1),
  79.        (2, 2, 1, 50, 'Ferrari', '3:18:5', 3, 2),
  80.        (3, 3, 1, 50, 'Rock', '3:23:5', 3, 3),
  81.        (4, 2, 2, 70, 'Ferrari', '4:18:5', 2, 1),
  82.        (5, 5, 2, 70, 'Mock', '5:18:5', 3, 2),
  83.        (6, 6, 2, 70, 'Loki', '6:18:5', 3, 3),
  84.        (7, 7, 3, 30, 'Qwerty', '2:08:5', 3, 1),
  85.        (8, 8, 3, 30, 'Bull', '2:18:5', 3, 2),
  86.        (9, 9, 3, 30, 'Rico', '3:18:5', 3, 3),
  87.        (10, 10, 4, 30, 'Bea', '4:18:5', 3, 5),
  88.        (11, 1, 5, 30, 'Nita', '5:18:5', 3, 7),
  89.        (12, 2, 6, 30, 'Colt', '4:12:5', 3, 3),
  90.        (13, 3, 7, 30, 'Fang', '5:12:5', 3, 6),
  91.        (14, 4, 8, 80, 'Sprout', '6:12:5', 3, 1),
  92.        (15, 5, 9, 80, 'Spike', '7:12:5', 3, 2);
  93.  
  94. ALTER SEQUENCE results_id_seq restart WITH 16;
  95.  
  96.  
  97. -- SELECT Section
  98.  
  99. -- 1 Вывести всех чемпионов разных гран-при
  100. SELECT r.pilot_name, r.race_time
  101. FROM results AS r
  102. WHERE r.place = 1;
  103.  
  104.  
  105. -- 2 Вывести все конюшни, по определённым местам
  106. SELECT s.name, s.country, r.place
  107. FROM stables AS s
  108.          JOIN results r ON s.id = r.stable_id
  109. WHERE r.place <= ?
  110. ORDER BY r.place;
  111.  
  112. -- 3 Вывести среднюю скорость гонщиков
  113. SELECT r.pilot_name,
  114.        ((s.lap_length * r.laps_count) / 1000::FLOAT / (SELECT EXTRACT(epoch FROM r.race_time) / 3600)) AS speed
  115. FROM results AS r
  116.          JOIN stages s ON r.stage_id = s.id
  117. ORDER BY speed DESC;
  118.  
  119.  
  120. -- DELETE/UPDATE Section
  121. -- 1 Удалить конюшни
  122.  
  123.  
  124. DELETE
  125. FROM results USING stables
  126. WHERE stables.id = results.stable_id
  127.   AND stables.name = ?;
  128.  
  129. DELETE
  130. FROM stables
  131. WHERE stables.name = ?;
  132.  
  133. SELECT *
  134. FROM results;
  135.  
  136. SELECT *
  137. FROM stables;
  138.  
  139. -- 2 Добавить конюшни
  140.  
  141. UPDATE stables
  142. SET motor = ?
  143. WHERE name = ?;
  144.  
  145. -- 3 Обновить результаты гонок
  146. UPDATE results
  147. SET place = ?
  148. WHERE pilot_name = ?;
  149.  
  150.  
  151. -- Использование оконных функций
  152. -- Подсчитать средннее место конющни
  153. SELECT s.name, place, AVG(place) OVER (PARTITION BY stable_id) AS FIRST
  154. FROM results
  155.          JOIN stables s ON results.stable_id = s.id
  156.  
  157.  
  158. SELECT *
  159. FROM results
  160. WHERE stage_id = 3;
  161.  
  162. -- Запрос который использует таблицу и алиас к этой таблице
  163. -- Найти все пары автомобилей, которые заняли первые и вторые места
  164. SELECT DISTINCT r1.place,
  165.                 r1.stable_id,
  166.                 r1.stage_id,
  167.                 r1.race_time,
  168.                 r1.pilot_name,
  169.                 r2.place,
  170.                 r2.stable_id,
  171.                 r2.stage_id,
  172.                 r2.race_time,
  173.                 r2.pilot_name
  174. FROM results AS r1,
  175.      results AS r2
  176. WHERE (r1.place = 2
  177.     AND r2.place = 1)
  178.     AND r1.stage_id = r2.stage_id
  179.     AND r1.id != r2.id;
  180. --     and r1.stage_id > 2 and r2.stage_id > 2;
  181.  
  182. SET role admin;
  183.  
  184.  
  185. -- 1.4
  186. -- Грязного чтения нет
  187. BEGIN ISOLATION LEVEL READ COMMITTED;
  188.  
  189. SELECT COUNT(id)
  190. FROM results;
  191.  
  192. SELECT COUNT(id)
  193. FROM results;
  194. COMMIT;
  195.  
  196. -- Неповторяющее чтение есть
  197. BEGIN ISOLATION LEVEL READ COMMITTED;
  198.  
  199. SELECT pilot_name
  200. FROM results
  201. WHERE id = 1;
  202.  
  203. SELECT pilot_name
  204. FROM results
  205. WHERE id = 1;
  206.  
  207. COMMIT;
  208.  
  209.  
  210. -- Фантомы есть
  211. BEGIN ISOLATION LEVEL READ COMMITTED;
  212.  
  213. SELECT COUNT(id)
  214. FROM results;
  215.  
  216. SELECT COUNT(id)
  217. FROM results;
  218.  
  219. COMMIT;
  220.  
  221. -- Неповторяемого чтения нет
  222. BEGIN ISOLATION LEVEL REPEATABLE READ;
  223.  
  224. SELECT pilot_name
  225. FROM results
  226. WHERE id = 1;
  227.  
  228. SELECT pilot_name
  229. FROM results
  230. WHERE id = 1;
  231.  
  232. COMMIT;
  233.  
  234. -- Фантомов нет
  235. BEGIN ISOLATION LEVEL REPEATABLE READ;
  236.  
  237. SELECT COUNT(id)
  238. FROM results;
  239.  
  240. SELECT COUNT(id)
  241. FROM results;
  242.  
  243. COMMIT;
  244.  
  245. BEGIN ISOLATION LEVEL REPEATABLE READ;
  246.  
  247. INSERT INTO results(stable_id, stage_id, laps_count, pilot_name, race_time, pit_stop_count, place)
  248. VALUES (3, 6, (SELECT COUNT(id)
  249.                FROM results
  250.                WHERE pilot_name = 'First'), 'Lewis', '3:12:5', 2, 1);
  251.  
  252. COMMIT;
  253.  
  254. -- Фантомов нет
  255. BEGIN ISOLATION LEVEL SERIALIZABLE;
  256.  
  257. SELECT COUNT(id)
  258. FROM results;
  259.  
  260. SELECT COUNT(id)
  261. FROM results;
  262.  
  263. COMMIT;
  264.  
  265. --Аномалии сериализации нет
  266. BEGIN ISOLATION LEVEL SERIALIZABLE;
  267.  
  268. INSERT INTO results(stable_id, stage_id, laps_count, pilot_name, race_time, pit_stop_count, place)
  269. VALUES (5, 5, (SELECT COUNT(id)
  270.                FROM results
  271.                WHERE pilot_name = 'Lewis'), 'First', '3:12:5', 2, 1);
  272.  
  273. COMMIT;
  274. -- DROP TABLE results;
  275. --
  276. -- DROP TABLE stables;
  277. -- DROP TABLE stages;
  278.  
  279. -- Триггер на pilot_name, stable_id и stage_id гонщика
  280.  
  281. CREATE OR REPLACE FUNCTION control_repetition()
  282.     RETURNS TRIGGER
  283.     LANGUAGE plpgsql
  284. AS
  285. $$
  286. BEGIN
  287.     IF NOT EXISTS(SELECT *
  288.                   FROM results
  289.                   WHERE stage_id = NEW.stage_id
  290.                     AND stable_id = NEW.stable_id
  291.                     AND pilot_name = NEW.pilot_name) THEN
  292.     ELSE
  293.  
  294.         BEGIN
  295.             RAISE EXCEPTION 'Отмена добавления результата: гонщик не может проехать за одну и ту же конюшню'
  296.                 'дважды один и тот же этап гонки';
  297.         END;
  298.     END IF;
  299.     RETURN NEW;
  300. END;
  301. $$;
  302.  
  303.  
  304. DROP FUNCTION control_repetition();
  305. DROP TRIGGER res_ins_trigger ON results;
  306.  
  307. CREATE TRIGGER res_ins_trigger
  308.     BEFORE INSERT
  309.     ON results
  310.     FOR EACH ROW
  311.     WHEN (pg_trigger_depth() < 1)
  312. EXECUTE PROCEDURE control_repetition();
  313.  
  314. SELECT *
  315. FROM results;
  316.  
  317. INSERT INTO results(stable_id, stage_id, laps_count, pilot_name, race_time, pit_stop_count, place)
  318. VALUES (2, 3, 50, 'Andrey', '3:12:5', 2, 1);
  319.  
  320.  
  321. grant SELECT, UPDATE, INSERT ON results TO another_user;
  322.  
  323. grant SELECT (name), UPDATE (motor) ON stables TO another_user;
  324.  
  325. grant INSERT (name), INSERT(id) ON stables TO another_user;
  326.  
  327. grant SELECT ON stages TO another_user;
  328.  
  329. CREATE VIEW stables_name_view AS
  330. SELECT name
  331. FROM stables;
  332.  
  333. SET role another_user;
  334. SET role admin;
  335. INSERT INTO stables_name_view
  336. VALUES ('ofc');
  337.  
  338.  
  339.  
  340. SELECT *
  341. FROM stables;
  342.  
  343. ALTER TABLE stables
  344.     ALTER COLUMN name SET DEFAULT '';
  345.  
  346. ALTER TABLE stables
  347.     ALTER COLUMN motor SET DEFAULT '';
  348.  
  349. ALTER TABLE stables
  350.     ALTER COLUMN country SET DEFAULT '';
  351.  
  352. ALTER TABLE stables
  353.     ALTER COLUMN rubber SET DEFAULT '';
  354.  
  355.  
  356. SET role admin;
  357.  
  358. CREATE TRIGGER stables_name_view_insert
  359.     INSTEAD OF INSERT
  360.     ON stables_name_view
  361.     FOR EACH ROW
  362. EXECUTE FUNCTION view_insert_row();
  363.  
  364. CREATE OR REPLACE FUNCTION view_insert_row()
  365.     RETURNS TRIGGER
  366.     LANGUAGE plpgsql
  367. AS
  368. $$
  369. BEGIN
  370.    INSERT INTO stables(name)
  371.     VALUES (NEW.name);
  372.     RETURN NEW;
  373. END;
  374. $$;
  375.  
  376. -- Собственная реализация вставки instead of insert на view, пустыми text заполнить not null поля
  377. -- Убрать ненужные пары alias
  378.  
  379. grant SELECT ON stables_name_view TO another_user;
  380.  
  381. -- Циклы, ветвления, переменные
  382. CREATE OR REPLACE FUNCTION get_all_first_places(name text) RETURNS int AS
  383. $BODY$
  384. DECLARE
  385.     r                      results % ROWTYPE;
  386.     namesakes_first_places int = 0;
  387. BEGIN
  388.     FOR r IN
  389.         SELECT * FROM results WHERE place = 1
  390.         LOOP
  391.             IF r.pilot_name = name
  392.             THEN
  393.                 namesakes_first_places = namesakes_first_places + 1;
  394.             END IF;
  395.         END LOOP;
  396.     RETURN namesakes_first_places;
  397. END;
  398.  
  399.  
  400. $BODY$
  401.     LANGUAGE plpgsql;
  402.  
  403. SELECT *
  404. FROM results
  405. WHERE place = 1;
  406.  
  407. SELECT *
  408. FROM get_all_first_places('Andrey');
  409.  
  410. -- Курсоры, исключения
  411. CREATE OR REPLACE FUNCTION find_first_or_raise_pilot_with_current_place(input_place int) RETURNS text AS
  412. $BODY$
  413. DECLARE
  414.     r    results % ROWTYPE;
  415.     cursor_place CURSOR FOR SELECT *
  416.                             FROM results
  417.                             WHERE place = input_place;
  418.     name text;
  419. BEGIN
  420.     OPEN cursor_place;
  421.     LOOP
  422.         FETCH cursor_place INTO r;
  423.  
  424.         IF r.pilot_name IS NULL THEN
  425.             CLOSE cursor_place;
  426.             RAISE EXCEPTION 'Нет пилота с выбранным местом';
  427.         ELSE
  428.             CLOSE cursor_place;
  429.             name = r.pilot_name;
  430.             RETURN name;
  431.  
  432.         END IF;
  433.     END LOOP;
  434. END ;
  435.  
  436.  
  437. $BODY$
  438.     LANGUAGE plpgsql;
  439.  
  440. SELECT *
  441. FROM find_first_or_raise_pilot_with_current_place(7);
  442.  
  443. SELECT *
  444. FROM results
  445. WHERE place = 7;
Add Comment
Please, Sign In to add comment