Main Diagram

1 { } [ ] Read column and table comments by hovering the columns and tables. Zoom with CTRL+whell mouse button, pan by dragging the diagram with the right-mouse button DbSchema Database Designer Main Diagram Read schema comments as mouse-over tooltips DbSchema.com © 2025-05-07 Wise CodersDbSchema is an universal database designer. DbSchema has a free Community Edition. Location Visitor MusicGenre 🔗 Foreign Key ArtistGenre_ibfk_1 ArtistGenre ref Artist ( Artist_ID ) 🔗 Foreign Key ArtistGenre_ibfk_1 ArtistGenre ref Artist ( Artist_ID ) Artist_ID 🔗 Foreign Key ArtistGenre_ibfk_2 ArtistGenre ref MusicGenre ( Genre_ID ) 🔗 Foreign Key ArtistGenre_ibfk_2 ArtistGenre ref MusicGenre ( Genre_ID ) Genre_ID 🔗 Foreign Key Band_Member_ibfk_1 Band_Member ref Band ( Band_ID ) 🔗 Foreign Key Band_Member_ibfk_1 Band_Member ref Band ( Band_ID ) Band_ID 🔗 Foreign Key Band_Member_ibfk_2 Band_Member ref Artist ( Artist_ID ) 🔗 Foreign Key Band_Member_ibfk_2 Band_Member ref Artist ( Artist_ID ) Artist_ID 🔗 Foreign Key Evaluation_ibfk_1 Evaluation ref Visitor ( Visitor_ID ) 🔗 Foreign Key Evaluation_ibfk_1 Evaluation ref Visitor ( Visitor_ID ) Visitor_ID 🔗 Foreign Key Evaluation_ibfk_2 Evaluation ref Performance ( Performance_ID ) 🔗 Foreign Key Evaluation_ibfk_2 Evaluation ref Performance ( Performance_ID ) Performance_ID 🔗 Foreign Key Event_ibfk_1 Event ref Festival ( Festival_ID ) 🔗 Foreign Key Event_ibfk_1 Event ref Festival ( Festival_ID ) Festival_ID 🔗 Foreign Key Event_ibfk_2 Event ref Stage ( Stage_ID ) 🔗 Foreign Key Event_ibfk_2 Event ref Stage ( Stage_ID ) Stage_ID 🔗 Foreign Key Festival_ibfk_1 Festival ref Location ( Location_ID ) 🔗 Foreign Key Festival_ibfk_1 Festival ref Location ( Location_ID ) Location_ID 🔗 Foreign Key Performance_ibfk_1 Performance ref Event ( Event_ID ) 🔗 Foreign Key Performance_ibfk_1 Performance ref Event ( Event_ID ) Event_ID 🔗 Foreign Key Performance_ibfk_2 Performance ref Artist ( Artist_ID ) 🔗 Foreign Key Performance_ibfk_2 Performance ref Artist ( Artist_ID ) Artist_ID 🔗 Foreign Key Performance_ibfk_3 Performance ref Band ( Band_ID ) 🔗 Foreign Key Performance_ibfk_3 Performance ref Band ( Band_ID ) Band_ID 🔗 Foreign Key ResaleBuyerQueue_ibfk_1 ResaleBuyerQueue ref Visitor ( Buyer_ID -> Visitor_ID ) 🔗 Foreign Key ResaleBuyerQueue_ibfk_1 ResaleBuyerQueue ref Visitor ( Buyer_ID -> Visitor_ID ) Buyer_ID 🔗 Foreign Key ResaleBuyerQueue_ibfk_2 ResaleBuyerQueue ref Performance ( Performance_ID ) 🔗 Foreign Key ResaleBuyerQueue_ibfk_2 ResaleBuyerQueue ref Performance ( Performance_ID ) Performance_ID 🔗 Foreign Key ResaleTicket_ibfk_1 ResaleTicket ref Ticket ( Ticket_ID ) 🔗 Foreign Key ResaleTicket_ibfk_1 ResaleTicket ref Ticket ( Ticket_ID ) Ticket_ID 🔗 Foreign Key ResaleTicket_ibfk_2 ResaleTicket ref Visitor ( Seller_ID -> Visitor_ID ) 🔗 Foreign Key ResaleTicket_ibfk_2 ResaleTicket ref Visitor ( Seller_ID -> Visitor_ID ) Seller_ID 🔗 Foreign Key StaffAssignment_ibfk_1 StaffAssignment ref Staff ( Staff_ID ) 🔗 Foreign Key StaffAssignment_ibfk_1 StaffAssignment ref Staff ( Staff_ID ) Staff_ID 🔗 Foreign Key StaffAssignment_ibfk_2 StaffAssignment ref Event ( Event_ID ) 🔗 Foreign Key StaffAssignment_ibfk_2 StaffAssignment ref Event ( Event_ID ) Event_ID 🔗 Foreign Key Ticket_ibfk_1 Ticket ref Performance ( Performance_ID ) 🔗 Foreign Key Ticket_ibfk_1 Ticket ref Performance ( Performance_ID ) Performance_ID 🔗 Foreign Key Ticket_ibfk_2 Ticket ref Visitor ( Visitor_ID ) 🔗 Foreign Key Ticket_ibfk_2 Ticket ref Visitor ( Visitor_ID ) Visitor_ID 🔗 Foreign Key TicketResaleQueue_ibfk_1 TicketResaleQueue ref Ticket ( Ticket_ID ) 🔗 Foreign Key TicketResaleQueue_ibfk_1 TicketResaleQueue ref Ticket ( Ticket_ID ) Ticket_ID ArtistTable kosni_db.Artist 🔑 Pk pk_artist ( Artist_ID ) Artist_ID⧉ Artist_ID * int ↙ ArtistGenre( Artist_ID ) ↙ Band_Member( Artist_ID ) ↙ Performance( Artist_ID ) 🔗 Referred by ArtistGenre ( Artist_ID ) Referred by Band_Member ( Artist_ID ) Referred by Performance ( Artist_ID ) Real_Name⧉ Real_Name * varchar(100) t Stage_Name⧉ Stage_Name varchar(100) t Birthdate⧉ Birthdate date d Website⧉ Website varchar(255) t Instagram_Profile⧉ Instagram_Profile varchar(255) t Image⧉ Image text t Image_Description⧉ Image_Description text t ArtistGenreTable kosni_db.ArtistGenre 🔑 Pk pk_artistgenre ( Artist_ID, Genre_ID ) Artist_ID⧉ Artist_ID * int ↗ ArtistGenre( Artist_ID ) 🔗 References Artist ( Artist_ID ) 🔑 Pk pk_artistgenre ( Artist_ID, Genre_ID ) 🔍 Genre_ID ( Genre_ID ) Genre_ID⧉ Genre_ID * int ↗ ArtistGenre( Genre_ID ) 🔗 References MusicGenre ( Genre_ID ) BandTable kosni_db.Band 🔑 Pk pk_band ( Band_ID ) Band_ID⧉ Band_ID * int ↙ Band_Member( Band_ID ) ↙ Performance( Band_ID ) 🔗 Referred by Band_Member ( Band_ID ) Referred by Performance ( Band_ID ) Name⧉ Name * varchar(100) t Formation_Date⧉ Formation_Date date d Website⧉ Website varchar(255) t Instagram_Profile⧉ Instagram_Profile varchar(255) t Band_MemberTable kosni_db.Band_Member 🔑 Pk pk_band_member ( Band_ID, Artist_ID ) Band_ID⧉ Band_ID * int ↗ Band_Member( Band_ID ) 🔗 References Band ( Band_ID ) 🔑 Pk pk_band_member ( Band_ID, Artist_ID ) 🔍 Artist_ID ( Artist_ID ) Artist_ID⧉ Artist_ID * int ↗ Band_Member( Artist_ID ) 🔗 References Artist ( Artist_ID ) EntityImageTable kosni_db.EntityImage 🔑 Pk pk_entityimage ( Image_ID ) Image_ID⧉ Image_ID * int # Entity_Type⧉ Entity_Type * enum('festival','artist','band','stage','equipment') t Entity_ID⧉ Entity_ID * int # Image_Description⧉ Image_Description varchar(255) t Image_Data⧉ Image_Data * longblob ~ EvaluationTable kosni_db.Evaluation 🔑 Pk pk_evaluation ( Evaluation_ID ) Evaluation_ID⧉ Evaluation_ID * int # 🔍 Unq Visitor_ID ( Visitor_ID, Performance_ID ) 🔍 idx_evaluation_visitor ( Visitor_ID ) Visitor_ID⧉ Visitor_ID * int ↗ Evaluation( Visitor_ID ) 🔗 References Visitor ( Visitor_ID ) 🔍 Unq Visitor_ID ( Visitor_ID, Performance_ID ) 🔍 idx_evaluation_performance ( Performance_ID ) Performance_ID⧉ Performance_ID * int ↗ Evaluation( Performance_ID ) 🔗 References Performance ( Performance_ID ) Evaluation_Date⧉ Evaluation_Date * datetime default current_timestamp() d Artist_Performance⧉ Artist_Performance * tinyint # Sound_Lighting⧉ Sound_Lighting * tinyint # Stage_Presence⧉ Stage_Presence * tinyint # Organization⧉ Organization * tinyint # Overall_Impression⧉ Overall_Impression * tinyint # EventTable kosni_db.Event 🔑 Pk pk_event ( Event_ID ) Event_ID⧉ Event_ID * int ↙ Performance( Event_ID ) ↙ StaffAssignment( Event_ID ) 🔗 Referred by Performance ( Event_ID ) Referred by StaffAssignment ( Event_ID ) 🔍 idx_event_festival ( Festival_ID ) Festival_ID⧉ Festival_ID * int ↗ Event( Festival_ID ) 🔗 References Festival ( Festival_ID ) 🔍 Unq Stage_ID ( Stage_ID, Start_Time ) 🔍 idx_event_stage ( Stage_ID ) Stage_ID⧉ Stage_ID * int ↗ Event( Stage_ID ) 🔗 References Stage ( Stage_ID ) 🔍 Unq Stage_ID ( Stage_ID, Start_Time ) Start_Time⧉ Start_Time * datetime d End_Time⧉ End_Time * datetime d Status⧉ Status * enum('scheduled','ongoing','completed') default 'Scheduled' t FestivalTable kosni_db.Festival 🔑 Pk pk_festival ( Festival_ID ) Festival_ID⧉ Festival_ID * int ↙ Event( Festival_ID ) 🔗 Referred by Event ( Festival_ID ) Year⧉ Year * year(4) # Start_Date⧉ Start_Date * date d End_Date⧉ End_Date * date d Image⧉ Image text t Image_Description⧉ Image_Description text t 🔍 Location_ID ( Location_ID ) Location_ID⧉ Location_ID * int ↗ Festival( Location_ID ) 🔗 References Location ( Location_ID ) Status⧉ Status * enum('scheduled','ongoing','completed') default 'Scheduled' t LocationTable kosni_db.Location 🔑 Pk pk_location ( Location_ID ) Location_ID⧉ Location_ID * int ↙ Festival( Location_ID ) 🔗 Referred by Festival ( Location_ID ) Address⧉ Address * varchar(255) t Coordinates⧉ Coordinates varchar(100) t City⧉ City * varchar(100) t Country⧉ Country * varchar(100) t Continent⧉ Continent varchar(100) t Image⧉ Image text t Image_Description⧉ Image_Description text t MusicGenreTable kosni_db.MusicGenre 🔑 Pk pk_musicgenre ( Genre_ID ) Genre_ID⧉ Genre_ID * int ↙ ArtistGenre( Genre_ID ) 🔗 Referred by ArtistGenre ( Genre_ID ) Name⧉ Name text t Subgenre⧉ Subgenre text t PerformanceTable kosni_db.Performance 🔑 Pk pk_performance ( Performance_ID ) Performance_ID⧉ Performance_ID * int ↙ Evaluation( Performance_ID ) ↙ ResaleBuyerQueue( Performance_ID ) ↙ Ticket( Performance_ID ) 🔗 Referred by Evaluation ( Performance_ID ) Referred by ResaleBuyerQueue ( Performance_ID ) Referred by Ticket ( Performance_ID ) 🔍 idx_performance_event ( Event_ID ) Event_ID⧉ Event_ID * int ↗ Performance( Event_ID ) 🔗 References Event ( Event_ID ) 🔍 idx_performance_artist ( Artist_ID ) Artist_ID⧉ Artist_ID int ↗ Performance( Artist_ID ) 🔗 References Artist ( Artist_ID ) 🔍 idx_performance_band ( Band_ID ) Band_ID⧉ Band_ID int ↗ Performance( Band_ID ) 🔗 References Band ( Band_ID ) Type⧉ Type * enum('warm up','headline','special guest') t Start_Time⧉ Start_Time * datetime d Duration⧉ Duration * int # ResaleBuyerQueueTable kosni_db.ResaleBuyerQueue 🔑 Pk pk_resalebuyerqueue ( Queue_ID ) Queue_ID⧉ Queue_ID * int # 🔍 idx_resalebuyerqueue_buyer ( Buyer_ID ) Buyer_ID⧉ Buyer_ID * int ↗ ResaleBuyerQueue( Visitor_ID ) 🔗 References Visitor ( Buyer_ID -> Visitor_ID ) 🔍 idx_resalebuyerqueue_performance ( Performance_ID ) Performance_ID⧉ Performance_ID * int ↗ ResaleBuyerQueue( Performance_ID ) 🔗 References Performance ( Performance_ID ) Category⧉ Category * enum('general','vip','backstage') t Requested_At⧉ Requested_At * datetime default current_timestamp() d Status⧉ Status * enum('waiting','matched','cancelled') default 'Waiting' t ResaleTicketTable kosni_db.ResaleTicket 🔑 Pk pk_resaleticket ( ResaleTicket_ID ) ResaleTicket_ID⧉ ResaleTicket_ID * int # 🔍 idx_resaleticket_ticket ( Ticket_ID ) Ticket_ID⧉ Ticket_ID * int ↗ ResaleTicket( Ticket_ID ) 🔗 References Ticket ( Ticket_ID ) 🔍 idx_resaleticket_seller ( Seller_ID ) Seller_ID⧉ Seller_ID * int ↗ ResaleTicket( Visitor_ID ) 🔗 References Visitor ( Seller_ID -> Visitor_ID ) Listed_At⧉ Listed_At * datetime default current_timestamp() d Status⧉ Status * enum('available','sold','withdrawn') default 'Available' t StaffTable kosni_db.Staff 🔑 Pk pk_staff ( Staff_ID ) Staff_ID⧉ Staff_ID * int ↙ StaffAssignment( Staff_ID ) 🔗 Referred by StaffAssignment ( Staff_ID ) Name⧉ Name * varchar(100) t Age⧉ Age * int # Role⧉ Role * enum('technical','security','auxiliary') t Experience_Level⧉ Experience_Level * enum('intern','beginner','intermediate','experienced','expert') t StaffAssignmentTable kosni_db.StaffAssignment 🔑 Pk pk_staffassignment ( Staff_ID, Event_ID ) 🔍 idx_staffassignment_staff ( Staff_ID ) Staff_ID⧉ Staff_ID * int ↗ StaffAssignment( Staff_ID ) 🔗 References Staff ( Staff_ID ) 🔑 Pk pk_staffassignment ( Staff_ID, Event_ID ) 🔍 idx_staffassignment_event ( Event_ID ) Event_ID⧉ Event_ID * int ↗ StaffAssignment( Event_ID ) 🔗 References Event ( Event_ID ) StageTable kosni_db.Stage 🔑 Pk pk_stage ( Stage_ID ) Stage_ID⧉ Stage_ID * int ↙ Event( Stage_ID ) 🔗 Referred by Event ( Stage_ID ) Name⧉ Name * varchar(100) t Description⧉ Description text t Max_Capacity⧉ Max_Capacity * int # Technical_Equipment⧉ Technical_Equipment text t Image⧉ Image text t Image_Description⧉ Image_Description text t TicketTable kosni_db.Ticket 🔑 Pk pk_ticket ( Ticket_ID ) Ticket_ID⧉ Ticket_ID * int ↙ ResaleTicket( Ticket_ID ) ↙ TicketResaleQueue( Ticket_ID ) 🔗 Referred by ResaleTicket ( Ticket_ID ) Referred by TicketResaleQueue ( Ticket_ID ) 🔍 Unq Visitor_ID ( Visitor_ID, Performance_ID, Purchase_Date ) 🔍 idx_ticket_performance ( Performance_ID ) Performance_ID⧉ Performance_ID * int ↗ Ticket( Performance_ID ) 🔗 References Performance ( Performance_ID ) 🔍 Unq Visitor_ID ( Visitor_ID, Performance_ID, Purchase_Date ) 🔍 idx_ticket_visitor ( Visitor_ID ) Visitor_ID⧉ Visitor_ID * int ↗ Ticket( Visitor_ID ) 🔗 References Visitor ( Visitor_ID ) Category⧉ Category * enum('general','vip','backstage') t 🔍 Unq Visitor_ID ( Visitor_ID, Performance_ID, Purchase_Date ) Purchase_Date⧉ Purchase_Date * date d Cost⧉ Cost * decimal(10,2) # Payment_Method⧉ Payment_Method * enum('credit card','debit card','bank transfer') t 🔍 Unq EAN131_Code ( EAN131_Code ) EAN131_Code⧉ EAN131_Code * bigint # Activated⧉ Activated boolean default false b TicketResaleQueueTable kosni_db.TicketResaleQueue 🔑 Pk pk_ticketresalequeue ( Queue_ID ) Queue_ID⧉ Queue_ID * int # 🔍 Ticket_ID ( Ticket_ID ) Ticket_ID⧉ Ticket_ID int ↗ TicketResaleQueue( Ticket_ID ) 🔗 References Ticket ( Ticket_ID ) Queue_Type⧉ Queue_Type text t Queue_Timestamp⧉ Queue_Timestamp datetime d VisitorTable kosni_db.Visitor 🔑 Pk pk_visitor ( Visitor_ID ) Visitor_ID⧉ Visitor_ID * int ↙ Evaluation( Visitor_ID ) ↙ ResaleBuyerQueue( Visitor_ID ) ↙ ResaleTicket( Visitor_ID ) ↙ Ticket( Visitor_ID ) 🔗 Referred by Evaluation ( Visitor_ID ) Referred by ResaleBuyerQueue ( Buyer_ID -> Visitor_ID ) Referred by ResaleTicket ( Seller_ID -> Visitor_ID ) Referred by Ticket ( Visitor_ID ) First_Name⧉ First_Name * varchar(100) t Last_Name⧉ Last_Name * varchar(100) t Contact_Info⧉ Contact_Info * varchar(255) t Age⧉ Age * int # Get a better understanding of the schema by creating multiple diagrams with the same or different tables. Double-click the table headers, columns, or foreign keys to edit. The schema structure will be saved to the design model file.





