DatabaseCreation: ddl.sql

File ddl.sql, 66.9 KB (added by 231511, 5 days ago)
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
1212
1213CREATE INDEX IF NOT EXISTS idx_objects_site_id ON Objects(site_id);
1214CREATE INDEX IF NOT EXISTS idx_fragments_site_id ON Fragments(site_id);
1215
1216CREATE OR REPLACE VIEW Heritage_Full_Overview AS
1217SELECT
1218 f.fragment_id,
1219 f.description AS fragment_description,
1220 o.title AS object_title,
1221 s.site_id,
1222 s.site_name,
1223 r.name AS region,
1224 ps.name AS protection_status
1225FROM Fragments f
1226JOIN Objects o ON f.object_id = o.object_id
1227JOIN Sites s ON f.site_id = s.site_id
1228JOIN Regions r ON s.region_id = r.region_id
1229JOIN Protection_Status ps ON s.protection_status_id = ps.protection_status_id;
1230
1231SELECT * FROM Heritage_Full_Overview LIMIT 100;
1232
1233-- INSERT
1234INSERT INTO Fragments (
1235 description,
1236 site_id,
1237 object_id,
1238 status_id,
1239 found_by_user_id,
1240 discovery_date
1241)
1242SELECT
1243 'Нов фрагмент',
1244 1,
1245 object_id,
1246 1,
1247 1,
1248 CURRENT_DATE
1249FROM Objects
1250LIMIT 1;
1251
1252-- UPDATE
1253UPDATE Fragments
1254SET description = 'Ажуриран фрагмент'
1255WHERE fragment_id = (
1256 SELECT fragment_id
1257 FROM Fragments
1258 LIMIT 1
1259);
1260
1261--podeleni spored lokalitet
1262
1263
1264create OR replace VIEW Site_Statistics AS
1265SELECT
1266 s.site_id,
1267 s.site_name,
1268 r.name AS region,
1269 COALESCE(o_counts.total_objects, 0) AS total_objects,
1270 COALESCE(f_counts.total_fragments, 0) AS total_fragments,
1271 (CURRENT_DATE - (floor(random() * 3650) * interval '1 day'))::timestamp AS last_checked_at
1272FROM Sites s
1273JOIN Regions r ON s.region_id = r.region_id
1274LEFT JOIN (
1275 SELECT site_id, COUNT(*) AS total_objects
1276 FROM Objects
1277 GROUP BY site_id
1278) o_counts ON s.site_id = o_counts.site_id
1279LEFT JOIN (
1280 SELECT site_id, COUNT(*) AS total_fragments
1281 FROM Fragments
1282 GROUP BY site_id
1283) f_counts ON s.site_id = f_counts.site_id;
1284
1285SELECT
1286 relname AS table_name,
1287 pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
1288 pg_size_pretty(pg_relation_size(relid)) AS data_size,
1289 pg_size_pretty(pg_total_relation_size(relid) - pg_relation_size(relid)) AS index_size
1290FROM pg_catalog.pg_statio_user_tables
1291WHERE relname IN ('fragments', 'objects', 'sites');
1292
1293CREATE INDEX idx_objects_site_id
1294ON Objects(site_id);
1295
1296CREATE INDEX idx_fragments_site_id
1297ON Fragments(site_id);
1298
1299select * from site_statistics where site_id=39568;
1300
1301SELECT *
1302FROM Site_Statistics
1303limit 50;
1304
1305
1306
1307-- INSERT
1308INSERT INTO Sites (site_name, site_type_id, region_id, protection_status_id, latitude, longitude, discovery_year)
1309VALUES ('Локалитет 11001', 1, 1, 1, 41.3, 21.7, 2001);
1310
1311-- UPDATE
1312UPDATE Sites
1313SET discovery_year = 2002
1314WHERE site_id = 100;
1315
1316
1317--zastiteni lokaliteti
1318CREATE OR REPLACE VIEW Protected_Sites_Inventory AS
1319SELECT
1320 s.site_id,
1321 s.site_name,
1322 r.name AS region,
1323 s.discovery_year,
1324 COALESCE(o.total_objects_count, 0) AS total_objects_count
1325FROM Sites s
1326JOIN Regions r
1327 ON s.region_id = r.region_id
1328JOIN Protection_Status ps
1329 ON s.protection_status_id = ps.protection_status_id
1330LEFT JOIN (
1331 SELECT site_id, COUNT(*) AS total_objects_count
1332 FROM Objects
1333 GROUP BY site_id
1334) o
1335 ON s.site_id = o.site_id
1336WHERE ps.name = 'Заштитен'
1337ORDER BY s.discovery_year DESC;
1338
1339SELECT * FROM Protected_Sites_Inventory limit 50;
1340
1341
1342--insert
1343INSERT INTO Objects (inventory_number, title, current_status_id, site_id)
1344VALUES ('INV-9999999', 'Test object', 1, 100);
1345
1346-- UPDATE
1347UPDATE Objects
1348SET title = 'UPDATED TEST OBJECT'
1349WHERE inventory_number = 'INV-9999999';
1350
1351--spored materijali se prebaruva
1352CREATE OR REPLACE VIEW Objects_with_Materials AS
1353SELECT
1354 o.object_id,
1355 o.title,
1356 m.name AS material
1357FROM Objects o
1358LEFT JOIN Materials_Objects om
1359 ON o.object_id = om.object_id
1360LEFT JOIN Materials m
1361 ON om.material_id = m.material_id;
1362
1363SELECT * FROM Objects_with_Materials;
1364
1365-- UPDATE
1366UPDATE Materials_Objects
1367SET material_id = 2
1368WHERE object_id = 1000;
1369
1370
1371-- kade se naogaat vo koj lokalitet momentalno
1372CREATE OR REPLACE VIEW Object_Current_Location AS
1373SELECT
1374 o.object_id,
1375 o.title,
1376 i.name AS institution
1377FROM Objects o
1378JOIN Object_Location_History olh ON olh.object_id = o.object_id
1379JOIN Institutions i ON i.institution_id = olh.institution_id
1380WHERE olh.end_date IS NULL;
1381
1382
1383SELECT * FROM Object_Current_Location limit 50;
1384
1385
1386
1387-- INSERT
1388INSERT INTO Object_Location_History (object_id, institution_id, start_date)
1389VALUES (809042, 1, CURRENT_DATE);
1390
1391-- UPDATE
1392UPDATE Object_Location_History
1393SET end_date = CURRENT_DATE
1394WHERE object_id = 809042
1395 AND end_date IS NULL;
1396
1397
1398--na koja kultura pripaga
1399CREATE OR REPLACE VIEW Object_with_Culture AS
1400SELECT
1401 o.object_id,
1402 o.title,
1403 c.name AS culture,
1404 cat.name AS category
1405FROM Objects o
1406JOIN Object_Classification oc ON oc.object_id = o.object_id
1407JOIN Culture c ON c.culture_id = oc.culture_id
1408JOIN Categories cat ON cat.category_id = oc.category_id;
1409
1410
1411SELECT * FROM Object_with_Culture limit 50;
1412
1413-- INSERT
1414INSERT INTO Object_Classification (object_id, category_id, culture_id)
1415VALUES (1649219, 1, 1);
1416
1417-- UPDATE
1418UPDATE Object_Classification
1419SET category_id = 2
1420WHERE object_id = 1649219;
1421
1422--koi predmeti na koi izlozbi
1423
1424CREATE OR REPLACE VIEW Exhibition_Objects AS
1425SELECT
1426 e.exhibition_id,
1427 e.name AS exhibition,
1428 o.object_id,
1429 o.title AS object,
1430 i.name AS institution
1431FROM Object_Exhibition oe
1432JOIN Exhibitions e ON e.exhibition_id = oe.exhibition_id
1433JOIN Objects o ON o.object_id = oe.object_id
1434JOIN Institutions i ON i.institution_id = e.location_institution_id;
1435
1436
1437SELECT * FROM Exhibition_Objects limit 50;
1438
1439
1440-- INSERT
1441INSERT INTO Object_Exhibition (object_id, exhibition_id)
1442VALUES (
1443 (SELECT MAX(object_id) FROM Objects),
1444 (SELECT MAX(exhibition_id) FROM Exhibitions)
1445);
1446
1447-- UPDATE
1448UPDATE Object_Exhibition
1449SET exhibition_id = 3
1450WHERE object_id = (
1451 SELECT MAX(object_id) FROM Object_Exhibition
1452)
1453AND exhibition_id = (
1454 SELECT MAX(exhibition_id) FROM Object_Exhibition
1455);
1456
1457
1458--koj naucnik ili istrazuvas pobaral da istrazuva predmet dali mu e odobreno momentalno
1459
1460CREATE OR REPLACE VIEW Research_Access_Details AS
1461SELECT
1462 ra.user_id,
1463 u.full_name,
1464 ra.object_id,
1465 o.title AS object,
1466 i.name AS institution,
1467 s.status_name AS access_status,
1468 ra.access_date
1469FROM Researcher_Access ra
1470JOIN Users u ON u.user_id = ra.user_id
1471JOIN Objects o ON o.object_id = ra.object_id
1472JOIN Institutions i ON i.institution_id = ra.institution_id
1473JOIN Status_Types s ON s.status_id = ra.access_status_id
1474WHERE s.type = 'access';
1475
1476SELECT * FROM Research_Access_Details limit 100;
1477
1478
1479INSERT INTO Researcher_Access (
1480 access_date, access_status_id, user_id, object_id, institution_id
1481)
1482SELECT
1483 CURRENT_DATE,
1484 6,
1485 user_id,
1486 object_id,
1487 1
1488FROM Users u
1489JOIN Objects o ON o.object_id = u.user_id
1490LIMIT 1;
1491
1492
1493UPDATE Researcher_Access
1494SET access_status_id = 7
1495WHERE user_id = 1000
1496AND object_id = 1000;
1497
1498--tretmani vrz odreden objekt
1499
1500CREATE OR REPLACE VIEW Treatment_History AS
1501SELECT
1502 t.object_id,
1503 o.title,
1504 t.treatment_date,
1505 tsl.step_number,
1506 tsl.step_description,
1507 u.full_name
1508FROM Treatments t
1509JOIN Objects o ON o.object_id = t.object_id
1510JOIN Treatment_Step_Log tsl ON tsl.treatment_id = t.treatment_id
1511JOIN Users u ON u.user_id = tsl.performed_by_user;
1512
1513SELECT * FROM Treatment_History limit 100;
1514
1515
1516-- INSERT
1517INSERT INTO Treatments (object_id, treatment_date, description)
1518SELECT object_id, CURRENT_DATE, 'Test treatment'
1519FROM Objects
1520WHERE object_id BETWEEN 1 AND 10
1521LIMIT 1;
1522
1523-- UPDATE
1524UPDATE Treatments
1525SET description = 'Update treatment',
1526 treatment_date = CURRENT_DATE
1527WHERE object_id = (
1528 SELECT object_id
1529 FROM Objects
1530 WHERE object_id BETWEEN 1 AND 10
1531 LIMIT 1
1532)
1533AND description = 'Test treatment';
1534
1535
1536--koj avtor koi publikacii gi napravil
1537
1538CREATE OR REPLACE VIEW Publications_with_Authors AS
1539SELECT
1540 pa.publication_id,
1541 p.title,
1542 a.full_name AS author
1543FROM Publication_Authors pa
1544JOIN Publications p ON p.publication_id = pa.publication_id
1545JOIN Authors a ON a.author_id = pa.author_id;
1546
1547
1548SELECT * FROM Publications_with_Authors limit 100;
1549
1550-- INSERT
1551INSERT INTO Publication_Authors (publication_id, author_id)
1552VALUES (2, 50000);
1553
1554UPDATE Publication_Authors
1555SET author_id = 49999
1556WHERE publication_id = 2
1557 AND author_id = 50000;
1558
1559
1560
1561-- function - додавање нов објект кој го нашол и каде
1562CREATE OR REPLACE FUNCTION find_object_details(p_object_id BIGINT)
1563RETURNS TABLE (
1564 object_id BIGINT,
1565 title TEXT,
1566 found_by TEXT,
1567 site_name TEXT
1568) AS $$
1569BEGIN
1570 RETURN QUERY
1571 SELECT
1572 o.object_id,
1573 o.title::TEXT,
1574 u.full_name::TEXT,
1575 s.site_name::TEXT
1576 FROM Objects o
1577 LEFT JOIN Users u ON o.found_by_user_id = u.user_id
1578 JOIN Sites s ON o.site_id = s.site_id
1579 WHERE o.object_id = p_object_id;
1580END;
1581$$ LANGUAGE plpgsql;
1582
1583SELECT * FROM find_object_details(804822);
1584
1585
1586-- procedure - додавање нов објект кој го нашол и каде
1587CREATE OR REPLACE PROCEDURE add_new_object(
1588 p_inventory VARCHAR,
1589 p_title VARCHAR,
1590 p_status_id BIGINT,
1591 p_site_id BIGINT,
1592 p_user_id BIGINT
1593)
1594LANGUAGE plpgsql
1595AS $$
1596BEGIN
1597 INSERT INTO Objects(
1598 inventory_number,
1599 title,
1600 current_status_id,
1601 site_id,
1602 found_by_user_id
1603 )
1604 VALUES (
1605 p_inventory,
1606 p_title,
1607 p_status_id,
1608 p_site_id,
1609 p_user_id
1610 );
1611END;
1612$$;
1613
1614CALL add_new_object(
1615 'INV997',
1616 'Test Object',
1617 1,
1618 1,
1619 10
1620);
1621
1622SELECT *
1623FROM Objects
1624WHERE inventory_number = 'INV997';
1625
1626
1627--додава нов објект + категорија + култура + материјал
1628CREATE OR REPLACE PROCEDURE catalog_object(
1629 p_inventory VARCHAR,
1630 p_title VARCHAR,
1631 p_status_id BIGINT,
1632 p_site_id BIGINT,
1633 p_user_id BIGINT,
1634 p_category_id BIGINT,
1635 p_culture_id BIGINT,
1636 p_material_id BIGINT
1637)
1638LANGUAGE plpgsql
1639AS $$
1640DECLARE
1641 v_object_id BIGINT;
1642BEGIN
1643 INSERT INTO Objects(
1644 inventory_number,
1645 title,
1646 current_status_id,
1647 site_id,
1648 found_by_user_id
1649 )
1650 VALUES (
1651 p_inventory,
1652 p_title,
1653 p_status_id,
1654 p_site_id,
1655 p_user_id
1656 )
1657 RETURNING object_id INTO v_object_id;
1658
1659 INSERT INTO Object_Classification(object_id, category_id, culture_id)
1660 VALUES (v_object_id, p_category_id, p_culture_id);
1661
1662 INSERT INTO Materials_Objects(object_id, material_id)
1663 VALUES (v_object_id, p_material_id);
1664END;
1665$$;
1666
1667CALL catalog_object(
1668 'INV888',
1669 'Full Object',
1670 1,
1671 1,
1672 10,
1673 1,
1674 1,
1675 1
1676);
1677
1678SELECT *
1679FROM Objects
1680WHERE inventory_number = 'INV888';
1681
1682SELECT *
1683FROM Object_Classification
1684WHERE object_id = 2804830;
1685
1686SELECT *
1687FROM Materials_Objects
1688WHERE object_id = 2804830;
1689
1690
1691--FUNCTION 1 – проверка дали објект е валиден за работа
1692CREATE OR REPLACE FUNCTION is_object_available(p_object_id BIGINT)
1693RETURNS BOOLEAN AS $$
1694DECLARE v_status BIGINT;
1695BEGIN
1696 SELECT current_status_id
1697 INTO v_status
1698 FROM Objects
1699 WHERE object_id = p_object_id;
1700
1701 IF NOT FOUND THEN
1702 RETURN FALSE;
1703 END IF;
1704
1705 IF v_status = 3 THEN
1706 RETURN FALSE;
1707 END IF;
1708
1709 RETURN TRUE;
1710END;
1711$$ LANGUAGE plpgsql;
1712
1713SELECT is_object_available(804822);
1714
1715
1716-- PROCEDURE 1 – додавање третман само ако објект е дозволен
1717CREATE OR REPLACE PROCEDURE add_treatment(
1718 p_object_id BIGINT,
1719 p_desc TEXT
1720)
1721LANGUAGE plpgsql
1722AS $$
1723DECLARE v_status BIGINT;
1724BEGIN
1725 SELECT current_status_id INTO v_status
1726 FROM Objects
1727 WHERE object_id = p_object_id;
1728
1729 IF NOT FOUND OR v_status = 3 THEN
1730 RAISE EXCEPTION 'Објектот не е достапен за третман';
1731 END IF;
1732
1733 INSERT INTO Treatments(object_id, treatment_date, description)
1734 VALUES (p_object_id, CURRENT_DATE, p_desc);
1735END;
1736$$;
1737
1738CALL add_treatment(804822, 'Basic treatment');
1739SELECT *
1740FROM Treatments
1741WHERE object_id = 804822
1742ORDER BY treatment_id DESC;
1743
1744
1745--додавање третман + кој работел на него
1746CREATE OR REPLACE FUNCTION add_treatment(
1747 p_object_id BIGINT,
1748 p_description TEXT,
1749 p_user_id BIGINT
1750)
1751RETURNS VOID AS $$
1752DECLARE
1753 v_treatment_id BIGINT;
1754BEGIN
1755 INSERT INTO Treatments(object_id, treatment_date, description)
1756 VALUES (p_object_id, CURRENT_DATE, p_description)
1757 RETURNING treatment_id INTO v_treatment_id;
1758
1759 INSERT INTO Treatment_Step_Log(
1760 treatment_id,
1761 step_number,
1762 step_description,
1763 performed_by_user
1764 )
1765 VALUES (
1766 v_treatment_id,
1767 1,
1768 'Initial treatment',
1769 p_user_id
1770 );
1771END;
1772$$ LANGUAGE plpgsql;
1773
1774SELECT add_treatment(804822, 'Cleaning treatment', 10);
1775SELECT *
1776FROM Treatments
1777WHERE object_id = 804822
1778ORDER BY treatment_id DESC;
1779
1780
1781-- TRIGGER 1 – автоматско спречување „лоши фрагменти“
1782CREATE OR REPLACE FUNCTION trg_fragment_validation()
1783RETURNS TRIGGER AS $$
1784BEGIN
1785 IF NEW.object_id IS NOT NULL AND NEW.parent_fragment_id IS NOT NULL THEN
1786 RAISE EXCEPTION 'Фрагмент не може да има и object и parent';
1787 END IF;
1788
1789 RETURN NEW;
1790END;
1791$$ LANGUAGE plpgsql;
1792
1793
1794
1795INSERT INTO Fragments (object_id, parent_fragment_id, status_id)
1796VALUES (1, 2, 1);
1797
1798INSERT INTO Fragments (
1799 fragment_id,
1800 site_id,
1801 object_id,
1802 status_id
1803)
1804VALUES (
1805 10500004,
1806 1,
1807 804822,
1808 1
1809);
1810
1811SELECT *
1812FROM Fragments
1813WHERE fragment_id = 10500004;
1814
1815
1816-- FUNCTION 2 – проверка на истражувачки пристап
1817CREATE OR REPLACE FUNCTION has_access(
1818 p_user_id BIGINT,
1819 p_object_id BIGINT
1820)
1821RETURNS BOOLEAN AS $$
1822BEGIN
1823 RETURN EXISTS (
1824 SELECT 1
1825 FROM Researcher_Access
1826 WHERE user_id = p_user_id
1827 AND object_id = p_object_id
1828 AND access_status_id = 6
1829 );
1830END;
1831$$ LANGUAGE plpgsql;
1832
1833SELECT has_access(10, 804822);
1834
1835
1836-- PROCEDURE 2 – барање за пристап
1837CREATE OR REPLACE PROCEDURE request_access(
1838 p_user_id BIGINT,
1839 p_object_id BIGINT,
1840 p_institution_id BIGINT
1841)
1842LANGUAGE plpgsql
1843AS $$
1844BEGIN
1845 INSERT INTO Researcher_Access(
1846 access_date,
1847 access_status_id,
1848 user_id,
1849 object_id,
1850 institution_id
1851 )
1852 VALUES (
1853 CURRENT_DATE,
1854 7, -- во обработка
1855 p_user_id,
1856 p_object_id,
1857 p_institution_id
1858 );
1859END;
1860$$;
1861
1862CALL request_access(10, 804822, 1);
1863
1864
1865SELECT *
1866FROM Researcher_Access
1867WHERE user_id = 10 AND object_id = 804822;
1868
1869UPDATE Researcher_Access
1870SET access_status_id = 6
1871WHERE user_id = 10 AND object_id = 804822;
1872
1873CALL request_access(10, 804822, 1);
1874
1875
1876
1877-- FUNCTION 3 – број на автори по публикација
1878CREATE OR REPLACE FUNCTION count_authors(p_publication_id BIGINT)
1879RETURNS INT AS $$
1880DECLARE v_count INT;
1881BEGIN
1882 SELECT COUNT(*)
1883 INTO v_count
1884 FROM Publication_Authors
1885 WHERE publication_id = p_publication_id;
1886
1887 RETURN v_count;
1888END;
1889$$ LANGUAGE plpgsql;
1890
1891SELECT count_authors(1);
1892SELECT count_authors(99999);
1893
1894-- PROCEDURE 3 – додавање автор во публикација (без дупликати)
1895CREATE OR REPLACE PROCEDURE add_author_to_publication(
1896 p_publication_id BIGINT,
1897 p_author_id BIGINT
1898)
1899LANGUAGE plpgsql
1900AS $$
1901BEGIN
1902 IF EXISTS (
1903 SELECT 1
1904 FROM Publication_Authors
1905 WHERE publication_id = p_publication_id
1906 AND author_id = p_author_id
1907 ) THEN
1908 RAISE NOTICE 'Авторот веќе постои';
1909 RETURN;
1910 END IF;
1911
1912 INSERT INTO Publication_Authors(publication_id, author_id)
1913 VALUES (p_publication_id, p_author_id);
1914END;
1915$$;
1916
1917CALL add_author_to_publication(1, 5);
1918CALL add_author_to_publication(1, 5);
1919
1920SELECT *
1921FROM Publication_Authors
1922WHERE publication_id = 1 AND author_id = 5;
1923
1924
1925-- FUNCTION 4 – автоматска проценка на “важност” на објект
1926CREATE OR REPLACE FUNCTION object_importance(p_object_id BIGINT)
1927RETURNS INT AS $$
1928DECLARE
1929 v_treatments INT;
1930 v_publications INT;
1931BEGIN
1932 SELECT COUNT(*) INTO v_treatments
1933 FROM Treatments
1934 WHERE object_id = p_object_id;
1935
1936 SELECT COUNT(*) INTO v_publications
1937 FROM Object_Publication
1938 WHERE object_id = p_object_id;
1939
1940 RETURN (v_treatments * 2) + (v_publications * 3);
1941END;
1942$$ LANGUAGE plpgsql;
1943
1944
1945SELECT object_importance(1940759);
1946SELECT object_importance(99999);
1947
1948SELECT *
1949FROM Treatments
1950LIMIT 10;
1951
1952SELECT *
1953FROM Object_Publication
1954LIMIT 10;
1955
1956-- Тригер кој проверува дека conservation_project_id во Researcher_Access
1957-- се однесува на истиот object_id наведен во барањето за пристап
1958-- Без оваа проверка, може да се внесе логички неконзистентен запис каде
1959-- истражувачот бара пристап до еден артефакт, но наведува проект кој
1960-- припаѓа на сосема друг предмет. Бидејќи ова правило бара споредба
1961-- на вредности од две различни табели истовремено, не може да се
1962-- спроведе со стандарден FOREIGN KEY constraint — затоа се користи тригер.
1963
1964
1965CREATE OR REPLACE FUNCTION trg_validate_project_object_match()
1966RETURNS TRIGGER AS $$
1967DECLARE
1968 v_project_object_id BIGINT;
1969BEGIN
1970 -- Ако нема поврзан проект, нема што да се проверува
1971 IF NEW.conservation_project_id IS NULL THEN
1972 RETURN NEW;
1973 END IF;
1974
1975 -- Го наоѓаме object_id на проектот од Conservation_Projects
1976 SELECT object_id
1977 INTO v_project_object_id
1978 FROM Conservation_Projects
1979 WHERE project_id = NEW.conservation_project_id;
1980
1981 -- Споредуваме: дали проектот навистина го покрива бараниот артефакт
1982 IF v_project_object_id <> NEW.object_id THEN
1983 RAISE EXCEPTION 'Конзерваторскиот проект % не припаѓа на објектот %. Пристапот е одбиен.',
1984 NEW.conservation_project_id, NEW.object_id;
1985 END IF;
1986
1987 RETURN NEW;
1988END;
1989$$ LANGUAGE plpgsql;
1990
1991SELECT object_id
1992FROM Conservation_Projects
1993WHERE project_id = 1;
1994
1995--valid
1996INSERT INTO Researcher_Access(
1997 access_date,
1998 access_status_id,
1999 user_id,
2000 object_id,
2001 institution_id,
2002 conservation_project_id
2003)
2004VALUES (
2005 CURRENT_DATE,
2006 7,
2007 10,
2008 1596278,
2009 1,
2010 1
2011);
2012
2013SELECT *
2014FROM Researcher_Access
2015WHERE user_id = 10
2016 AND object_id = 1596278
2017 AND conservation_project_id = 1;
2018
2019--invalid
2020INSERT INTO Researcher_Access(
2021 access_date,
2022 access_status_id,
2023 user_id,
2024 object_id,
2025 institution_id,
2026 conservation_project_id
2027)
2028VALUES (
2029 CURRENT_DATE,
2030 7,
2031 10,
2032 100,
2033 1,
2034 9999
2035);
2036
2037CREATE TRIGGER trg_researcher_access_project_match
2038BEFORE INSERT OR UPDATE ON Researcher_Access
2039FOR EACH ROW
2040EXECUTE FUNCTION trg_validate_project_object_match();
2041
2042
2043CREATE TRIGGER trg_fragment_check
2044BEFORE INSERT OR UPDATE ON Fragments
2045FOR EACH ROW
2046EXECUTE FUNCTION trg_fragment_validation();
2047
2048
2049SELECT schemaname, tablename, indexname
2050FROM pg_indexes
2051WHERE indexname LIKE 'idx_%'
2052ORDER BY tablename;
2053
2054