-- Database schema for Music Band Information System -- Create sequences for auto-generated IDs CREATE SEQUENCE IF NOT EXISTS coordinates_seq START 1; CREATE SEQUENCE IF NOT EXISTS location_seq START 1; CREATE SEQUENCE IF NOT EXISTS album_seq START 1; CREATE SEQUENCE IF NOT EXISTS person_seq START 1; CREATE SEQUENCE IF NOT EXISTS music_band_seq START 1; -- Create tables CREATE TABLE IF NOT EXISTS coordinates ( id BIGINT PRIMARY KEY DEFAULT nextval('coordinates_seq'), x BIGINT NOT NULL, y INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS location ( id BIGINT PRIMARY KEY DEFAULT nextval('location_seq'), x INTEGER NOT NULL, y DOUBLE PRECISION NOT NULL, z INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS album ( id BIGINT PRIMARY KEY DEFAULT nextval('album_seq'), name VARCHAR(255) NOT NULL CHECK (name <> ''), tracks BIGINT NOT NULL CHECK (tracks > 0) ); CREATE TABLE IF NOT EXISTS person ( id BIGINT PRIMARY KEY DEFAULT nextval('person_seq'), name VARCHAR(255) NOT NULL CHECK (name <> ''), eye_color VARCHAR(20) NOT NULL CHECK (eye_color IN ('GREEN', 'BLUE', 'BROWN')), hair_color VARCHAR(20) CHECK (hair_color IN ('GREEN', 'BLUE', 'BROWN')), location_id BIGINT REFERENCES location(id) ON DELETE CASCADE, height DOUBLE PRECISION NOT NULL CHECK (height > 0), nationality VARCHAR(20) NOT NULL CHECK (nationality IN ('INDIA', 'THAILAND', 'SOUTH_KOREA', 'NORTH_KOREA')) ); CREATE TABLE IF NOT EXISTS music_band ( id BIGINT PRIMARY KEY DEFAULT nextval('music_band_seq'), name VARCHAR(255) NOT NULL CHECK (name <> ''), coordinates_id BIGINT NOT NULL REFERENCES coordinates(id) ON DELETE CASCADE, creation_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, genre VARCHAR(30) NOT NULL CHECK (genre IN ('ROCK', 'PSYCHEDELIC_CLOUD_RAP', 'JAZZ')), number_of_participants BIGINT NOT NULL CHECK (number_of_participants > 0), singles_count INTEGER NOT NULL CHECK (singles_count > 0), description TEXT, best_album_id BIGINT REFERENCES album(id) ON DELETE SET NULL, albums_count INTEGER CHECK (albums_count IS NULL OR albums_count > 0), establishment_date TIMESTAMP WITH TIME ZONE NOT NULL, front_man_id BIGINT REFERENCES person(id) ON DELETE SET NULL ); -- Create indexes for better performance CREATE INDEX IF NOT EXISTS idx_music_band_name ON music_band(name); CREATE INDEX IF NOT EXISTS idx_music_band_genre ON music_band(genre); CREATE INDEX IF NOT EXISTS idx_music_band_participants ON music_band(number_of_participants); CREATE INDEX IF NOT EXISTS idx_music_band_establishment_date ON music_band(establishment_date); -- Database functions for special operations CREATE OR REPLACE FUNCTION calculate_average_albums_count() RETURNS DOUBLE PRECISION AS $$ BEGIN RETURN (SELECT AVG(albums_count) FROM music_band WHERE albums_count IS NOT NULL); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION find_band_with_max_name() RETURNS TABLE(id BIGINT, name VARCHAR(255)) AS $$ BEGIN RETURN QUERY SELECT mb.id, mb.name FROM music_band mb WHERE mb.name = (SELECT MAX(mb2.name) FROM music_band mb2) LIMIT 1; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION group_bands_by_participants() RETURNS TABLE(participants BIGINT, band_count BIGINT) AS $$ BEGIN RETURN QUERY SELECT mb.number_of_participants, COUNT(*)::BIGINT FROM music_band mb GROUP BY mb.number_of_participants ORDER BY mb.number_of_participants; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION add_single_to_band(band_id BIGINT) RETURNS VOID AS $$ BEGIN UPDATE music_band SET singles_count = singles_count + 1 WHERE id = band_id; IF NOT FOUND THEN RAISE EXCEPTION 'Band with ID % not found', band_id; END IF; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION remove_participant_from_band(band_id BIGINT) RETURNS VOID AS $$ BEGIN UPDATE music_band SET number_of_participants = number_of_participants - 1 WHERE id = band_id AND number_of_participants > 1; IF NOT FOUND THEN RAISE EXCEPTION 'Band with ID % not found or cannot remove participant (minimum 1 required)', band_id; END IF; END; $$ LANGUAGE plpgsql;