Table Artist
IdxColumn NameData Type
* Artist_ID INT AUTO_INCREMENT
* Real_Name VARCHAR(100)
  Stage_Name VARCHAR(100)
  Birthdate DATE
  Website VARCHAR(255)
  Instagram_Profile VARCHAR(255)
  Image TEXT
  Image_Description TEXT
Indexes
pk_artist Primary Key ON Artist_ID
Referring Foreign Key
ArtistGenre_ibfk_1 Artist_ID ↙ ❏ ArtistGenre
Band_Member_ibfk_2 Artist_ID ↙ ❏ Band_Member
Performance_ibfk_2 Artist_ID ↙ ❏ Performance
Options
ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table ArtistGenre
IdxColumn NameData Type
* Artist_ID INT
* Genre_ID INT
Indexes
pk_artistgenre Primary Key ON Artist_ID, Genre_ID
Genre_ID Index ON Genre_ID
Foreign Key
ArtistGenre_ibfk_1 Artist_ID ↗ ❏ Artist
ArtistGenre_ibfk_2 Genre_ID ↗ ❏ MusicGenre
Options
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Band
IdxColumn NameData Type
* Band_ID INT AUTO_INCREMENT
* Name VARCHAR(100)
  Formation_Date DATE
  Website VARCHAR(255)
  Instagram_Profile VARCHAR(255)
