DatabaseCreation: DDL.sql

File DDL.sql, 68.7 KB (added by 231511, 27 hours ago)

Full ddl with inserts and views togetehr

Line 
1CREATE TABLE Status_Types (
2 status_id BIGSERIAL PRIMARY KEY,
3 status_name varchar(50) NOT NULL,
4 type varchar(50) NOT NULL,
5 CONSTRAINT uniques_status_per_type UNIQUE (status_name,type)
6);
7
8CREATE TABLE Categories (
9 category_id BIGSERIAL PRIMARY KEY,
10 name varchar(100) NOT NULL UNIQUE,
11 description_category text
12);
13
14CREATE TABLE Site_Types (
15 site_type_id BIGSERIAL PRIMARY KEY,
16 name VARCHAR(50) UNIQUE NOT NULL
17);
18
19CREATE TABLE Regions (
20 region_id BIGSERIAL PRIMARY KEY,
21 name VARCHAR(50) UNIQUE NOT NULL
22);
23
24CREATE TABLE Protection_Status (
25 protection_status_id BIGSERIAL PRIMARY KEY,
26 name VARCHAR(50) UNIQUE NOT NULL
27);
28
29CREATE TABLE Roles (
30 role_id BIGSERIAL PRIMARY KEY,
31 role_name varchar(20) NOT NULL UNIQUE
32);
33
34CREATE TABLE Materials (
35 material_id BIGSERIAL PRIMARY KEY,
36 name varchar(50) NOT NULL UNIQUE,
37 description_materials text
38);
39
40CREATE TABLE Municipalities (
41 municipality_id BIGSERIAL PRIMARY KEY,
42 name VARCHAR(100) UNIQUE NOT NULL
43);
44
45CREATE TABLE Sites (
46 site_id BIGSERIAL PRIMARY KEY,
47 site_name varchar(100) NOT NULL,
48 site_type_id BIGINT NOT NULL,
49 region_id BIGINT NOT NULL,
50 protection_status_id BIGINT NOT NULL,
51 latitude decimal(9, 6) NOT NULL,
52 longitude decimal(9, 6) NOT NULL,
53 altitude decimal(7, 2),
54 discovery_year int NOT NULL,
55 description text,
56 created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
57 is_active boolean DEFAULT true,
58 municipality_id BIGINT,
59 CONSTRAINT check_macedonia_coords
60 CHECK (latitude BETWEEN 40.0 AND 43.0 AND longitude BETWEEN 20.0 AND 24.0),
61 CONSTRAINT fk_site_type
62 FOREIGN KEY (site_type_id)
63 REFERENCES Site_Types(site_type_id),
64 CONSTRAINT fk_region
65 FOREIGN KEY (region_id)
66 REFERENCES Regions(region_id),
67 CONSTRAINT fk_protection
68 FOREIGN KEY (protection_status_id)
69 REFERENCES Protection_Status(protection_status_id),
70 CONSTRAINT fk_site_municipality
71 FOREIGN KEY (municipality_id)
72 REFERENCES Municipalities(municipality_id),
73 CONSTRAINT unique_site_name_region UNIQUE (site_name,region_id)
74);
75
76CREATE TABLE Culture (
77 culture_id BIGSERIAL PRIMARY KEY,
78 name varchar(100) NOT NULL UNIQUE,
79 origin_region_id BIGINT NOT NULL,
80 description text,
81 period_from_year int,
82 period_to_year int,
83 CHECK (
84 period_from_year IS NOT NULL AND
85 (period_to_year IS NULL OR period_to_year >= period_from_year)),
86 CONSTRAINT fk_culture_region FOREIGN KEY ( origin_region_id)
87 REFERENCES Regions(region_id)
88 ON DELETE RESTRICT ON UPDATE CASCADE
89);
90
91CREATE TABLE Institutions (
92 institution_id BIGSERIAL PRIMARY KEY,
93 name varchar(100) NOT NULL UNIQUE,
94 address text,
95 city varchar(50)
96);
97
98CREATE TABLE Users (
99 user_id BIGSERIAL PRIMARY KEY,
100 username varchar(30) NOT NULL UNIQUE,
101 full_name varchar(50) NOT NULL,
102 email varchar(100) NOT NULL UNIQUE
103 CHECK (email ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'),
104 password_hash varchar(255) NOT NULL,
105 role_id BIGINT NOT NULL,
106 CONSTRAINT fk_user_role FOREIGN KEY (role_id)
107 REFERENCES Roles(role_id)
108 ON DELETE RESTRICT ON UPDATE CASCADE
109);
110
111CREATE TABLE User_Details (
112 user_id BIGINT PRIMARY KEY,
113 institution_id BIGINT,
114 specialization VARCHAR(100),
115
116 CONSTRAINT fk_ud_user FOREIGN KEY (user_id)
117 REFERENCES Users(user_id)
118 ON DELETE CASCADE,
119
120 CONSTRAINT fk_ud_inst FOREIGN KEY (institution_id)
121 REFERENCES Institutions(institution_id)
122 ON DELETE SET NULL
123);
124
125CREATE TABLE Exhibitions (
126 exhibition_id BIGSERIAL PRIMARY KEY,
127 start_date date NOT NULL,
128 end_date date,
129 name varchar(100) NOT NULL,
130 location_institution_id BIGINT,
131 CONSTRAINT fk_exh_objex FOREIGN KEY (location_institution_id)
132 REFERENCES Institutions(institution_id)
133 ON DELETE SET NULL ON UPDATE CASCADE,
134 CONSTRAINT chk_exhibition_dates
135 CHECK (end_date IS NULL OR end_date >= start_date)
136);
137
138CREATE TABLE Authors (
139 author_id BIGSERIAL PRIMARY KEY,
140 full_name VARCHAR(150) NOT NULL
141);
142
143CREATE TABLE Publications (
144 publication_id BIGSERIAL PRIMARY KEY,
145 request_date date NOT NULL,
146 main_author_id BIGINT,
147 title varchar(255) NOT NULL,
148 status_id BIGINT NOT NULL,
149 publisher_location varchar(50),
150 CONSTRAINT fk_pub_status FOREIGN KEY (status_id)
151 REFERENCES Status_Types(status_id)
152 ON DELETE RESTRICT ON UPDATE CASCADE,
153 CONSTRAINT fk_pub_main_author FOREIGN KEY (main_author_id)
154 REFERENCES Authors(author_id)
155 ON DELETE SET NULL ON UPDATE cascade
156);
157
158
159CREATE TABLE Publication_Authors (
160 publication_id BIGINT NOT NULL,
161 author_id BIGINT NOT NULL,
162
163 PRIMARY KEY (publication_id, author_id),
164
165 CONSTRAINT fk_pa_pub FOREIGN KEY (publication_id)
166 REFERENCES Publications(publication_id)
167 ON DELETE CASCADE,
168
169 CONSTRAINT fk_pa_author FOREIGN KEY (author_id)
170 REFERENCES Authors(author_id)
171 ON DELETE CASCADE
172);
173CREATE TABLE Objects (
174 object_id BIGSERIAL PRIMARY KEY,
175 inventory_number varchar(50) UNIQUE NOT NULL,
176 title varchar(150) NOT NULL,
177 creation_year INT,
178 acquisition_date date,
179 description text,
180 current_status_id BIGINT NOT NULL,
181 site_id BIGINT NOT NULL,
182 found_by_user_id BIGINT,
183 CONSTRAINT fk_obj_site FOREIGN KEY (site_id)
184 REFERENCES Sites(site_id)
185 ON DELETE RESTRICT ON UPDATE CASCADE,
186 CONSTRAINT fk_obj_user FOREIGN KEY (found_by_user_id)
187 REFERENCES Users(user_id)
188 ON DELETE SET NULL ON UPDATE CASCADE,
189 CONSTRAINT chk_creation_year
190 CHECK (creation_year IS NULL OR creation_year <= EXTRACT(YEAR FROM CURRENT_DATE)),
191 CONSTRAINT fk_obj_status FOREIGN KEY (current_status_id)
192 REFERENCES Status_Types(status_id)
193 ON DELETE SET NULL ON UPDATE CASCADE
194);
195
196CREATE TABLE Treatments (
197 treatment_id BIGSERIAL PRIMARY KEY,
198 object_id BIGINT NOT null,
199 treatment_date DATE,
200 description TEXT,
201 CONSTRAINT fk_treatment_obj
202 FOREIGN KEY (object_id)
203 REFERENCES Objects(object_id)
204 ON DELETE CASCADE ON UPDATE CASCADE
205);
206
207CREATE TABLE Conservation_Projects (
208 project_id BIGSERIAL,
209 project_name varchar(150) NOT NULL,
210 start_date date NOT NULL,
211 end_date date,
212 budget decimal(15, 2),
213 description_project text,
214 institution_id BIGINT NOT NULL,
215 object_id BIGINT NOT NULL,
216 PRIMARY KEY (project_id),
217 CONSTRAINT unique_proj_obj UNIQUE (object_id,project_name),
218 CONSTRAINT fk_proj_inst FOREIGN KEY (institution_id)
219 REFERENCES Institutions(institution_id)
220 ON DELETE RESTRICT ON UPDATE CASCADE,
221 CONSTRAINT chk_proj_dates
222 CHECK (end_date IS NULL OR end_date >= start_date),
223 CONSTRAINT fk_proj_obj FOREIGN KEY (object_id)
224 REFERENCES Objects(object_id)
225 ON DELETE RESTRICT ON UPDATE CASCADE
226);
227
228CREATE TABLE Researcher_Access (
229 access_id BIGSERIAL PRIMARY KEY,
230 access_date date NOT NULL,
231 access_status_id BIGINT NOT NULL,
232 user_id BIGINT NOT NULL,
233 object_id BIGINT NOT NULL,
234 institution_id BIGINT NOT NULL,
235 conservation_project_id BIGINT, -- NOTE: conservation_project_id must refer to the same object_id
236 CONSTRAINT fk_ra_user FOREIGN KEY (user_id)
237 REFERENCES Users(user_id)
238 ON DELETE CASCADE ON UPDATE CASCADE,
239 CONSTRAINT fk_ra_obj FOREIGN KEY (object_id)
240 REFERENCES Objects(object_id)
241 ON DELETE RESTRICT ON UPDATE CASCADE,
242 CONSTRAINT fk_ra_inst FOREIGN KEY (institution_id)
243 REFERENCES Institutions(institution_id)
244 ON DELETE RESTRICT ON UPDATE CASCADE,
245 CONSTRAINT fk_ra_proj FOREIGN KEY (conservation_project_id)
246 REFERENCES Conservation_Projects(project_id)
247 ON DELETE SET NULL ON UPDATE CASCADE,
248 CONSTRAINT fk_ra_status FOREIGN KEY (access_status_id)
249 REFERENCES Status_Types(status_id)
250 ON DELETE RESTRICT ON UPDATE cascade
251);
252
253CREATE TABLE Object_Publication (
254 object_pub_id BIGSERIAL PRIMARY KEY,
255 object_id BIGINT NOT NULL,
256 publication_id BIGINT NOT NULL,
257 page_reference varchar(50),
258 notes text,
259 CONSTRAINT fk_objpub_obj FOREIGN KEY (object_id)
260 REFERENCES Objects(object_id)
261 ON DELETE CASCADE ON UPDATE CASCADE,
262 CONSTRAINT fk_objpub_pub FOREIGN KEY (publication_id)
263 REFERENCES Publications(publication_id)
264 ON DELETE RESTRICT ON UPDATE cascade,
265 CONSTRAINT unique_obj_pub UNIQUE (object_id,publication_id)
266);
267
268CREATE TABLE Object_Classification (
269 classification_id BIGSERIAL PRIMARY KEY,
270 object_id BIGINT NOT NULL,
271 category_id BIGINT NOT NULL,
272 culture_id BIGINT NOT NULL,
273 period_descr varchar(100),
274 style varchar(100),
275 iconography text,
276 CONSTRAINT fk_class_obj FOREIGN KEY (object_id)
277 REFERENCES Objects(object_id)
278 ON DELETE CASCADE ON UPDATE CASCADE,
279 CONSTRAINT fk_class_cat FOREIGN KEY (category_id)
280 REFERENCES Categories(category_id)
281 ON DELETE RESTRICT ON UPDATE CASCADE,
282 CONSTRAINT fk_class_cult FOREIGN KEY (culture_id)
283 REFERENCES Culture(culture_id)
284 ON DELETE RESTRICT ON UPDATE CASCADE
285);
286
287CREATE TABLE Object_Exhibition (
288 object_ex_id BIGSERIAL PRIMARY KEY,
289 object_id BIGINT NOT NULL,
290 exhibition_id BIGINT NOT NULL,
291 UNIQUE (object_id, exhibition_id),
292 CONSTRAINT fk_objex_obj FOREIGN KEY (object_id)
293 REFERENCES Objects(object_id)
294 ON DELETE CASCADE ON UPDATE CASCADE,
295 CONSTRAINT fk_objex_exh FOREIGN KEY (exhibition_id)
296 REFERENCES Exhibitions(exhibition_id)
297 ON DELETE CASCADE ON UPDATE CASCADE
298);
299
300CREATE TABLE Treatment_Step_Log (
301 step_id BIGSERIAL PRIMARY KEY,
302 treatment_id BIGINT NOT NULL,
303 step_number int NOT NULL,
304 step_description varchar(255) NOT NULL,
305 observations text,
306 timestamp_performed timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
307 performed_by_user BIGINT NOT NULL,
308 researcher_access_id BIGINT,
309 CONSTRAINT fk_treat_user FOREIGN KEY (performed_by_user)
310 REFERENCES Users(user_id)
311 ON DELETE RESTRICT ON UPDATE CASCADE,
312 CONSTRAINT fk_treat_ra FOREIGN KEY (researcher_access_id)
313 REFERENCES Researcher_Access(access_id)
314 ON DELETE RESTRICT ON UPDATE CASCADE,
315 CONSTRAINT fk_treat_treatment FOREIGN KEY (treatment_id)
316 REFERENCES Treatments(treatment_id)
317 ON DELETE CASCADE ON UPDATE cascade,
318 CONSTRAINT unique_treatment_step UNIQUE (treatment_id,step_number)
319);
320
321CREATE TABLE Object_Location_History (
322 history_id BIGSERIAL PRIMARY KEY,
323 object_id BIGINT NOT NULL,
324 institution_id BIGINT NOT NULL,
325 start_date DATE NOT NULL,
326 end_date DATE,
327
328 CONSTRAINT fk_olh_obj FOREIGN KEY (object_id)
329 REFERENCES Objects(object_id)
330 ON DELETE CASCADE,
331
332 CONSTRAINT fk_olh_inst FOREIGN KEY (institution_id)
333 REFERENCES Institutions(institution_id)
334 ON DELETE RESTRICT,
335
336 CONSTRAINT chk_olh_dates
337 CHECK (end_date IS NULL OR end_date >= start_date)
338);
339
340CREATE TABLE Condition_Assessment (
341 assessment_id BIGSERIAL PRIMARY KEY,
342 assessment_date date NOT NULL,
343 notes text,
344 object_id BIGINT NOT NULL,
345 status_id BIGINT NOT NULL,
346 CONSTRAINT fk_ca_obj FOREIGN KEY (object_id)
347 REFERENCES Objects(object_id)
348 ON DELETE RESTRICT ON UPDATE CASCADE,
349 CONSTRAINT fk_ca_status FOREIGN KEY (status_id)
350 REFERENCES Status_Types(status_id)
351 ON DELETE RESTRICT ON UPDATE cascade,
352 CONSTRAINT unique_object_assessment_date UNIQUE (object_id,assessment_date)
353);
354
355CREATE TABLE Materials_Objects (
356 object_id BIGINT NOT NULL,
357 material_id BIGINT NOT NULL,
358 PRIMARY KEY (object_id, material_id),
359 CONSTRAINT fk_mo_mat FOREIGN KEY (material_id)
360 REFERENCES Materials(material_id)
361 ON DELETE RESTRICT ON UPDATE CASCADE,
362 CONSTRAINT fk_mo_obj FOREIGN KEY (object_id)
363 REFERENCES Objects(object_id)
364 ON DELETE CASCADE ON UPDATE CASCADE
365);
366
367CREATE TABLE Treatment_Materials (
368 treatment_id BIGINT NOT NULL,
369 material_id BIGINT NOT NULL,
370
371 PRIMARY KEY (treatment_id, material_id),
372
373 CONSTRAINT fk_tm_treatment FOREIGN KEY (treatment_id)
374 REFERENCES Treatments(treatment_id)
375 ON DELETE CASCADE,
376
377 CONSTRAINT fk_tm_material FOREIGN KEY (material_id)
378 REFERENCES Materials(material_id)
379 ON DELETE RESTRICT
380);
381
382CREATE TABLE Fragments (
383 fragment_id BIGSERIAL PRIMARY KEY,
384 found_by_user_id BIGINT,
385 description text,
386 status_id BIGINT,
387 discovery_date date,
388 site_id BIGINT NOT NULL,
389 object_id BIGINT,
390 parent_fragment_id BIGINT,
391 CONSTRAINT fk_frag_site FOREIGN KEY (site_id)
392 REFERENCES Sites(site_id)
393 ON DELETE RESTRICT ON UPDATE CASCADE,
394 CONSTRAINT fk_frag_obj FOREIGN KEY (object_id)
395 REFERENCES Objects(object_id)
396 ON DELETE CASCADE ON UPDATE CASCADE,
397 CONSTRAINT fk_frag_user FOREIGN KEY (found_by_user_id)
398 REFERENCES Users(user_id)
399 ON DELETE SET NULL ON UPDATE CASCADE,
400 CONSTRAINT fk_frag_status FOREIGN KEY (status_id)
401 REFERENCES Status_Types(status_id)
402 ON DELETE RESTRICT ON UPDATE cascade,
403 CONSTRAINT fk_fragment_parent FOREIGN KEY (parent_fragment_id)
404 REFERENCES Fragments(fragment_id)
405 ON DELETE SET null,
406 CONSTRAINT chk_no_self_parent
407 CHECK (parent_fragment_id IS NULL OR parent_fragment_id <> fragment_id),
408 CONSTRAINT chk_fragment_relation
409 CHECK (
410 NOT (object_id IS NOT NULL AND parent_fragment_id IS NOT NULL))
411);
412
413CREATE TABLE Object_Images (
414 image_id BIGSERIAL PRIMARY KEY,
415 image_url varchar(255) NOT NULL,
416 description varchar(150),
417 date_taken date,
418 object_id BIGINT NOT NULL,
419 is_primary BOOLEAN DEFAULT FALSE,
420 CONSTRAINT fk_img_obj FOREIGN KEY (object_id)
421 REFERENCES Objects(object_id)
422 ON DELETE CASCADE ON UPDATE CASCADE
423);
424
425CREATE TABLE Exhibition_Object_Details (
426 exhibition_detail_id BIGSERIAL PRIMARY KEY,
427 display_title varchar(255),
428 exhibition_description text,
429 language varchar(10),
430 object_id BIGINT NOT NULL,
431 exhibition_id BIGINT NOT NULL,
432 CONSTRAINT fk_eod_obj FOREIGN KEY (object_id)
433 REFERENCES Objects(object_id)
434 ON DELETE RESTRICT ON UPDATE CASCADE,
435 CONSTRAINT fk_eod_exh FOREIGN KEY (exhibition_id)
436 REFERENCES Exhibitions(exhibition_id)
437 ON DELETE RESTRICT ON UPDATE cascade,
438 CONSTRAINT unique_eod_obj_exh UNIQUE (object_id,exhibition_id)
439);
440
441CREATE INDEX idx_objects_site ON Objects(site_id);
442CREATE INDEX idx_sites_type_id ON Sites(site_type_id);
443CREATE INDEX idx_fragments_object ON Fragments(object_id);
444
445
446-- ФУНКЦИЈА 1: UPDATE
447CREATE OR REPLACE FUNCTION update_object_title(
448 obj_id BIGINT,
449 new_title VARCHAR(150)
450)
451RETURNS VOID AS $$
452BEGIN
453 IF new_title IS NULL OR LENGTH(TRIM(new_title)) = 0 THEN
454 RAISE EXCEPTION 'Насловот не смее да биде празен.';
455 END IF;
456
457 UPDATE Objects
458 SET title = new_title
459 WHERE object_id = obj_id;
460
461 IF NOT FOUND THEN
462 RAISE EXCEPTION 'Објект со ID % не е пронајден.', obj_id;
463 END IF;
464END;
465$$ LANGUAGE plpgsql;
466
467-- ФУНКЦИЈА 2: INSERT
468CREATE OR REPLACE FUNCTION add_site(
469 p_name VARCHAR,
470 p_site_type_id BIGINT,
471 p_region_id BIGINT,
472 p_year INT,
473 p_protection_status_id BIGINT,
474 p_latitude decimal(9,6),
475 p_longitude decimal(9,6),
476 p_municipality_id BIGINT,
477 p_description VARCHAR DEFAULT NULL
478)
479RETURNS VOID AS $$
480BEGIN
481 INSERT INTO Sites(
482 site_name,
483 site_type_id,
484 region_id,
485 discovery_year,
486 protection_status_id,
487 latitude,
488 longitude,
489 municipality_id,
490 description
491 )
492 VALUES (
493 p_name,
494 p_site_type_id,
495 p_region_id,
496 p_year,
497 p_protection_status_id,
498 p_latitude,
499 p_longitude,
500 p_municipality_id,
501 p_description
502 );
503END;
504$$ LANGUAGE plpgsql;
505
506
507
508SET synchronous_commit = OFF;
509
510INSERT INTO Regions (name) VALUES
511('Скопски'), ('Пелагониски'), ('Вардарски'), ('Источен'),
512('Североисточен'), ('Југозападен'), ('Полошки'), ('Југоисточен');
513
514INSERT INTO Site_Types (name) VALUES
515('Антички локалитет'), ('Опсерваторија'),
516('Средновековен локалитет'), ('Археолошки парк'),('Тумба (Неолитска населба)'),('Наколна населба'),
517('Мегалитска опсерваторија'),('Антички град'),('Некропола'),('Римски терми'),('Аквадукт'),('Вила Рустика'),
518('Тврдина (Кале)'),('Ранохристијанска базилика'),('Средновековен манастир'),('Антички рудник');
519
520INSERT INTO Protection_Status (name) VALUES
521('Заштитен'), ('Делумно заштитен'), ('Незаштитен');
522SELECT * FROM Protection_Status;
523
524INSERT INTO Roles (role_name) VALUES
525('Admin'), ('Researcher'), ('Conservator'), ('Visitor');
526
527INSERT INTO Status_Types (status_name, type) VALUES
528('Изложен', 'object'),
529('Депониран', 'object'),
530('На конзервација', 'object'),
531('Објавено', 'publication'),
532('Во подготовка', 'publication'),
533('Одобрено', 'access'),
534('Во обработка', 'access'),
535('Одбиено', 'access');
536
537INSERT INTO Materials (name) VALUES
538('Керамика'), ('Бронза'), ('Железо'),
539('Камен'), ('Стакло'), ('Злато'),
540('Сребро'), ('Коска'), ('Дрво');
541
542UPDATE Materials
543SET description_materials = CASE
544 WHEN material_id % 4 = 0 THEN 'Природен материјал со широка употреба во изработка на предмети.'
545 WHEN material_id % 4 = 1 THEN 'Често користен материјал во традиционални и модерни техники.'
546 WHEN material_id % 4 = 2 THEN 'Материјал со специфични физички и хемиски својства.'
547 ELSE 'Историски значаен материјал со културна вредност.'
548END;
549
550INSERT INTO Categories (name, description_category) VALUES
551('Орудија и оружје', 'Предмети користени за работа, лов и војување, изработени од камен, коска или метал.'),
552('Накит', 'Декоративни предмети (фибули, обетки, прстени) изработени од злато, сребро, бронза или стакло.'),
553('Садови и керамика', 'Предмети за секојдневна употреба, складирање храна (амфори, питоси) и обредни цели.'),
554('Монети', 'Метални парични единици од различни периоди (пајонски, македонски, римски, византиски).'),
555('Скулптури и пластика', 'Уметнички дела од мермер, камен или бронза, вклучувајќи статуи, бисти и релјефи.'),
556('Теракотни предмети', 'Предмети од печена земја, вклучувајќи ги уникатните Винички икони и фигурини.'),
557('Епиграфски споменици', 'Камени натписи, надгробни стели и почесни плочи со историски записи.'),
558('Мозаици', 'Подни и ѕидни декорации изработени од мали камчиња (тесери), карактеристични за базиликите.'),
559('Архитектонски елементи', 'Делови од градби како капители, столбови и мермерни прагови.'),
560('Опрема за секојдневие', 'Светилки (луцерни), коскени игли, огледала и други предмети за домаќинството.');
561
562ALTER TABLE Categories
563ALTER COLUMN description_category SET DEFAULT 'Нема опис';
564
565
566INSERT INTO Municipalities (name) VALUES
567('Скопје'), ('Битола'), ('Охрид'), ('Виница'),('Штип'),('Кавадарци'),('Прилеп'), ('Гевгелија'), ('Струмица'), ('Куманово');
568
569INSERT INTO Institutions (name, address,city) VALUES
570('Археолошки музеј на Македонија', 'Кеј Димитар Влахов бб', 'Скопје'),
571('Музеј на Македонија', 'Куршумли Ан бб', 'Скопје'), -- Ова е националниот музеј во Старата Чаршија
572('Музеј на град Скопје', 'Улица Македонија бб', 'Скопје'),
573('Меморијален центар на Холокаустот на Евреите од Македонија', 'Улица Тетовска бб', 'Скопје'),
574('Природонаучен музеј на Македонија', 'Булевар Илинден 86', 'Скопје'),
575
576('НУ Завод и музеј Битола', 'Улица Климент Охридски бб', 'Битола'),
577('НУ Завод и музеј Прилеп', 'Улица Александар Македонски 142', 'Прилеп'),
578('НУ Завод и музеј Охрид', 'Улица Цар Самоил 62', 'Охрид'), -- Куќата на Робевци
579('Национален парк Галичица - Музејски центар', 'Улица Наум Охридски 124', 'Охрид'),
580('НУ Завод и музеј Струга', 'Улица Партизанска бб', 'Струга'),
581
582('НУ Завод и музеј Струмица', 'Улица 27-ми Март бб', 'Струмица'),
583('НУ Завод и музеј Штип', 'Улица Тошо Арсов 10', 'Штип'),
584('Народен музеј Велес', 'Улица 8-ми Септември бб', 'Велес'),
585('НУ Музеј на град Гевгелија', 'Улица Маршал Тито бб', 'Гевгелија'),
586('НУ Музеј Радовиш', 'Улица 22-ри Октомври бб', 'Радовиш'),
587('НУ Музеј на град Кочани', 'Улица Маршал Тито бб', 'Кочани'),
588
589('НУ Музеј Куманово', 'Улица 11-ти Октомври бб', 'Куманово'),
590('Музеј на Тетовскиот крај', 'Улица Иво Лола Рибар бб', 'Тетово'),
591('Музеј на град Кратово', 'Улица Гоце Делчев бб', 'Кратово'),
592('Музеј "Западна Македонија во НОВ"', 'Улица Ослободување бб', 'Кичево'),
593('Музеј на град Дебар', 'Улица 8-ми Септември бб', 'Дебар');
594
595
596WITH first_names AS (
597 SELECT ARRAY['Ivan','Ana','Marko','Elena','Stefan','Marija'] AS fn_arr
598),
599last_names AS (
600 SELECT ARRAY['Petrov','Stojanovska','Trajkov','Dimitrova','Nikolov','Ivanova'] AS ln_arr
601)
602INSERT INTO Users (username, full_name, email, password_hash, role_id)
603SELECT
604 'user_' || i,
605 fn_arr[ceil(random()*array_length(fn_arr,1))] || ' ' ||
606 ln_arr[ceil(random()*array_length(ln_arr,1))],
607 'user' || i || '@mail.com',
608 'pass',
609 floor(random()*4 + 1)
610FROM generate_series(1, 2000) s(i), first_names, last_names;
611
612
613INSERT INTO User_Details (user_id,institution_id,specialization)
614SELECT
615 user_id,
616 floor(random()*21+1),
617 CASE floor(random()*7)
618 WHEN 0 THEN 'Aрхеологија'
619 WHEN 1 THEN 'Конзервација'
620 WHEN 2 THEN 'Нумизматика'
621 WHEN 3 THEN 'Етнологија'
622 WHEN 4 THEN 'Историја на уметност'
623 WHEN 5 THEN 'Подводна археологија'
624 WHEN 6 THEN 'Емиграфика'
625 END
626 FROM Users u
627 JOIN Roles r ON u.role_id=r.role_id
628 WHERE r.role_name != 'Visitor';
629
630INSERT INTO Sites(site_name,site_type_id,region_id,
631 protection_status_id,latitude,longitude,altitude,discovery_year,
632 description,municipality_id,is_active,created_at)
633SELECT
634 s.name || ' - ' || s.loc,
635 s.type_id,
636 floor(random()*8+1),
637 floor(random()*3+1),
638 40.8+(random()*1.5),
639 20.5+(random()*2.5),
640 (150+(random()*1100))::int,
641 1850+(random()*175)::int,
642
643 CASE
644 WHEN s.name IN ('Градиште', 'Кале', 'Кула') THEN
645 'Стратешко утврдување со остатоци од дефанзивни ѕидови и кули, датира од ' ||
646 (ARRAY['антиката', 'доцната антика', 'средниот век'])[floor(random()*3+1)] || '.'
647 WHEN s.name IN ('Тумба', 'Могила') THEN
648 'Повеќеслојна праисториска населба со богат инвентар на керамички наоди и остатоци од ' ||
649 (ARRAY['неолитски', 'енеолитски', 'бронзени'])[floor(random()*2+1)]
650 ELSE
651 'Археолошки комплекс со значајни архитектонски остатоци и фрагментирана подвижна керамика.'
652 END,
653
654 floor(random()*10+1),
655 (random()>0.1),
656 NOW()-(random()*interval '500 days')
657
658 FROM(
659 SELECT
660 s.i,
661 (ARRAY['Градиште', 'Тумба', 'Кале', 'Црквиште', 'Висока', 'Могила', 'Бања', 'Манастир', 'Чука', 'Кула'])
662 [floor(random()*10+1)] as name,
663 (ARRAY['с. Злокуќани', 'с. Моноспитово', 'с. Таор', 'с. Кожле', 'Битола', 'Прилеп', 'с. Возарци', 'с. Радолишта', 'с. Вевчани', 'с. Смолани'])
664 [floor(random()*10+1)] || ' (' || s.i || ')' as loc,
665 floor(random()*4+1) as type_id
666 FROM generate_series(1,6000) s(i)
667 )s;
668
669
670INSERT INTO Objects (
671 inventory_number, title, current_status_id, site_id,
672 creation_year, acquisition_date, found_by_user_id, description
673)
674SELECT
675 'INV-' || i,
676 CASE
677 WHEN random() < 0.3 THEN 'Керамички сад'
678 WHEN random() < 0.6 THEN 'Бронзен предмет'
679 WHEN random() < 0.8 THEN 'Монета'
680 ELSE 'Фрагмент'
681 END,
682 (SELECT status_id FROM Status_Types WHERE type = 'object' LIMIT 1),
683 floor(random() * 6000 + 1),
684 (random() * 2000 + 1)::int,
685 NOW() - (random() * interval '95 years'),
686 floor(random() * 2000 + 1),
687 (ARRAY[
688 'Одлично зачуван примерок.',
689 'Потребна е итна конзервација.',
690 'Видливи траги од горење.',
691 'Пронајден во станбен објект.',
692 'Специфична декорација.',
693 NULL
694 ])[floor(random() * 6 + 1)]
695FROM generate_series(1, 2000000) AS i;
696select * from objects limit 20;
697
698
699
700INSERT INTO Fragments (
701 description, site_id, object_id, status_id, found_by_user_id, discovery_date, parent_fragment_id
702)
703SELECT
704 CASE
705 WHEN random() < 0.15 THEN 'Керамички фрагмент од сад'
706 WHEN random() < 0.30 THEN 'Фрагмент од амфора'
707 WHEN random() < 0.45 THEN 'Бронзен украсен дел'
708 WHEN random() < 0.60 THEN 'Фрагмент од монета'
709 WHEN random() < 0.75 THEN 'Камен архитектонски дел'
710 WHEN random() < 0.90 THEN 'Фрагмент од римска керамика'
711 ELSE 'Фрагмент од алат од железно време'
712 END,
713 st_site.ids[floor(random() * array_length(st_site.ids, 1) + 1)],
714 st_object.ids[floor(random() * array_length(st_object.ids, 1) + 1)],
715 st_status.ids[floor(random() * array_length(st_status.ids, 1) + 1)],
716 st_user.ids[floor(random() * array_length(st_user.ids, 1) + 1)],
717 NOW() - (floor(random() * 2000) * interval '1 day'),
718 NULL
719FROM generate_series(1, 500000)
720CROSS JOIN (SELECT array_agg(site_id) AS ids FROM Sites) st_site
721CROSS JOIN (SELECT array_agg(object_id) AS ids FROM Objects) st_object
722CROSS JOIN (SELECT array_agg(status_id) AS ids FROM Status_Types WHERE type='object') st_status
723CROSS JOIN (SELECT array_agg(user_id) AS ids FROM Users) st_user;
724
725
726INSERT INTO Fragments (description, site_id, object_id, status_id, found_by_user_id, discovery_date, parent_fragment_id)
727SELECT
728 'Под-фрагмент',
729 st_sites.ids[floor(random()*array_length(st_sites.ids,1)+1)],
730 NULL,
731 st_status.ids[floor(random()*array_length(st_status.ids,1)+1)],
732 st_user.ids[floor(random()*array_length(st_user.ids,1)+1)],
733 NOW() - (random()*500)*interval '1 day',
734 st_parents.ids[floor(random()*array_length(st_parents.ids,1)+1)]
735FROM generate_series(1, 500000)
736CROSS JOIN (SELECT array_agg(fragment_id) as ids FROM (SELECT fragment_id FROM Fragments LIMIT 200000) p) st_parents
737CROSS JOIN (SELECT array_agg(site_id) as ids FROM Sites) st_sites
738CROSS JOIN (SELECT array_agg(status_id) as ids FROM Status_Types) st_status
739CROSS JOIN (SELECT array_agg(user_id) as ids FROM Users) st_user;
740
741
742INSERT INTO Fragments (description, site_id, object_id, status_id, found_by_user_id, discovery_date, parent_fragment_id)
743SELECT
744 case
745 WHEN random() < 0.15 THEN 'Генерален фрагмент'
746 WHEN random() < 0.30 THEN 'Фрагмент од амфора'
747 WHEN random() < 0.45 THEN 'Генерален фрагмент'
748 WHEN random() < 0.60 THEN 'Фрагмент од монета'
749 WHEN random() < 0.75 THEN 'Генерален фрагмент'
750 WHEN random() < 0.90 THEN 'Фрагмент од римска керамика'
751 end,
752 st_sites.ids[floor(random()*array_length(st_sites.ids,1)+1)],
753 CASE WHEN random() < 0.8 THEN st_objects.ids[floor(random()*array_length(st_objects.ids,1)+1)] ELSE NULL END,
754 st_status.ids[floor(random()*array_length(st_status.ids,1)+1)],
755 st_user.ids[floor(random()*array_length(st_user.ids,1)+1)],
756 NOW() - (random()*1000)*interval '1 day',
757 NULL
758FROM generate_series(1, 500000)
759CROSS JOIN (SELECT array_agg(site_id) as ids FROM Sites) st_sites
760CROSS JOIN (SELECT array_agg(object_id) as ids FROM Objects) st_objects
761CROSS JOIN (SELECT array_agg(status_id) as ids FROM Status_Types) st_status
762CROSS JOIN (SELECT array_agg(user_id) as ids FROM Users) st_user;
763
764INSERT INTO Authors (full_name)
765SELECT
766 first_names.name || ' ' || last_names.surname
767FROM
768 (SELECT unnest(ARRAY[
769 'Иван','Петар','Гоце','Марко','Никола','Александар',
770 'Елена','Марија','Даниела','Снежана','Тамара','Кристина',
771 'Влатко','Бојан','Љупчо','Стефан','Зоран','Кирил'
772 ]) AS name) first_names,
773
774 (SELECT unnest(ARRAY[
775 'Микулчиќ','Кузман','Манев','Алексов','Стојанов','Петров',
776 'Илиев','Георгиев','Марков','Тодоров','Димитров','Павлов',
777 'Костов','Ристов','Наумов','Спасов','Стојков','Цветков'
778 ]) AS surname) last_names,
779
780 generate_series(1, 50000) g(i)
781LIMIT 50000;
782
783INSERT INTO Publications (
784 request_date,
785 main_author_id,
786 title,
787 status_id,
788 publisher_location
789)
790SELECT
791 CURRENT_DATE - (random()*3000)::int,
792
793 st_author.ids[floor(random()*array_length(st_author.ids,1)+1)],
794 CASE
795 WHEN random() < 0.2 THEN 'Археолошки истражувања во Вардарска долина'
796 WHEN random() < 0.4 THEN 'Римски период на Балканот: анализа на наоди'
797 WHEN random() < 0.6 THEN 'Средновековни утврдувања во Македонија'
798 WHEN random() < 0.8 THEN 'Културно наследство на античка Македонија'
799 ELSE 'Конзервација и реставрација на археолошки објекти'
800 END,
801 st_status.ids[floor(random()*array_length(st_status.ids,1)+1)],
802 CASE
803 WHEN random() < 0.3 THEN 'Skopje'
804 WHEN random() < 0.5 THEN 'Bitola'
805 WHEN random() < 0.7 THEN 'Ohrid'
806 ELSE 'Strumica'
807 END
808FROM generate_series(1, 500000)
809CROSS JOIN(SELECT array_agg(author_id) as ids FROM Authors)st_author
810CROSS JOIN(SELECT array_agg(status_id) as ids FROM Status_Types)st_status;
811
812INSERT INTO Culture (name, origin_region_id, description, period_from_year, period_to_year)
813VALUES
814-- PRAISTORIJA
815('Палеолитска култура', 1, 'Рани човечки заедници и ловци-собирачи', -100000, -10000),
816('Неолитска култура', 1, 'Први земјоделски заедници и села', -7000, -3000),
817('Бронзено време', 2, 'Развој на металургија и племенски општества', -3000, -1200),
818('Железно време', 3, 'Племенски култури пред антика', -1200, -500),
819
820-- ANTIKA
821('Пајонска култура', 4, 'Античко племе во регионот на Вардар', -1000, -200),
822('Античка македонска култура', 1, 'Кралството на Македонија', -800, -168),
823('Хеленистичка култура', 1, 'Период по Александар Велики', -323, -31),
824
825-- RIMSKI PERIOD
826('Римска провинциска култура', 2, 'Римска администрација и урбан развој', -168, 300),
827('Доцноримска култура', 3, 'Криза и трансформација на Римската империја', 300, 600),
828
829-- VIZANTIJA
830('Рановизантиска култура', 4, 'Рано христијанство и византиска уметност', 330, 800),
831('Средновизантиска култура', 5, 'Развој на црква и феудализам', 800, 1200),
832('Доцновизантиска култура', 5, 'Ослабување на Византија', 1200, 1453),
833
834-- SREDEN VEK
835('Словенска култура', 6, 'Доаѓање на словенските племиња', 600, 1000),
836('Средновековна балканска култура', 6, 'Феудални држави на Балканот', 1000, 1400),
837
838-- OSMANSKI PERIOD
839('Османлиска култура', 7, 'Османлиско владеење на Балканот', 1400, 1912),
840
841-- MODERNO
842('Современа култура', 8, 'Модерен период по ослободувањето', 1912, 2020);
843
844WITH obj AS (
845 SELECT object_id FROM Objects
846),
847mat AS (
848 SELECT material_id FROM Materials
849),
850pairs AS (
851 SELECT
852 obj.object_id,
853 mat.material_id,
854 row_number() OVER () AS rn
855 FROM obj
856 CROSS JOIN mat
857)
858
859INSERT INTO Materials_Objects (object_id, material_id)
860SELECT
861 st_object_id.ids[floor(random()*array_length(st_object_id.ids,1)+1)],
862 st_material_id.ids[floor(random()*array_length(st_material_id.ids,1)+1)]
863FROM generate_series(1,500000)
864CROSS JOIN(SELECT array_agg(object_id) as ids FROM Objects)st_object_id
865CROSS JOIN(SELECT array_agg(material_id) as ids FROM Materials)st_material_id
866on conflict do nothing;
867
868
869WITH obj AS (
870 SELECT array_agg(object_id) AS oids FROM Objects
871),
872inst AS (
873 SELECT array_agg(institution_id) AS insts FROM Institutions
874)
875
876INSERT INTO Conservation_Projects (
877 project_name,
878 start_date,
879 end_date,
880 budget,
881 description_project,
882 institution_id,
883 object_id
884)
885SELECT
886 name || ' ' || i,
887 t.start_d,
888 t.start_d + (1 + floor(random()*1000)) * interval '1 day',
889 (1000 + random()*99000)::numeric(10,2),
890 name || ' - детално истражување и конзервација на артефактот.',
891 inst.insts[1 + floor(random()*array_length(inst.insts,1))::int],
892 obj.oids[1 + floor(random()*array_length(obj.oids,1))::int]
893
894FROM generate_series(1, 200000) i,
895 obj, inst,
896 LATERAL (
897 SELECT
898 CASE
899 WHEN random() < 0.25 THEN 'Проект за конзервација на керамика'
900 WHEN random() < 0.50 THEN 'Реставрација на антички објекти'
901 WHEN random() < 0.75 THEN 'Археолошко истражување на локалитет'
902 ELSE 'Дигитализација на културно наследство'
903 END AS name,
904 NOW() - (floor(random()*2000+i*0))*interval '30 days' AS start_d
905 ) t;
906
907
908WITH obj AS (
909 SELECT array_agg(object_id) AS oids FROM Objects
910)
911INSERT INTO Treatments (object_id, treatment_date,description)
912SELECT
913 obj.oids[1 + floor(random()*array_length(obj.oids,1))::int],
914 CURRENT_DATE - (floor(random()*1000))::int,
915 CASE
916 WHEN random() < 0.25 THEN 'Механичко чистење на површински наслоги и земја'
917 WHEN random() < 0.40 THEN 'Хемиска стабилизација на кородирани метални делови'
918 WHEN random() < 0.55 THEN 'Консолидација на кршлива керамика со паралоид B-72'
919 WHEN random() < 0.70 THEN 'Превентивна десалинизација во дејонизирана вода'
920 WHEN random() < 0.80 THEN 'Лепење на фрагменти со реверзибилен лепак'
921 WHEN random() < 0.90 THEN 'Реставрација на недостатоци со гипс и ретуширање'
922 ELSE 'Нанесување на заштитен микрокристален восок'
923END
924FROM obj, generate_series(1, 500000);
925
926WITH o AS (
927 SELECT array_agg(object_id) AS oids FROM Objects
928),
929s AS (
930 SELECT array_agg(status_id) as ids FROM Status_Types WHERE type='object'
931)
932INSERT INTO Condition_Assessment (
933 assessment_date,
934 notes,
935 object_id,
936 status_id
937)
938SELECT
939 CURRENT_DATE - (floor(random()*2000))::int,
940 'Condition note ' || i,
941 o.oids[i],
942 s.ids[floor(random()*array_length(s.ids,1)+1)]
943FROM o, s,
944generate_series(1, array_length((SELECT array_agg(object_id) FROM Objects),1)) i;
945
946
947INSERT INTO Treatment_Step_Log (
948 treatment_id, step_number, step_description, observations,
949 timestamp_performed, performed_by_user, researcher_access_id
950)
951SELECT
952 st_treatment.ids[floor(random()*array_length(st_treatment.ids,1)+1)],
953 floor(random()*5+1),
954 (ARRAY['Инспекција', 'Чистење', 'Конзервација', 'Документација', 'Проверка'])[floor(random()*5+1)], -- Сигурен избор без NULL
955 CASE WHEN random() < 0.5 THEN 'Процесот помина во најдобар ред.' ELSE 'Забележани ситни нечистотии.' END,
956 NOW() - (random() * interval '30 days'),
957 u.ids[floor(random() * array_length(u.ids, 1) + 1)],
958 ra.ids[floor(random() * array_length(ra.ids, 1) + 1)]
959FROM generate_series(1, 7000000)
960CROSS JOIN (SELECT array_agg(user_id) AS ids FROM Users) u
961CROSS JOIN (SELECT array_agg(access_id) AS ids FROM Researcher_Access) ra
962CROSS JOIN (SELECT array_agg(treatment_id) AS ids FROM Treatments) st_treatment
963on conflict do nothing;
964
965select count(*) from treatment_step_log;
966
967
968
969WITH obj AS (
970 SELECT array_agg(object_id) AS oids FROM Objects
971)
972INSERT INTO Object_Images (
973 image_url,
974 object_id,
975 description,
976 date_taken,
977 is_primary
978)
979SELECT
980 'http://img/object_' || selected_id || '_' || i,
981 selected_id,
982 CASE
983 WHEN i % 3 = 0 THEN 'Поглед од предна страна'
984 WHEN i % 3 = 1 THEN 'Детален приказ на текстура'
985 ELSE 'Профилна снимка на предметот'
986 END,
987 CURRENT_DATE - (random() * 730)::int,
988 (random() < 0.15)
989FROM (
990 SELECT
991 obj.oids[floor(random() * array_length(obj.oids, 1) + 1)] AS selected_id,
992 i
993 FROM obj, generate_series(1, 1000000) i
994) subquery;
995
996
997INSERT INTO Researcher_Access (
998 access_date,
999 access_status_id,
1000 user_id,
1001 object_id,
1002 institution_id,
1003 conservation_project_id
1004)
1005SELECT
1006 CURRENT_DATE - (floor(random()*1200))::int,
1007 st_arr.ids[floor(random() * array_length(st_arr.ids, 1) + 1)],
1008 u_arr.ids[floor(random() * array_length(u_arr.ids, 1) + 1)],
1009 o_arr.ids[floor(random() * array_length(o_arr.ids, 1) + 1)],
1010 i_arr.ids[floor(random() * array_length(i_arr.ids, 1) + 1)],
1011 CASE
1012 WHEN random() < 0.6 THEN p_arr.ids[floor(random() * array_length(p_arr.ids, 1) + 1)]
1013 ELSE NULL
1014 END
1015FROM
1016 (SELECT array_agg(status_id) AS ids FROM Status_Types WHERE type = 'access') st_arr,
1017 (SELECT array_agg(user_id) AS ids FROM Users) u_arr,
1018 (SELECT array_agg(object_id) AS ids FROM Objects) o_arr,
1019 (SELECT array_agg(institution_id) AS ids FROM Institutions) i_arr,
1020 (SELECT array_agg(project_id) AS ids FROM Conservation_Projects) p_arr,
1021 generate_series(1, 500000) AS s;
1022
1023
1024
1025INSERT INTO Exhibitions (start_date, end_date, name, location_institution_id)
1026SELECT
1027 base_date,
1028 CASE
1029 WHEN random() < 0.7
1030 THEN base_date + (floor(random()*1500))::int
1031 ELSE NULL
1032 END,
1033 CASE (i % 8)
1034 WHEN 0 THEN 'Праисториска Македонија'
1035 WHEN 1 THEN 'Античка Македонија'
1036 WHEN 2 THEN 'Римски период'
1037 WHEN 3 THEN 'Византија'
1038 WHEN 4 THEN 'Среден век'
1039 WHEN 5 THEN 'Османлиски период'
1040 WHEN 6 THEN 'Археологија'
1041 ELSE 'Модерна уметност'
1042 END || ' - Изложба ' || i,
1043 inst_arr.ids[floor(random() * array_length(inst_arr.ids, 1) + 1)]
1044FROM generate_series(1, 5000) i
1045CROSS JOIN (
1046 SELECT array_agg(institution_id) AS ids FROM Institutions
1047) inst_arr
1048CROSS JOIN LATERAL (
1049 SELECT CURRENT_DATE - (floor(random()*4000+i*0))::int AS base_date
1050) d;
1051
1052
1053INSERT INTO Exhibition_Object_Details (
1054 display_title,
1055 exhibition_description,
1056 language,
1057 object_id,
1058 exhibition_id
1059)
1060SELECT
1061 'Објект во изложба ' || gs,
1062
1063 CASE
1064 WHEN random() < 0.3 THEN 'Археолошки наод'
1065 WHEN random() < 0.6 THEN 'Музејски предмет'
1066 ELSE 'Културно наследство'
1067 END,
1068
1069 CASE WHEN random() < 0.5 THEN 'mk' ELSE 'en' END,
1070
1071 o.object_id,
1072 e.exhibition_id
1073
1074FROM generate_series(1, 10000) gs
1075
1076JOIN LATERAL (
1077 SELECT object_id
1078 FROM Objects
1079 ORDER BY object_id
1080 OFFSET (gs % (SELECT COUNT(*) FROM Objects))
1081 LIMIT 1
1082) o ON true
1083
1084JOIN LATERAL (
1085 SELECT exhibition_id
1086 FROM Exhibitions
1087 ORDER BY exhibition_id
1088 OFFSET (gs % (SELECT COUNT(*) FROM Exhibitions))
1089 LIMIT 1
1090) e ON true;
1091
1092INSERT INTO Object_Classification (
1093 object_id,
1094 category_id,
1095 culture_id,
1096 period_descr,
1097 style,
1098 iconography
1099)
1100SELECT
1101 o.object_id,
1102 cat.ids[floor(random() * array_length(cat.ids, 1) + 1)],
1103 cul.ids[floor(random() * array_length(cul.ids, 1) + 1)],
1104 (ARRAY['Ран неолит', 'Доцна антика', 'Среден век', 'Бронзено доба', 'Хеленистички период'])[floor(random() * 5 + 1)],
1105 (ARRAY['Доричен', 'Јонски', 'Византиски', 'Локален стил', 'Барок'])[floor(random() * 5 + 1)],
1106 (ARRAY['Религиозни мотиви', 'Геометриски фигури', 'Животински приказ', 'Растителни орнаменти'])[floor(random() * 4 + 1)]
1107FROM Objects o
1108CROSS JOIN (SELECT array_agg(category_id) AS ids FROM Categories) cat
1109CROSS JOIN (SELECT array_agg(culture_id) AS ids FROM Culture) cul
1110ON CONFLICT DO NOTHING;
1111
1112
1113INSERT INTO Object_Exhibition (object_id, exhibition_id)
1114SELECT
1115 o.object_id,
1116 ex.ids[floor(random() * array_length(ex.ids, 1) + 1)]
1117FROM (
1118 SELECT object_id FROM Objects
1119 LIMIT 500000
1120) o
1121CROSS JOIN (
1122 SELECT array_agg(exhibition_id) AS ids FROM Exhibitions
1123) ex
1124ON CONFLICT DO NOTHING;
1125
1126
1127INSERT INTO Object_Location_History (
1128 object_id,
1129 institution_id,
1130 start_date,
1131 end_date
1132)
1133SELECT
1134 o.object_id,
1135 inst.ids[floor(random() * array_length(inst.ids, 1) + 1)],
1136 start_d,
1137 CASE
1138 WHEN random() < 0.7
1139 THEN start_d + (random() * 500)::int
1140 ELSE NULL
1141 END
1142FROM (
1143 SELECT
1144 object_id,
1145 CURRENT_DATE - (random() * 3000)::int AS start_d
1146 FROM Objects
1147) o
1148CROSS JOIN (
1149 SELECT array_agg(institution_id) AS ids FROM Institutions
1150) inst
1151ON CONFLICT DO NOTHING;
1152
1153
1154
1155INSERT INTO Object_Publication (
1156 object_id,
1157 publication_id,
1158 page_reference,
1159 notes
1160)
1161SELECT
1162 o.object_id,
1163 p.ids[floor(random() * array_length(p.ids, 1) + 1)],
1164 'p.' || floor(random() * 500 + 1)::text,
1165 'Археолошка публикација'
1166FROM (
1167 SELECT object_id FROM Objects LIMIT 200000
1168) o
1169CROSS JOIN (
1170 SELECT array_agg(publication_id) AS ids FROM Publications
1171) p
1172ON CONFLICT DO NOTHING;
1173
1174
1175INSERT INTO Publication_Authors (publication_id, author_id)
1176SELECT
1177 p.publication_id,
1178 a.ids[floor(random()*array_length(a.ids,1)+1)]
1179FROM Publications p
1180CROSS JOIN(SELECT array_agg(author_id) as ids FROM Authors)a
1181LIMIT 200000;
1182
1183INSERT INTO Treatment_Materials (treatment_id, material_id)
1184SELECT
1185 t.treatment_id,
1186 COALESCE(
1187 CASE
1188 WHEN o.title ILIKE '%керами%' OR o.title ILIKE '%сад%'
1189 THEN (SELECT material_id FROM Materials WHERE name = 'Керамика' LIMIT 1)
1190 WHEN o.title ILIKE '%бронз%' OR o.title ILIKE '%фибул%'
1191 THEN (SELECT material_id FROM Materials WHERE name = 'Бронза' LIMIT 1)
1192 WHEN o.title ILIKE '%желез%' OR o.title ILIKE '%меч%' OR o.title ILIKE '%нож%'
1193 THEN (SELECT material_id FROM Materials WHERE name = 'Железо' LIMIT 1)
1194 WHEN o.title ILIKE '%монета%' OR o.title ILIKE '%пари%'
1195 THEN (SELECT material_id FROM Materials WHERE name IN ('Сребро', 'Злато', 'Бронза') ORDER BY random() LIMIT 1)
1196 WHEN o.title ILIKE '%камен%' OR o.title ILIKE '%стату%'
1197 THEN (SELECT material_id FROM Materials WHERE name = 'Камен' LIMIT 1)
1198 END,
1199 m_list.ids[floor(random() * array_length(m_list.ids, 1) + 1)]
1200 )
1201FROM (
1202 SELECT treatment_id, object_id FROM Treatments LIMIT 1000000
1203) t
1204JOIN Objects o ON o.object_id = t.object_id
1205CROSS JOIN (
1206 SELECT array_agg(material_id) AS ids FROM Materials
1207) m_list
1208ON CONFLICT DO NOTHING;
1209
1210select count(*) from treatment_materials;
1211
1212CREATE INDEX IF NOT EXISTS idx_sites_region ON Sites(region_id);
1213CREATE INDEX IF NOT EXISTS idx_sites_status ON Sites(protection_status_id);
1214DROP VIEW IF EXISTS Heritage_Full_Overview CASCADE;
1215
1216
1217CREATE INDEX IF NOT EXISTS idx_objects_site_id ON Objects(site_id);
1218CREATE INDEX IF NOT EXISTS idx_fragments_site_id ON Fragments(site_id);
1219
1220CREATE OR REPLACE VIEW Heritage_Full_Overview AS
1221SELECT
1222 f.fragment_id,
1223 f.description AS fragment_description,
1224 o.title AS object_title,
1225 s.site_id,
1226 s.site_name,
1227 r.name AS region,
1228 ps.name AS protection_status
1229FROM Fragments f
1230JOIN Objects o ON f.object_id = o.object_id
1231JOIN Sites s ON f.site_id = s.site_id
1232JOIN Regions r ON s.region_id = r.region_id
1233JOIN Protection_Status ps ON s.protection_status_id = ps.protection_status_id;
1234
1235
1236EXPLAIN ANALYZE SELECT * FROM Heritage_Full_Overview WHERE site_id = 100 LIMIT 10;
1237
1238-- INSERT
1239INSERT INTO Fragments (
1240 description,
1241 site_id,
1242 object_id,
1243 status_id,
1244 found_by_user_id,
1245 discovery_date
1246)
1247SELECT
1248 'Нов фрагмент',
1249 1,
1250 object_id,
1251 1,
1252 1,
1253 CURRENT_DATE
1254FROM Objects
1255LIMIT 1;
1256
1257-- UPDATE
1258UPDATE Fragments
1259SET description = 'Ажуриран фрагмент'
1260WHERE fragment_id = (
1261 SELECT fragment_id
1262 FROM Fragments
1263 LIMIT 1
1264);
1265
1266--podeleni spored lokalitet
1267
1268CREATE INDEX IF NOT EXISTS idx_objects_site_id ON Objects(site_id);
1269CREATE INDEX IF NOT EXISTS idx_fragments_site_id ON Fragments(site_id);
1270
1271ANALYZE Objects;
1272ANALYZE Fragments;
1273
1274create OR replace VIEW Site_Statistics AS
1275SELECT
1276 s.site_id,
1277 s.site_name,
1278 r.name AS region,
1279 COALESCE(o_counts.total_objects, 0) AS total_objects,
1280 COALESCE(f_counts.total_fragments, 0) AS total_fragments,
1281 (CURRENT_DATE - (floor(random() * 3650) * interval '1 day'))::timestamp AS last_checked_at
1282FROM Sites s
1283JOIN Regions r ON s.region_id = r.region_id
1284LEFT JOIN (
1285 SELECT site_id, COUNT(*) AS total_objects
1286 FROM Objects
1287 GROUP BY site_id
1288) o_counts ON s.site_id = o_counts.site_id
1289LEFT JOIN (
1290 SELECT site_id, COUNT(*) AS total_fragments
1291 FROM Fragments
1292 GROUP BY site_id
1293) f_counts ON s.site_id = f_counts.site_id;
1294
1295SELECT
1296 relname AS table_name,
1297 pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
1298 pg_size_pretty(pg_relation_size(relid)) AS data_size,
1299 pg_size_pretty(pg_total_relation_size(relid) - pg_relation_size(relid)) AS index_size
1300FROM pg_catalog.pg_statio_user_tables
1301WHERE relname IN ('fragments', 'objects', 'sites');
1302
1303explain analyze select * from site_statistics where site_id=39568;
1304
1305EXPLAIN ANALYZE
1306SELECT *
1307FROM Site_Statistics
1308WHERE site_id = 10;
1309
1310
1311
1312-- INSERT
1313INSERT INTO Sites (site_name, site_type_id, region_id, protection_status_id, latitude, longitude, discovery_year)
1314VALUES ('Локалитет 11001', 1, 1, 1, 41.3, 21.7, 2001);
1315
1316-- UPDATE
1317UPDATE Sites
1318SET discovery_year = 2002
1319WHERE site_id = 100;
1320
1321
1322--zastiteni lokaliteti
1323CREATE OR REPLACE VIEW Protected_Sites_Inventory AS
1324SELECT
1325 s.site_id,
1326 s.site_name,
1327 r.name AS region,
1328 s.discovery_year,
1329 COALESCE(o.total_objects_count, 0) AS total_objects_count
1330FROM Sites s
1331JOIN Regions r
1332 ON s.region_id = r.region_id
1333JOIN Protection_Status ps
1334 ON s.protection_status_id = ps.protection_status_id
1335LEFT JOIN (
1336 SELECT site_id, COUNT(*) AS total_objects_count
1337 FROM Objects
1338 GROUP BY site_id
1339) o
1340 ON s.site_id = o.site_id
1341WHERE ps.name = 'Заштитен'
1342ORDER BY s.discovery_year DESC;
1343
1344explain analyze select * from Protected_Sites_Inventory;
1345SELECT * FROM Protected_Sites_Inventory;
1346
1347EXPLAIN ANALYZE
1348SELECT *
1349FROM Protected_Sites_Inventory
1350WHERE site_id = 456890;
1351
1352
1353--insert
1354INSERT INTO Objects (inventory_number, title, current_status_id, site_id)
1355VALUES ('INV-9999999', 'Test object', 1, 100);
1356
1357-- UPDATE
1358UPDATE Objects
1359SET title = 'UPDATED TEST OBJECT'
1360WHERE inventory_number = 'INV-9999999';
1361
1362--spored materijali se prebaruva
1363CREATE OR REPLACE VIEW Objects_with_Materials AS
1364SELECT
1365 o.object_id,
1366 o.title,
1367 m.name AS material
1368FROM Objects o
1369LEFT JOIN Materials_Objects om
1370 ON o.object_id = om.object_id
1371LEFT JOIN Materials m
1372 ON om.material_id = m.material_id;
1373
1374SELECT * FROM Objects_with_Materials;
1375
1376-- UPDATE
1377UPDATE Materials_Objects
1378SET material_id = 2
1379WHERE object_id = 1000;
1380
1381
1382-- kade se naogaat vo koj lokalitet momentalno
1383CREATE OR REPLACE VIEW Object_Current_Location AS
1384SELECT
1385 o.object_id,
1386 o.title,
1387 i.name AS institution
1388FROM Objects o
1389JOIN Object_Location_History olh ON olh.object_id = o.object_id
1390JOIN Institutions i ON i.institution_id = olh.institution_id
1391WHERE olh.end_date IS NULL;
1392
1393CREATE INDEX idx_olh_end_date ON Object_Location_History(end_date);
1394
1395EXPLAIN ANALYZE SELECT * FROM Object_Current_Location WHERE object_id = 1340;
1396
1397
1398
1399-- INSERT
1400INSERT INTO Object_Location_History (object_id, institution_id, start_date)
1401VALUES (809042, 1, CURRENT_DATE);
1402
1403-- UPDATE
1404UPDATE Object_Location_History
1405SET end_date = CURRENT_DATE
1406WHERE object_id = 809042
1407 AND end_date IS NULL;
1408
1409
1410--na koja kultura pripaga
1411CREATE OR REPLACE VIEW Object_with_Culture AS
1412SELECT
1413 o.object_id,
1414 o.title,
1415 c.name AS culture,
1416 cat.name AS category
1417FROM Objects o
1418JOIN Object_Classification oc ON oc.object_id = o.object_id
1419JOIN Culture c ON c.culture_id = oc.culture_id
1420JOIN Categories cat ON cat.category_id = oc.category_id;
1421
1422CREATE INDEX idx_oc_object_id ON Object_Classification(object_id);
1423
1424EXPLAIN ANALYZE SELECT * FROM Object_with_Culture WHERE object_id = 150;
1425SELECT * FROM Object_with_Culture;
1426
1427-- INSERT
1428INSERT INTO Object_Classification (object_id, category_id, culture_id)
1429VALUES (1649219, 1, 1);
1430
1431-- UPDATE
1432UPDATE Object_Classification
1433SET category_id = 2
1434WHERE object_id = 1649219;
1435
1436--koi predmeti na koi izlozbi
1437
1438CREATE OR REPLACE VIEW Exhibition_Objects AS
1439SELECT
1440 e.exhibition_id,
1441 e.name AS exhibition,
1442 o.object_id,
1443 o.title AS object,
1444 i.name AS institution
1445FROM Object_Exhibition oe
1446JOIN Exhibitions e ON e.exhibition_id = oe.exhibition_id
1447JOIN Objects o ON o.object_id = oe.object_id
1448JOIN Institutions i ON i.institution_id = e.location_institution_id;
1449
1450CREATE INDEX idx_oe_exhibition_id ON Object_Exhibition(exhibition_id);
1451CREATE INDEX idx_oe_object_id ON Object_Exhibition(object_id);
1452
1453
1454EXPLAIN ANALYZE SELECT * FROM Exhibition_Objects LIMIT 10;
1455EXPLAIN ANALYZE SELECT * FROM Exhibition_Objects WHERE exhibition_id = 204050;
1456EXPLAIN ANALYZE SELECT * FROM Exhibition_Objects WHERE exhibition_id = 4;
1457
1458
1459-- INSERT
1460INSERT INTO Object_Exhibition (object_id, exhibition_id)
1461VALUES (
1462 (SELECT MAX(object_id) FROM Objects),
1463 (SELECT MAX(exhibition_id) FROM Exhibitions)
1464);
1465
1466-- UPDATE
1467UPDATE Object_Exhibition
1468SET exhibition_id = 3
1469WHERE object_id = (
1470 SELECT MAX(object_id) FROM Object_Exhibition
1471)
1472AND exhibition_id = (
1473 SELECT MAX(exhibition_id) FROM Object_Exhibition
1474);
1475
1476
1477--koj naucnik ili istrazuvas pobaral da istrazuva predmet dali mu e odobreno momentalno
1478
1479CREATE OR REPLACE VIEW Research_Access_Details AS
1480SELECT
1481 ra.user_id,
1482 u.full_name,
1483 ra.object_id,
1484 o.title AS object,
1485 i.name AS institution,
1486 s.status_name AS access_status,
1487 ra.access_date
1488FROM Researcher_Access ra
1489JOIN Users u ON u.user_id = ra.user_id
1490JOIN Objects o ON o.object_id = ra.object_id
1491JOIN Institutions i ON i.institution_id = ra.institution_id
1492JOIN Status_Types s ON s.status_id = ra.access_status_id
1493WHERE s.type = 'access';
1494
1495CREATE INDEX idx_ra_user_id ON Researcher_Access(user_id);
1496CREATE INDEX idx_ra_object_id ON Researcher_Access(object_id);
1497ANALYZE Researcher_Access;
1498CREATE INDEX idx_ra_institution_id ON Researcher_Access(institution_id);
1499ANALYZE Objects;
1500
1501
1502EXPLAIN ANALYZE SELECT * FROM Research_Access_Details WHERE user_id = 1000;
1503
1504CREATE INDEX IF NOT EXISTS idx_tsl_treatment
1505ON Treatment_Step_Log(treatment_id);
1506
1507CREATE INDEX IF NOT EXISTS idx_treatments_object
1508ON Treatments(object_id);
1509
1510CREATE INDEX IF NOT EXISTS idx_tsl_treatment_user_step
1511ON Treatment_Step_Log(treatment_id, performed_by_user, step_number);
1512
1513CREATE INDEX idx_ra_user_object
1514ON Researcher_Access(user_id, object_id);
1515
1516INSERT INTO Researcher_Access (
1517 access_date, access_status_id, user_id, object_id, institution_id
1518)
1519SELECT
1520 CURRENT_DATE,
1521 6,
1522 user_id,
1523 object_id,
1524 1
1525FROM Users u
1526JOIN Objects o ON o.object_id = u.user_id
1527LIMIT 1;
1528
1529
1530UPDATE Researcher_Access
1531SET access_status_id = 7
1532WHERE user_id = 1000
1533AND object_id = 1000;
1534
1535--tretmani vrz odreden objekt
1536
1537CREATE OR REPLACE VIEW Treatment_History AS
1538SELECT
1539 t.object_id,
1540 o.title,
1541 t.treatment_date,
1542 tsl.step_number,
1543 tsl.step_description,
1544 u.full_name
1545FROM Treatments t
1546JOIN Objects o ON o.object_id = t.object_id
1547JOIN Treatment_Step_Log tsl ON tsl.treatment_id = t.treatment_id
1548JOIN Users u ON u.user_id = tsl.performed_by_user;
1549
1550EXPLAIN ANALYZE SELECT * FROM Treatment_History WHERE object_id = 100;
1551
1552
1553-- INSERT
1554INSERT INTO Treatments (object_id, treatment_date, description)
1555SELECT object_id, CURRENT_DATE, 'Test treatment'
1556FROM Objects
1557WHERE object_id BETWEEN 1 AND 10
1558LIMIT 1;
1559
1560-- UPDATE
1561UPDATE Treatments
1562SET description = 'Update treatment',
1563 treatment_date = CURRENT_DATE
1564WHERE object_id = (
1565 SELECT object_id
1566 FROM Objects
1567 WHERE object_id BETWEEN 1 AND 10
1568 LIMIT 1
1569)
1570AND description = 'Test treatment';
1571
1572
1573--koj avtor koi publikacii gi napravil
1574
1575CREATE OR REPLACE VIEW Publications_with_Authors AS
1576SELECT
1577 pa.publication_id,
1578 p.title,
1579 a.full_name AS author
1580FROM Publication_Authors pa
1581JOIN Publications p ON p.publication_id = pa.publication_id
1582JOIN Authors a ON a.author_id = pa.author_id;
1583
1584
1585CREATE INDEX idx_pa_publication_id ON Publication_Authors(publication_id);
1586CREATE INDEX idx_pa_author_id ON Publication_Authors(author_id);
1587ANALYZE Publication_Authors;
1588ANALYZE Publications;
1589
1590
1591EXPLAIN ANALYZE SELECT * FROM Publications_with_Authors WHERE publication_id = 100;
1592
1593-- INSERT
1594INSERT INTO Publication_Authors (publication_id, author_id)
1595VALUES (2, 50000);
1596
1597UPDATE Publication_Authors
1598SET author_id = 49999
1599WHERE publication_id = 2
1600 AND author_id = 50000;
1601
1602
1603--FUNCTION 1 – проверка дали објект е валиден за работа
1604CREATE OR REPLACE FUNCTION is_object_available(p_object_id BIGINT)
1605RETURNS BOOLEAN AS $$
1606DECLARE v_status BIGINT;
1607BEGIN
1608 SELECT current_status_id
1609 INTO v_status
1610 FROM Objects
1611 WHERE object_id = p_object_id;
1612
1613 IF NOT FOUND THEN
1614 RETURN FALSE;
1615 END IF;
1616
1617 IF v_status = 3 THEN
1618 RETURN FALSE;
1619 END IF;
1620
1621 RETURN TRUE;
1622END;
1623$$ LANGUAGE plpgsql;
1624
1625
1626-- PROCEDURE 1 – додавање третман само ако објект е дозволен
1627CREATE OR REPLACE PROCEDURE add_treatment(
1628 p_object_id BIGINT,
1629 p_desc TEXT
1630)
1631LANGUAGE plpgsql
1632AS $$
1633BEGIN
1634 IF NOT is_object_available(p_object_id) THEN
1635 RAISE EXCEPTION 'Објектот не е достапен за третман';
1636 END IF;
1637
1638 INSERT INTO Treatments(object_id, treatment_date, description)
1639 VALUES (p_object_id, CURRENT_DATE, p_desc);
1640END;
1641$$;
1642
1643SELECT is_object_available(804822);
1644CALL add_treatment(804822, 'Чистење');
1645SELECT *
1646FROM Treatments
1647WHERE object_id = 804822
1648ORDER BY treatment_date DESC;
1649
1650
1651--додавање третман + кој работел на него
1652CREATE OR REPLACE FUNCTION add_treatment(
1653 p_object_id BIGINT,
1654 p_description TEXT,
1655 p_user_id BIGINT
1656)
1657RETURNS VOID AS $$
1658DECLARE
1659 v_treatment_id BIGINT;
1660BEGIN
1661 -- проверка дали објект постои
1662 IF NOT EXISTS (
1663 SELECT 1 FROM Objects WHERE object_id = p_object_id
1664 ) THEN
1665 RAISE EXCEPTION 'Објектот не постои';
1666 END IF;
1667
1668 -- додавање третман
1669 INSERT INTO Treatments(object_id, treatment_date, description)
1670 VALUES (p_object_id, CURRENT_DATE, p_description)
1671 RETURNING treatment_id INTO v_treatment_id;
1672
1673 -- лог кој го работел
1674 INSERT INTO Treatment_Step_Log(
1675 treatment_id,
1676 step_number,
1677 step_description,
1678 performed_by_user
1679 )
1680 VALUES (
1681 v_treatment_id,
1682 1,
1683 'Initial treatment',
1684 p_user_id
1685 );
1686END;
1687$$ LANGUAGE plpgsql;
1688
1689
1690-- TRIGGER 1 – автоматско спречување „лоши фрагменти“
1691CREATE OR REPLACE FUNCTION trg_fragment_validation()
1692RETURNS TRIGGER AS $$
1693BEGIN
1694 IF NEW.object_id IS NOT NULL AND NEW.parent_fragment_id IS NOT NULL THEN
1695 RAISE EXCEPTION 'Фрагмент не може да има и object и parent';
1696 END IF;
1697
1698 RETURN NEW;
1699END;
1700$$ LANGUAGE plpgsql;
1701
1702CREATE TRIGGER trg_fragment_check
1703BEFORE INSERT OR UPDATE ON Fragments
1704FOR EACH ROW
1705EXECUTE FUNCTION trg_fragment_validation();
1706
1707INSERT INTO Fragments (object_id, parent_fragment_id, status_id)
1708VALUES (1, 2, 1);
1709
1710INSERT INTO Fragments (
1711 fragment_id,
1712 site_id,
1713 object_id,
1714 status_id
1715)
1716VALUES (
1717 10500004,
1718 1,
1719 804822,
1720 1
1721);
1722
1723SELECT *
1724FROM Fragments
1725WHERE fragment_id = 10500004;
1726
1727
1728-- FUNCTION 2 – проверка на истражувачки пристап
1729CREATE OR REPLACE FUNCTION has_access(
1730 p_user_id BIGINT,
1731 p_object_id BIGINT
1732)
1733RETURNS BOOLEAN AS $$
1734BEGIN
1735 RETURN EXISTS (
1736 SELECT 1
1737 FROM Researcher_Access
1738 WHERE user_id = p_user_id
1739 AND object_id = p_object_id
1740 AND access_status_id = 6
1741 );
1742END;
1743$$ LANGUAGE plpgsql;
1744
1745
1746-- PROCEDURE 2 – барање за пристап
1747CREATE OR REPLACE PROCEDURE request_access(
1748 p_user_id BIGINT,
1749 p_object_id BIGINT,
1750 p_institution_id BIGINT
1751)
1752LANGUAGE plpgsql
1753AS $$
1754BEGIN
1755 INSERT INTO Researcher_Access(
1756 access_date,
1757 access_status_id,
1758 user_id,
1759 object_id,
1760 institution_id
1761 )
1762 VALUES (
1763 CURRENT_DATE,
1764 7, -- во обработка
1765 p_user_id,
1766 p_object_id,
1767 p_institution_id
1768 );
1769END;
1770$$;
1771
1772CALL request_access(10, 804822, 1);
1773
1774SELECT *
1775FROM Researcher_Access
1776WHERE user_id = 10 AND object_id = 804822;
1777
1778UPDATE Researcher_Access
1779SET access_status_id = 6
1780WHERE user_id = 10 AND object_id = 804822;
1781
1782
1783SELECT has_access(10, 804822);
1784
1785-- TRIGGER 2 – автоматско одбивање ако нема право
1786CREATE OR REPLACE FUNCTION trg_block_access()
1787RETURNS TRIGGER AS $$
1788BEGIN
1789 IF NEW.access_status_id = 6 AND NEW.object_id IS NULL THEN
1790 RAISE EXCEPTION 'Не може одобрен пристап без објект';
1791 END IF;
1792
1793 RETURN NEW;
1794END;
1795$$ LANGUAGE plpgsql;
1796
1797CREATE TRIGGER trg_access_check
1798BEFORE INSERT ON Researcher_Access
1799FOR EACH ROW
1800EXECUTE FUNCTION trg_block_access();
1801
1802-- FUNCTION 3 – број на автори по публикација
1803CREATE OR REPLACE FUNCTION count_authors(p_publication_id BIGINT)
1804RETURNS INT AS $$
1805DECLARE v_count INT;
1806BEGIN
1807 SELECT COUNT(*)
1808 INTO v_count
1809 FROM Publication_Authors
1810 WHERE publication_id = p_publication_id;
1811
1812 RETURN v_count;
1813END;
1814$$ LANGUAGE plpgsql;
1815
1816-- PROCEDURE 3 – додавање автор во публикација (без дупликати)
1817CREATE OR REPLACE PROCEDURE add_author_to_publication(
1818 p_publication_id BIGINT,
1819 p_author_id BIGINT
1820)
1821LANGUAGE plpgsql
1822AS $$
1823BEGIN
1824 IF EXISTS (
1825 SELECT 1
1826 FROM Publication_Authors
1827 WHERE publication_id = p_publication_id
1828 AND author_id = p_author_id
1829 ) THEN
1830 RAISE NOTICE 'Авторот веќе постои';
1831 RETURN;
1832 END IF;
1833
1834 INSERT INTO Publication_Authors(publication_id, author_id)
1835 VALUES (p_publication_id, p_author_id);
1836END;
1837$$;
1838
1839-- TRIGGER 3 – спречување публикација без главен автор
1840CREATE OR REPLACE FUNCTION trg_pub_author_check()
1841RETURNS TRIGGER AS $$
1842BEGIN
1843 IF NEW.main_author_id IS NULL THEN
1844 RAISE EXCEPTION 'Публикацијата мора да има главен автор';
1845 END IF;
1846
1847 RETURN NEW;
1848END;
1849$$ LANGUAGE plpgsql;
1850
1851CREATE TRIGGER trg_publication_check
1852BEFORE INSERT OR UPDATE ON Publications
1853FOR EACH ROW
1854EXECUTE FUNCTION trg_pub_author_check();
1855
1856-- FUNCTION 4 – автоматска проценка на “важност” на објект
1857CREATE OR REPLACE FUNCTION object_importance(p_object_id BIGINT)
1858RETURNS INT AS $$
1859DECLARE
1860 v_treatments INT;
1861 v_publications INT;
1862BEGIN
1863 SELECT COUNT(*) INTO v_treatments
1864 FROM Treatments
1865 WHERE object_id = p_object_id;
1866
1867 SELECT COUNT(*) INTO v_publications
1868 FROM Object_Publication
1869 WHERE object_id = p_object_id;
1870 RETURN (v_treatments * 2) + (v_publications * 3);
1871END;
1872$$ LANGUAGE plpgsql;
1873
1874
1875-- TRIGGER 4 + FUNCTION – автоматско поставување статус на фрагмент
1876CREATE OR REPLACE FUNCTION trg_auto_fragment_status()
1877RETURNS TRIGGER AS $$
1878BEGIN
1879 IF NEW.object_id IS NOT NULL THEN
1880 NEW.status_id := 1;
1881 END IF;
1882
1883 RETURN NEW;
1884END;
1885$$ LANGUAGE plpgsql;
1886
1887CREATE TRIGGER trg_fragment_auto_status
1888BEFORE INSERT ON Fragments
1889FOR EACH ROW
1890EXECUTE FUNCTION trg_auto_fragment_status();
1891
1892
1893-- Тригер кој проверува дека conservation_project_id во Researcher_Access
1894-- се однесува на истиот object_id наведен во барањето за пристап
1895-- Без оваа проверка, може да се внесе логички неконзистентен запис каде
1896-- истражувачот бара пристап до еден артефакт, но наведува проект кој
1897-- припаѓа на сосема друг предмет. Бидејќи ова правило бара споредба
1898-- на вредности од две различни табели истовремено, не може да се
1899-- спроведе со стандарден FOREIGN KEY constraint — затоа се користи тригер.
1900
1901
1902CREATE OR REPLACE FUNCTION trg_validate_project_object_match()
1903RETURNS TRIGGER AS $$
1904DECLARE
1905 v_project_object_id BIGINT;
1906BEGIN
1907 -- Ако нема поврзан проект, нема што да се проверува
1908 IF NEW.conservation_project_id IS NULL THEN
1909 RETURN NEW;
1910 END IF;
1911
1912 -- Го наоѓаме object_id на проектот од Conservation_Projects
1913 SELECT object_id
1914 INTO v_project_object_id
1915 FROM Conservation_Projects
1916 WHERE project_id = NEW.conservation_project_id;
1917
1918 -- Споредуваме: дали проектот навистина го покрива бараниот артефакт
1919 IF v_project_object_id <> NEW.object_id THEN
1920 RAISE EXCEPTION 'Конзерваторскиот проект % не припаѓа на објектот %. Пристапот е одбиен.',
1921 NEW.conservation_project_id, NEW.object_id;
1922 END IF;
1923
1924 RETURN NEW;
1925END;
1926$$ LANGUAGE plpgsql;
1927
1928CREATE TRIGGER trg_researcher_access_project_match
1929BEFORE INSERT OR UPDATE ON Researcher_Access
1930FOR EACH ROW
1931EXECUTE FUNCTION trg_validate_project_object_match();
1932
1933-- function - додавање нов објект кој го нашол и каде
1934CREATE OR REPLACE FUNCTION find_object_details(p_object_id BIGINT)
1935RETURNS TABLE (
1936 object_id BIGINT,
1937 title TEXT,
1938 found_by TEXT,
1939 site_name TEXT
1940) AS $$
1941BEGIN
1942 RETURN QUERY
1943 SELECT
1944 o.object_id,
1945 o.title,
1946 u.full_name,
1947 s.site_name
1948 FROM Objects o
1949 LEFT JOIN Users u ON o.found_by_user_id = u.user_id
1950 JOIN Sites s ON o.site_id = s.site_id
1951 WHERE o.object_id = p_object_id;
1952END;
1953$$ LANGUAGE plpgsql;
1954
1955-- procedure - додавање нов објект кој го нашол и каде
1956CREATE OR REPLACE PROCEDURE add_new_object(
1957 p_inventory VARCHAR,
1958 p_title VARCHAR,
1959 p_status_id BIGINT,
1960 p_site_id BIGINT,
1961 p_user_id BIGINT
1962)
1963LANGUAGE plpgsql
1964AS $$
1965BEGIN
1966 INSERT INTO Objects(
1967 inventory_number,
1968 title,
1969 current_status_id,
1970 site_id,
1971 found_by_user_id
1972 )
1973 VALUES (
1974 p_inventory,
1975 p_title,
1976 p_status_id,
1977 p_site_id,
1978 p_user_id
1979 );
1980END;
1981$$;
1982
1983
1984--додава нов објект + категорија + култура + материјал
1985CREATE OR REPLACE PROCEDURE catalog_object(
1986 p_inventory VARCHAR,
1987 p_title VARCHAR,
1988 p_status_id BIGINT,
1989 p_site_id BIGINT,
1990 p_user_id BIGINT,
1991 p_category_id BIGINT,
1992 p_culture_id BIGINT,
1993 p_material_id BIGINT
1994)
1995LANGUAGE plpgsql
1996AS $$
1997DECLARE
1998 v_object_id BIGINT;
1999BEGIN
2000 INSERT INTO Objects(
2001 inventory_number,
2002 title,
2003 current_status_id,
2004 site_id,
2005 found_by_user_id
2006 )
2007 VALUES (
2008 p_inventory,
2009 p_title,
2010 p_status_id,
2011 p_site_id,
2012 p_user_id
2013 )
2014 RETURNING object_id INTO v_object_id;
2015
2016 INSERT INTO Object_Classification(
2017 object_id,
2018 category_id,
2019 culture_id
2020 )
2021 VALUES (
2022 v_object_id,
2023 p_category_id,
2024 p_culture_id
2025 );
2026
2027 INSERT INTO Materials_Objects(
2028 object_id,
2029 material_id
2030 )
2031 VALUES (
2032 v_object_id,
2033 p_material_id
2034 );
2035
2036END;
2037$$;
2038