CREATE SCHEMA IF NOT EXISTS institutions; CREATE EXTENSION IF NOT EXISTS "pgcrypto"; CREATE EXTENSION IF NOT EXISTS "pg_trgm"; CREATE OR REPLACE FUNCTION institutions.update_lastupdated_timestamp() RETURNS TRIGGER AS $$ BEGIN NEW.last_updated_at = now(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TABLE institutions.country ( country_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), iso_code VARCHAR NOT NULL, name_english VARCHAR NOT NULL, name_official VARCHAR, name_short VARCHAR, publicated BOOLEAN NOT NULL, hidden BOOLEAN, country_group VARCHAR NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.location ( location_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id_original VARCHAR NOT NULL, country_id UUID NOT NULL REFERENCES institutions.country(country_id), origin_name VARCHAR NOT NULL, name_short VARCHAR, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.institution_type ( institution_type_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name_short VARCHAR, status VARCHAR CHECK (status IN ('H +', 'H -', 'H +/-')), comment TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.institution ( institution_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id_original VARCHAR NOT NULL, country_id UUID NOT NULL REFERENCES institutions.country(country_id), location_id UUID REFERENCES institutions.location(location_id), institution_type_id UUID NOT NULL REFERENCES institutions.institution_type(institution_type_id), name_short VARCHAR, abbreviation VARCHAR, homepage VARCHAR, name_german VARCHAR, address_street VARCHAR, address_zip VARCHAR, address_city VARCHAR, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.degree_type ( degree_type_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id_original VARCHAR NOT NULL, country_id UUID NOT NULL REFERENCES institutions.country(country_id), name_short VARCHAR, name_german VARCHAR, name_female VARCHAR, name_female_german VARCHAR, comment TEXT, hide_requirement BOOLEAN, requirement TEXT, additional_requirement TEXT, hide_studies BOOLEAN, studies_min_length FLOAT, studies_max_length FLOAT, explanation_studies_length TEXT, studies_description TEXT, abbreviation VARCHAR, abbreviation_female VARCHAR, degree_class VARCHAR CHECK (degree_class IN ('A1', 'A2', 'A3', 'A4', 'A5', 'PGS', 'NZ', 'D1', 'D2', 'HC')), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.degree_type_equivalence ( degree_type_equivalence_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id_original VARCHAR NOT NULL, degree_type_id UUID NOT NULL REFERENCES institutions.degree_type(degree_type_id), hidden BOOLEAN, equivalence_class VARCHAR NOT NULL, comment TEXT, admin_comment TEXT, internal_comment TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.degree_field_of_study ( degree_field_of_study_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id_original VARCHAR NOT NULL, country_id UUID NOT NULL REFERENCES institutions.country(country_id), name_short VARCHAR, name_german VARCHAR, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.degree ( degree_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id_original VARCHAR NOT NULL, country_id UUID NOT NULL REFERENCES institutions.country(country_id), degree_type_id UUID REFERENCES institutions.degree_type(degree_type_id), field_of_study_id UUID REFERENCES institutions.degree_field_of_study(degree_field_of_study_id), degree_short VARCHAR, name_short VARCHAR, name_german VARCHAR, name_female VARCHAR, name_female_german VARCHAR, comment TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.alias_name ( alias_name_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), type VARCHAR NOT NULL CHECK (type IN ('alias', 'alternative', 'outdated')), id_original VARCHAR NOT NULL, name_short VARCHAR, name_german VARCHAR, comment TEXT, hidden BOOLEAN, deleted BOOLEAN, language_id VARCHAR, name_translated VARCHAR, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.entity_name_link ( entity_type VARCHAR NOT NULL CHECK (entity_type IN ('degree', 'institution', 'location', 'degree_type')), entity_id UUID NOT NULL, name_id UUID NOT NULL REFERENCES institutions.alias_name(alias_name_id), name_type VARCHAR NOT NULL CHECK (name_type IN ('alias', 'alternative', 'outdated')), PRIMARY KEY (entity_type, entity_id, name_id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.institution_degree ( institution_id UUID REFERENCES institutions.institution(institution_id), degree_id UUID REFERENCES institutions.degree(degree_id), PRIMARY KEY (institution_id, degree_id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.degree_equivalence ( degree_id UUID REFERENCES institutions.degree(degree_id), equivalence_id UUID REFERENCES institutions.degree_type_equivalence(degree_type_equivalence_id), PRIMARY KEY (degree_id, equivalence_id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE institutions.degree_type_equivalence_link ( degree_type_id UUID REFERENCES institutions.degree_type(degree_type_id), equivalence_id UUID REFERENCES institutions.degree_type_equivalence(degree_type_equivalence_id), PRIMARY KEY (degree_type_id, equivalence_id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); DO $$ DECLARE tbl TEXT; BEGIN FOR tbl IN SELECT table_name FROM information_schema.columns WHERE column_name = 'last_updated_at' AND table_schema = 'app' LOOP EXECUTE format(' DROP TRIGGER IF EXISTS trg_update_last_updated_at ON institutions.%I; CREATE TRIGGER trg_update_last_updated_at BEFORE UPDATE ON institutions.%I FOR EACH ROW EXECUTE FUNCTION institutions.update_lastupdated_timestamp();', tbl, tbl ); END LOOP; END $$; -- Drop and recreate institution_search CREATE OR REPLACE VIEW institutions.institution_search AS SELECT i.institution_id, i.name_short AS main_name_short, i.name_german AS main_name_german, a.name_short AS alias_name_short, a.name_german AS alias_name_german, a.type AS alias_type, it.status AS institution_status, GREATEST( similarity(i.name_short, ''), similarity(i.name_german, ''), similarity(a.name_short, ''), similarity(a.name_german, '') ) AS match_score FROM institutions.institution i LEFT JOIN institutions.entity_name_link enl ON enl.entity_type = 'institution' AND enl.entity_id = i.institution_id LEFT JOIN institutions.alias_name a ON enl.name_id = a.alias_name_id LEFT JOIN institutions.institution_type it ON i.institution_type_id = it.institution_type_id; -- Drop and recreate degree_search CREATE OR REPLACE VIEW institutions.degree_search AS SELECT d.degree_id, d.name_short AS main_name_short, d.name_german AS main_name_german, a.name_short AS alias_name_short, a.name_german AS alias_name_german, a.type AS alias_type, GREATEST( similarity(d.name_short, ''), similarity(d.name_german, ''), similarity(a.name_short, ''), similarity(a.name_german, '') ) AS match_score FROM institutions.degree d LEFT JOIN institutions.entity_name_link enl ON enl.entity_type = 'degree' AND enl.entity_id = d.degree_id LEFT JOIN institutions.alias_name a ON enl.name_id = a.alias_name_id; CREATE INDEX idx_inst_name_short_trgm ON institutions.institution USING gin (name_short gin_trgm_ops); CREATE INDEX idx_inst_name_german_trgm ON institutions.institution USING gin (name_german gin_trgm_ops); CREATE INDEX idx_alias_name_short_trgm ON institutions.alias_name USING gin (name_short gin_trgm_ops); CREATE INDEX idx_alias_name_german_trgm ON institutions.alias_name USING gin (name_german gin_trgm_ops);