Indexes
pk_band Primary Key ON Band_ID
Referring Foreign Key
Band_Member_ibfk_1 Band_ID ↙ ❏ Band_Member
Performance_ibfk_3 Band_ID ↙ ❏ Performance
Options
ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Band_Member
IdxColumn NameData Type
* Band_ID INT
* Artist_ID INT
Indexes
pk_band_member Primary Key ON Band_ID, Artist_ID
Artist_ID Index ON Artist_ID
Foreign Key
Band_Member_ibfk_1 Band_ID ↗ ❏ Band
Band_Member_ibfk_2 Artist_ID ↗ ❏ Artist
Options
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table EntityImage
IdxColumn NameData Type
* Image_ID INT AUTO_INCREMENT
* Entity_Type ENUM('Festival','Artist','Band','Stage','Equipment')
* Entity_ID INT
  Image_Description VARCHAR(255)
* Image_Data LONGBLOB
Indexes
pk_entityimage Primary Key ON Image_ID
Options
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Evaluation
IdxColumn NameData Type
* Evaluation_ID INT AUTO_INCREMENT
* Visitor_ID INT
* Performance_ID INT
* Evaluation_Date DATETIME DEFAULT current_timestamp()
* Artist_Performance TINYINT
* Sound_Lighting TINYINT
* Stage_Presence TINYINT
* Organization TINYINT
* Overall_Impression TINYINT
Indexes
pk_evaluation Primary Key ON Evaluation_ID
Visitor_ID Unique Key ON Visitor_ID, Performance_ID
idx_evaluation_visitor Index ON Visitor_ID
idx_evaluation_performance Index ON Performance_ID
Foreign Key
Evaluation_ibfk_1 Visitor_ID ↗ ❏ Visitor
Evaluation_ibfk_2 Performance_ID ↗ ❏ Performance
Constraints
  cns_evaluation_artist_performance `Artist_Performance` between 1 and 3
  cns_evaluation_sound_lighting `Sound_Lighting` between 1 and 3
  cns_evaluation_stage_presence `Stage_Presence` between 1 and 3
  cns_evaluation_organization `Organization` between 1 and 3
  cns_evaluation_overall_impression `Overall_Impression` between 1 and 3
Triggers
  check_evaluation_ticket_activation
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Evaluation FOR EACH ROW BEGIN
  DECLARE ticket_count INT;
  SELECT COUNT(*) INTO ticket_count
  FROM Ticket t
  JOIN Performance p ON t.Performance_ID = p.Performance_ID
  WHERE t.Visitor_ID = NEW.Visitor_ID
    AND t.Performance_ID = NEW.Performance_ID
    AND t.Activated = 1;
  IF ticket_count = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Evaluation not allowed: visitor must have an activated ticket for the performance.';
  END IF;
END
Options
ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Event
IdxColumn NameData Type
* Event_ID INT AUTO_INCREMENT
* Festival_ID INT
* Stage_ID INT
* Start_Time DATETIME
* End_Time DATETIME
* Status ENUM('Scheduled','Ongoing','Completed') DEFAULT 'Scheduled'
Indexes
pk_event Primary Key ON Event_ID
Stage_ID Unique Key ON Stage_ID, Start_Time
idx_event_festival Index ON Festival_ID
idx_event_stage Index ON Stage_ID
Foreign Key
Event_ibfk_1 Festival_ID ↗ ❏ Festival
Event_ibfk_2 Stage_ID ↗ ❏ Stage
Referring Foreign Key
Performance_ibfk_1 Event_ID ↙ ❏ Performance
StaffAssignment_ibfk_2 Event_ID ↙ ❏ StaffAssignment
Constraints
  CONSTRAINT_1 `End_Time` > `Start_Time`
  CONSTRAINT_2 `Status` <> 'Canceled'
Triggers
  prevent_event_overlap
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Event FOR EACH ROW BEGIN
  DECLARE overlap_count INT;
  SELECT COUNT(*) INTO overlap_count
  FROM Event
  WHERE Stage_ID = NEW.Stage_ID
    AND Festival_ID = NEW.Festival_ID
    AND DATE(Start_Time) = DATE(NEW.Start_Time)
    AND (
      NEW.Start_Time < End_Time AND
      NEW.End_Time > Start_Time
    );
  IF overlap_count > 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Error: Overlapping event detected on the same stage.';
  END IF;
END
  prevent_event_overlap_update
CREATE TRIGGER ${nameWithSchemaName} BEFORE UPDATE ON Event FOR EACH ROW BEGIN
  DECLARE overlap_count INT;
  SELECT COUNT(*) INTO overlap_count
  FROM Event
  WHERE Stage_ID = NEW.Stage_ID
    AND Festival_ID = NEW.Festival_ID
    AND Event_ID != NEW.Event_ID
    AND (
      NEW.Start_Time < End_Time AND
      NEW.End_Time > Start_Time
    );
  IF overlap_count > 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Error: Overlapping event detected on the same stage.';
  END IF;
END
Options
ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Festival
IdxColumn NameData Type
* Festival_ID INT AUTO_INCREMENT
* Year YEAR(4)
* Start_Date DATE
* End_Date DATE
  Image TEXT
  Image_Description TEXT
* Location_ID INT
* Status ENUM('Scheduled','Ongoing','Completed') DEFAULT 'Scheduled'
Indexes
pk_festival Primary Key ON Festival_ID
Location_ID Index ON Location_ID
Foreign Key
Festival_ibfk_1 Location_ID ↗ ❏ Location
Referring Foreign Key
Event_ibfk_1 Festival_ID ↙ ❏ Event
Constraints
  CONSTRAINT_1 `End_Date` > `Start_Date`
  CONSTRAINT_2 `Status` <> 'Canceled'
Options
ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Location
IdxColumn NameData Type
* Location_ID INT AUTO_INCREMENT
* Address VARCHAR(255)
  Coordinates VARCHAR(100)
* City VARCHAR(100)
* Country VARCHAR(100)
  Continent VARCHAR(100)
  Image TEXT
  Image_Description TEXT
Indexes
pk_location Primary Key ON Location_ID
Referring Foreign Key
Festival_ibfk_1 Location_ID ↙ ❏ Festival
Options
ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table MusicGenre
IdxColumn NameData Type
* Genre_ID INT
  Name TEXT
  Subgenre TEXT
Indexes
pk_musicgenre Primary Key ON Genre_ID
Referring Foreign Key
ArtistGenre_ibfk_2 Genre_ID ↙ ❏ ArtistGenre
Options
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Performance
IdxColumn NameData Type
* Performance_ID INT AUTO_INCREMENT
* Event_ID INT
Artist_ID INT
Band_ID INT
* Type ENUM('Warm Up','Headline','Special Guest')
* Start_Time DATETIME
* Duration INT
Indexes
pk_performance Primary Key ON Performance_ID
idx_performance_artist Index ON Artist_ID
idx_performance_band Index ON Band_ID
idx_performance_event Index ON Event_ID
Foreign Key
Performance_ibfk_1 Event_ID ↗ ❏ Event
Performance_ibfk_2 Artist_ID ↗ ❏ Artist
Performance_ibfk_3 Band_ID ↗ ❏ Band
Referring Foreign Key
Evaluation_ibfk_2 Performance_ID ↙ ❏ Evaluation
ResaleBuyerQueue_ibfk_2 Performance_ID ↙ ❏ ResaleBuyerQueue
Ticket_ibfk_1 Performance_ID ↙ ❏ Ticket
Constraints
  cns_performance_duration `Duration` > 0 and `Duration` <= 180
  CONSTRAINT_1 `Artist_ID` is not null and `Band_ID` is null or `Artist_ID` is null and `Band_ID` is not null
Triggers
  check_artist_consecutive_years
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Performance FOR EACH ROW BEGIN
  DECLARE year INT;
  DECLARE consecutive_years INT;
  IF NEW.Artist_ID IS NOT NULL THEN
    
    SELECT f.Year INTO year
    FROM Event e
    JOIN Festival f ON e.Festival_ID = f.Festival_ID
    WHERE e.Event_ID = NEW.Event_ID;
    
    SELECT COUNT(DISTINCT f.Year) INTO consecutive_years
    FROM Performance p
    JOIN Event e ON p.Event_ID = e.Event_ID
    JOIN Festival f ON e.Festival_ID = f.Festival_ID
    WHERE p.Artist_ID = NEW.Artist_ID
      AND f.Year BETWEEN year - 2 AND year;
    IF consecutive_years > 3 THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Artist cannot perform more than 3 consecutive years.';
    END IF;
  END IF;
END
  check_band_consecutive_years
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Performance FOR EACH ROW BEGIN
  DECLARE current_year INT;
  DECLARE consecutive_years INT;
  IF NEW.Band_ID IS NOT NULL THEN
    
    SELECT f.Year INTO current_year
    FROM Event e
    JOIN Festival f ON e.Festival_ID = f.Festival_ID
    WHERE e.Event_ID = NEW.Event_ID;
    
    SELECT COUNT(DISTINCT f.Year) INTO consecutive_years
    FROM Performance p
    JOIN Event e ON p.Event_ID = e.Event_ID
    JOIN Festival f ON e.Festival_ID = f.Festival_ID
    WHERE p.Band_ID = NEW.Band_ID
      AND f.Year BETWEEN current_year - 2 AND current_year;
    IF consecutive_years >= 3 THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Band cannot perform more than 3 consecutive years.';
    END IF;
  END IF;
END
  check_performance_break
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Performance FOR EACH ROW BEGIN
  DECLARE previous_end_time DATETIME;
  DECLARE break_duration INT;
  DECLARE conflicting_count INT;
   
  SELECT COUNT(*) INTO conflicting_count
  FROM Performance
  WHERE Event_ID = NEW.Event_ID
    AND DATE(Start_Time) = DATE(NEW.Start_Time)
    AND (
      
      (NEW.Start_Time BETWEEN Start_Time AND (Start_Time + INTERVAL Duration MINUTE - INTERVAL 1 SECOND))
      OR ((NEW.Start_Time + INTERVAL NEW.Duration MINUTE - INTERVAL 1 SECOND) BETWEEN Start_Time AND (Start_Time + INTERVAL Duration MINUTE - INTERVAL 1 SECOND))
      OR (Start_Time BETWEEN NEW.Start_Time AND (NEW.Start_Time + INTERVAL NEW.Duration MINUTE - INTERVAL 1 SECOND))
    );
  IF conflicting_count > 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Performance time overlaps with an existing performance.';
  END IF;
  SELECT MAX(Start_Time + INTERVAL Duration MINUTE) INTO previous_end_time
  FROM Performance
  WHERE Event_ID = NEW.Event_ID
    AND Start_Time < NEW.Start_Time
    AND DATE(Start_Time) = DATE(NEW.Start_Time);  
  IF previous_end_time IS NOT NULL THEN
    SET break_duration = TIMESTAMPDIFF(MINUTE, previous_end_time, NEW.Start_Time);
    
    IF break_duration < 5 OR break_duration > 30 THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Break between performances must be between 5 and 30 minutes.';
    END IF;
  END IF;
END
  prevent_artist_overlap
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Performance FOR EACH ROW BEGIN
  DECLARE overlap_count INT;
  DECLARE festival_id INT;
  IF NEW.Artist_ID IS NOT NULL THEN
    SELECT e.Festival_ID INTO festival_id
    FROM Event e
    WHERE e.Event_ID = NEW.Event_ID;
    SELECT COUNT(*) INTO overlap_count
    FROM Performance p
    JOIN Event e ON p.Event_ID = e.Event_ID
    WHERE p.Artist_ID = NEW.Artist_ID
      AND e.Festival_ID = festival_id
      AND (
        NEW.Start_Time < ADDTIME(p.Start_Time, SEC_TO_TIME(p.Duration * 60)) AND
        ADDTIME(NEW.Start_Time, SEC_TO_TIME(NEW.Duration * 60)) > p.Start_Time
      );
    IF overlap_count > 0 THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Artist has overlapping performance in the same festival.';
    END IF;
  END IF;
END
  prevent_band_overlap
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Performance FOR EACH ROW BEGIN
  DECLARE overlap_count INT;
  DECLARE festival_id INT;
  IF NEW.Band_ID IS NOT NULL THEN
    SELECT e.Festival_ID INTO festival_id
    FROM Event e
    WHERE e.Event_ID = NEW.Event_ID;
    SELECT COUNT(*) INTO overlap_count
    FROM Performance p
    JOIN Event e ON p.Event_ID = e.Event_ID
    WHERE p.Band_ID = NEW.Band_ID
      AND e.Festival_ID = festival_id
      AND (
        NEW.Start_Time < ADDTIME(p.Start_Time, SEC_TO_TIME(p.Duration * 60)) AND
        ADDTIME(NEW.Start_Time, SEC_TO_TIME(NEW.Duration * 60)) > p.Start_Time
      );
    IF overlap_count > 0 THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Band has overlapping performance in the same festival.';
    END IF;
  END IF;
END
Options
ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table ResaleBuyerQueue
IdxColumn NameData Type
* Queue_ID INT AUTO_INCREMENT
* Buyer_ID INT
* Performance_ID INT
* Category ENUM('General','VIP','Backstage')
* Requested_At DATETIME DEFAULT current_timestamp()
* Status ENUM('Waiting','Matched','Cancelled') DEFAULT 'Waiting'
Indexes
pk_resalebuyerqueue Primary Key ON Queue_ID
idx_resalebuyerqueue_buyer Index ON Buyer_ID
idx_resalebuyerqueue_performance Index ON Performance_ID
Foreign Key
ResaleBuyerQueue_ibfk_1 Buyer_ID ↗ ❏ Visitor(Visitor_ID)
ResaleBuyerQueue_ibfk_2 Performance_ID ↗ ❏ Performance
Options
ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table ResaleTicket
IdxColumn NameData Type
* ResaleTicket_ID INT AUTO_INCREMENT
* Ticket_ID INT
* Seller_ID INT
* Listed_At DATETIME DEFAULT current_timestamp()
* Status ENUM('Available','Sold','Withdrawn') DEFAULT 'Available'
Indexes
pk_resaleticket Primary Key ON ResaleTicket_ID
idx_resaleticket_ticket Index ON Ticket_ID
idx_resaleticket_seller Index ON Seller_ID
Foreign Key
ResaleTicket_ibfk_1 Ticket_ID ↗ ❏ Ticket
ResaleTicket_ibfk_2 Seller_ID ↗ ❏ Visitor(Visitor_ID)
Options
ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Staff
IdxColumn NameData Type
* Staff_ID INT AUTO_INCREMENT
* Name VARCHAR(100)
* Age INT
* Role ENUM('Technical','Security','Auxiliary')
* Experience_Level ENUM('Intern','Beginner','Intermediate','Experienced','Expert')
Indexes
pk_staff Primary Key ON Staff_ID
Referring Foreign Key
StaffAssignment_ibfk_1 Staff_ID ↙ ❏ StaffAssignment
Constraints
  cns_staff_age `Age` >= 18
Options
ENGINE=InnoDB AUTO_INCREMENT=301 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table StaffAssignment
IdxColumn NameData Type
* Staff_ID INT
* Event_ID INT
Indexes
pk_staffassignment Primary Key ON Staff_ID, Event_ID
idx_staffassignment_staff Index ON Staff_ID
idx_staffassignment_event Index ON Event_ID
Foreign Key
StaffAssignment_ibfk_1 Staff_ID ↗ ❏ Staff
StaffAssignment_ibfk_2 Event_ID ↗ ❏ Event
Options
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Stage
IdxColumn NameData Type
* Stage_ID INT AUTO_INCREMENT
* Name VARCHAR(100)
  Description TEXT
* Max_Capacity INT
  Technical_Equipment TEXT
  Image TEXT
  Image_Description TEXT
Indexes
pk_stage Primary Key ON Stage_ID
Referring Foreign Key
Event_ibfk_2 Stage_ID ↙ ❏ Event
Constraints
  cns_stage_max_capacity `Max_Capacity` > 0
Options
ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Ticket
IdxColumn NameData Type
* Ticket_ID INT AUTO_INCREMENT
* Performance_ID INT
* Visitor_ID INT
* Category ENUM('General','VIP','Backstage')
* Purchase_Date DATE
* Cost DECIMAL(10,2)
* Payment_Method ENUM('Credit Card','Debit Card','Bank Transfer')
* EAN131_Code BIGINT
  Activated BOOLEAN DEFAULT false
Indexes
pk_ticket Primary Key ON Ticket_ID
EAN131_Code Unique Key ON EAN131_Code
Visitor_ID Unique Key ON Visitor_ID, Performance_ID, Purchase_Date
idx_ticket_performance Index ON Performance_ID
idx_ticket_visitor Index ON Visitor_ID
Foreign Key
Ticket_ibfk_1 Performance_ID ↗ ❏ Performance
Ticket_ibfk_2 Visitor_ID ↗ ❏ Visitor
Referring Foreign Key
ResaleTicket_ibfk_1 Ticket_ID ↙ ❏ ResaleTicket
TicketResaleQueue_ibfk_1 Ticket_ID ↙ ❏ TicketResaleQueue
Triggers
  check_stage_capacity
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Ticket FOR EACH ROW BEGIN
  DECLARE total_tickets INT;
  DECLARE stage_capacity INT;
  SELECT COUNT(*) INTO total_tickets
  FROM Ticket
  WHERE Performance_ID = NEW.Performance_ID;
  SELECT s.Max_Capacity INTO stage_capacity
  FROM Performance p
  JOIN Event e ON p.Event_ID = e.Event_ID
  JOIN Stage s ON e.Stage_ID = s.Stage_ID
  WHERE p.Performance_ID = NEW.Performance_ID;
  IF total_tickets >= stage_capacity THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Cannot sell ticket: stage capacity exceeded.';
  END IF;
END
  check_vip_limit
CREATE TRIGGER ${nameWithSchemaName} BEFORE INSERT ON Ticket FOR EACH ROW BEGIN
  DECLARE vip_tickets INT;
  DECLARE stage_capacity INT;
  DECLARE max_vip_tickets INT;
  IF NEW.Category = 'VIP' THEN
    SELECT COUNT(*) INTO vip_tickets
    FROM Ticket
    WHERE Performance_ID = NEW.Performance_ID
      AND Category = 'VIP';
    SELECT s.Max_Capacity INTO stage_capacity
    FROM Performance p
    JOIN Event e ON p.Event_ID = e.Event_ID
    JOIN Stage s ON e.Stage_ID = s.Stage_ID
    WHERE p.Performance_ID = NEW.Performance_ID;
    SET max_vip_tickets = FLOOR(stage_capacity * 0.10);
    IF vip_tickets >= max_vip_tickets THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Cannot sell VIP ticket: VIP limit exceeded.';
    END IF;
  END IF;
END
Options
ENGINE=InnoDB AUTO_INCREMENT=401 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table TicketResaleQueue
IdxColumn NameData Type
* Queue_ID INT
Ticket_ID INT
  Queue_Type TEXT
  Queue_Timestamp DATETIME
Indexes
pk_ticketresalequeue Primary Key ON Queue_ID
Ticket_ID Index ON Ticket_ID
Foreign Key
TicketResaleQueue_ibfk_1 Ticket_ID ↗ ❏ Ticket
Options
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci


Table Visitor
IdxColumn NameData Type
* Visitor_ID INT AUTO_INCREMENT
* First_Name VARCHAR(100)
* Last_Name VARCHAR(100)
* Contact_Info VARCHAR(255)
* Age INT
Indexes
pk_visitor Primary Key ON Visitor_ID
Referring Foreign Key
Evaluation_ibfk_1 Visitor_ID ↙ ❏ Evaluation
ResaleBuyerQueue_ibfk_1 Visitor_ID ↙ ❏ ResaleBuyerQueue(Buyer_ID)
ResaleTicket_ibfk_2 Visitor_ID ↙ ❏ ResaleTicket(Seller_ID)
Ticket_ibfk_2 Visitor_ID ↙ ❏ Ticket
Constraints
  cns_visitor_age `Age` >= 0
Options
ENGINE=InnoDB AUTO_INCREMENT=401 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci




Procedures
kosni_db.`ProcessResaleQueue`
CREATE PROCEDURE ${nameWithSchemaName}()
BEGIN
  DECLARE done INT DEFAULT FALSE;
  DECLARE resale_ticket_id INT;
  DECLARE ticket_id INT;
  DECLARE performance_id INT;
  DECLARE category ENUM('General', 'VIP', 'Backstage');
  DECLARE buyer_id INT;
  DECLARE buyer_queue_id INT;

  
  DECLARE resale_cursor CURSOR FOR
    SELECT rt.ResaleTicket_ID, t.Ticket_ID, p.Performance_ID, t.Category
    FROM ResaleTicket rt
    JOIN Ticket t ON rt.Ticket_ID = t.Ticket_ID
    JOIN Performance p ON t.Performance_ID = p.Performance_ID
    WHERE rt.Status = 'Available'
    ORDER BY rt.Listed_At ASC;

  
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  OPEN resale_cursor;

  read_loop: LOOP
    FETCH resale_cursor INTO resale_ticket_id, ticket_id, performance_id, category;
    IF done THEN
      LEAVE read_loop;
    END IF;

    
    SELECT rbq.Queue_ID, rbq.Buyer_ID
    INTO buyer_queue_id, buyer_id
    FROM ResaleBuyerQueue rbq
    WHERE rbq.Status = 'Waiting'
      AND rbq.Performance_ID = performance_id
      AND rbq.Category = category
    ORDER BY rbq.Requested_At ASC
    LIMIT 1;

    
    IF buyer_id IS NOT NULL THEN
      UPDATE Ticket
      SET Visitor_ID = buyer_id
      WHERE Ticket_ID = ticket_id;

      UPDATE ResaleTicket
      SET Status = 'Sold'
      WHERE ResaleTicket_ID = resale_ticket_id;

      UPDATE ResaleBuyerQueue
      SET Status = 'Matched'
      WHERE Queue_ID = buyer_queue_id;

      SET buyer_id = NULL;
    END IF;
  END LOOP;

  CLOSE resale_cursor;
END