-- 创建数据库 -- 创建数据表 CREATE TABLE admin ( admin_name VARCHAR(255) PRIMARY KEY, password VARCHAR(255) NOT NULL ); CREATE TABLE account ( account_id SERIAL PRIMARY KEY, type VARCHAR(50), status VARCHAR(50), created_by VARCHAR(255) REFERENCES admin(admin_name) ); CREATE TABLE venue ( venue_id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, capacity INT NOT NULL CHECK (capacity > 0) ); CREATE TABLE student ( student_id VARCHAR(255) PRIMARY KEY, name VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, personal_info_id INT UNIQUE, FOREIGN KEY (personal_info_id) REFERENCES personal_info(info_id) ); CREATE TABLE coach ( coach_id VARCHAR(255) PRIMARY KEY, name VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, personal_info_id INT UNIQUE, FOREIGN KEY (personal_info_id) REFERENCES personal_info(info_id) ); CREATE TABLE appointment ( appointment_id SERIAL PRIMARY KEY, student_id VARCHAR(255) NOT NULL REFERENCES student(student_id), coach_id VARCHAR(255) NOT NULL REFERENCES coach(coach_id), venue_id INT NOT NULL REFERENCES venue(venue_id), period VARCHAR(50) NOT NULL, status VARCHAR(50) NOT NULL, feedback_id INT REFERENCES feedback(feedback_id) ); CREATE TABLE feedback ( feedback_id SERIAL PRIMARY KEY, content TEXT NOT NULL, date DATE NOT NULL ); CREATE TABLE invoice ( invoice_id SERIAL PRIMARY KEY, amount DECIMAL(10, 2) NOT NULL CHECK (amount >= 0), date DATE NOT NULL, appointment_id INT REFERENCES appointment(appointment_id) ); CREATE TABLE personal_info ( info_id SERIAL PRIMARY KEY, student_id VARCHAR(255) NOT NULL REFERENCES student(student_id), phone VARCHAR(20), email VARCHAR(255) ); CREATE TABLE training_record ( record_id SERIAL PRIMARY KEY, student_id VARCHAR(255) NOT NULL REFERENCES student(student_id), coach_id VARCHAR(255) NOT NULL REFERENCES coach(coach_id), feedback TEXT, appointment_id INT REFERENCES appointment(appointment_id) ); CREATE TABLE booking_slot ( slot_id SERIAL PRIMARY KEY, start_time TIME NOT NULL, end_time TIME NOT NULL CHECK (end_time > start_time), venue_id INT NOT NULL REFERENCES venue(venue_id) ); -- 初始化ADMIN表 INSERT INTO admin (admin_name, password) VALUES ('admin1', 'password1'); INSERT INTO admin (admin_name, password) VALUES ('admin2', 'password2'); -- 初始化ACCOUNT表 INSERT INTO account (type, status, created_by) VALUES ('student', 'active', 'admin1'); INSERT INTO account (type, status, created_by) VALUES ('coach', 'active', 'admin1'); -- 初始化VENUE表 INSERT INTO venue (name, capacity) VALUES ('Venue A', 10); INSERT INTO venue (name, capacity) VALUES ('Venue B', 15); -- 初始化STUDENT表 INSERT INTO personal_info (phone, email) VALUES ('1234567890', 'student1@example.com'); INSERT INTO student (student_id, name, password, personal_info_id) VALUES ('S001', 'Student One', 'pass1', 1); -- 初始化COACH表 INSERT INTO personal_info (phone, email) VALUES ('0987654321', 'coach1@example.com'); INSERT INTO coach (coach_id, name, password, personal_info_id) VALUES ('C001', 'Coach One', 'pass1', 2); -- 初始化APPOINTMENT表 INSERT INTO appointment (student_id, coach_id, venue_id, period, status) VALUES ('S001', 'C001', 1, 'Morning', 'Scheduled'); -- 初始化FEEDBACK表 INSERT INTO feedback (content, date) VALUES ('Great session!', '2024-12-01'); -- 初始化INVOICE表 INSERT INTO invoice (amount, date, appointment_id) VALUES (100.00, '2024-12-01', 1); -- 初始化TRAINING_RECORD表 INSERT INTO training_record (student_id, coach_id, feedback, appointment_id) VALUES ('S001', 'C001', 'Good progress.', 1); -- 初始化BOOKING_SLOT表 INSERT INTO booking_slot (start_time, end_time, venue_id) VALUES ('09:00:00', '10:00:00', 1); -- 学生信息视图 CREATE VIEW StudentInfoView AS SELECT s.student_id, s.name, p.phone, p.email FROM student s JOIN personal_info p ON s.personal_info_id = p.info_id; -- 教练信息视图 CREATE VIEW CoachInfoView AS SELECT c.coach_id, c.name, p.phone, p.email FROM coach c JOIN personal_info p ON c.personal_info_id = p.info_id; -- 预约详情视图 CREATE VIEW AppointmentDetailView AS SELECT a.appointment_id, s.name AS student_name, c.name AS coach_name, v.name AS venue_name, a.period, a.status FROM appointment a JOIN student s ON a.student_id = s.student_id JOIN coach c ON a.coach_id = c.coach_id JOIN venue v ON a.venue_id = v.venue_id; -- 训练记录视图 CREATE VIEW TrainingRecordView AS SELECT t.record_id, s.name AS student_name, c.name AS coach_name, t.feedback FROM training_record t JOIN student s ON t.student_id = s.student_id JOIN coach c ON t.coach_id = c.coach_id; -- 发票详情视图 CREATE VIEW InvoiceDetailView AS SELECT i.invoice_id, i.amount, i.date, a.student_id, a.coach_id, a.venue_id FROM invoice i JOIN appointment a ON i.appointment_id = a.appointment_id; -- 在appointment表的period字段上创建索引 CREATE INDEX idx_appointment_period ON appointment(period); -- 在feedback表的date字段上创建索引 CREATE INDEX idx_feedback_date ON feedback(date); -- 在invoice表的date字段上创建索引 CREATE INDEX idx_invoice_date ON invoice(date); -- 在training_record表的record_id字段上创建索引 CREATE INDEX idx_training_record_record_id ON training_record(record_id); -- 在booking_slot表的start_time和end_time字段上创建复合索引 CREATE INDEX idx_booking_slot_start_end_time ON booking_slot(start_time, end_time); -- 在account表的status字段上创建索引 CREATE INDEX idx_account_status ON account(status); -- 在student表的name字段上创建索引 CREATE INDEX idx_student_name ON student(name); -- 在coach表的name字段上创建索引 CREATE INDEX idx_coach_name ON coach(name); -- 在venue表的name字段上创建索引 CREATE INDEX idx_venue_name ON venue(name); -- 在personal_info表的email字段上创建唯一索引 CREATE UNIQUE INDEX idx_personal_info_email ON personal_info(email); -- 添加新学员的存储过程 CREATE OR REPLACE FUNCTION AddNewStudent( _student_id VARCHAR(255), _name VARCHAR(255), _password VARCHAR(255), _phone VARCHAR(20), _email VARCHAR(255) ) RETURNS VOID AS $$ DECLARE _info_id INT; BEGIN INSERT INTO personal_info (phone, email) VALUES (_phone, _email) RETURNING info_id INTO _info_id; INSERT INTO student (student_id, name, password, personal_info_id) VALUES (_student_id, _name, _password, _info_id); END; $$ LANGUAGE plpgsql; -- 更新教练电话的存储过程 CREATE OR REPLACE FUNCTION UpdateCoachPhone( _coach_id VARCHAR(255), _new_phone VARCHAR(20) ) RETURNS VOID AS $$ BEGIN UPDATE personal_info SET phone = _new_phone WHERE info_id = (SELECT personal_info_id FROM coach WHERE coach_id = _coach_id); END; $$ LANGUAGE plpgsql; -- 获取某个学生的所有预约的存储过程 CREATE OR REPLACE FUNCTION GetStudentAppointments( _student_id VARCHAR(255) ) RETURNS TABLE(appointment_id INT, coach_name VARCHAR(255), venue_name VARCHAR(255), period VARCHAR(50), status VARCHAR(50)) AS $$ BEGIN RETURN QUERY SELECT a.appointment_id, c.name AS coach_name, v.name AS venue_name, a.period, a.status FROM appointment a JOIN coach c ON a.coach_id = c.coach_id JOIN venue v ON a.venue_id = v.venue_id WHERE a.student_id = _student_id; END; $$ LANGUAGE plpgsql; -- 获取某个教练的所有反馈的存储过程 CREATE OR REPLACE FUNCTION GetCoachFeedbacks( _coach_id VARCHAR(255) ) RETURNS TABLE(feedback_id INT, content TEXT, date DATE) AS $$ BEGIN RETURN QUERY SELECT f.feedback_id, f.content, f.date FROM feedback f JOIN training_record t ON f.feedback_id = t.feedback_id WHERE t.coach_id = _coach_id; END; $$ LANGUAGE plpgsql; -- 获取某个场地的所有可用时间段的存储过程 CREATE OR REPLACE FUNCTION GetAvailableSlotsForVenue( _venue_id INT ) RETURNS TABLE(slot_id INT, start_time TIME, end_time TIME) AS $$ BEGIN RETURN QUERY SELECT bs.slot_id, bs.start_time, bs.end_time FROM booking_slot bs LEFT JOIN appointment a ON bs.venue_id = a.venue_id AND bs.start_time <= a.period::time AND bs.end_time >= a.period::time WHERE bs.venue_id = _venue_id AND a.appointment_id IS NULL; END; $$ LANGUAGE plpgsql; -- 当插入新的学生时,自动在personal_info表中插入一条记录 CREATE OR REPLACE FUNCTION InsertPersonalInfoOnStudentInsert() RETURNS TRIGGER AS $$ BEGIN INSERT INTO personal_info (phone, email) VALUES ('', ''); NEW.personal_info_id := currval('personal_info_info_id_seq'); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_insert_personal_info_on_student_insert BEFORE INSERT ON student FOR EACH ROW EXECUTE FUNCTION InsertPersonalInfoOnStudentInsert(); -- 当删除一个教练时,自动删除其关联的personal_info记录 CREATE OR REPLACE FUNCTION DeletePersonalInfoOnCoachDelete() RETURNS TRIGGER AS $$ BEGIN DELETE FROM personal_info WHERE info_id = OLD.personal_info_id; RETURN OLD; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_delete_personal_info_on_coach_delete AFTER DELETE ON coach FOR EACH ROW EXECUTE FUNCTION DeletePersonalInfoOnCoachDelete(); -- 当插入新的预约时,检查是否已经有重叠的时间段 CREATE OR REPLACE FUNCTION CheckOverlapBeforeAppointmentInsert() RETURNS TRIGGER AS $$ DECLARE overlap_count INT; BEGIN SELECT COUNT(*) INTO overlap_count FROM appointment a WHERE a.venue_id = NEW.venue_id AND ((a.period = NEW.period) OR (a.period < NEW.period AND a.period + INTERVAL '1 hour' > NEW.period) OR (a.period > NEW.period AND a.period < NEW.period + INTERVAL '1 hour')); IF overlap_count > 0 THEN RAISE EXCEPTION 'There is an overlapping appointment at the same time and place.'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_check_overlap_before_appointment_insert BEFORE INSERT ON appointment FOR EACH ROW EXECUTE FUNCTION CheckOverlapBeforeAppointmentInsert(); -- 当更新发票金额时,确保金额不小于零 CREATE OR REPLACE FUNCTION EnsureInvoiceAmountNonNegative() RETURNS TRIGGER AS $$ BEGIN IF NEW.amount < 0 THEN RAISE EXCEPTION 'Invoice amount cannot be negative.'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_ensure_invoice_amount_non_negative BEFORE UPDATE ON invoice FOR EACH ROW EXECUTE FUNCTION EnsureInvoiceAmountNonNegative(); -- 创建角色 CREATE ROLE AdminRole LOGIN PASSWORD 'admin_password'; CREATE ROLE CoachRole LOGIN PASSWORD 'coach_password'; CREATE ROLE StudentRole LOGIN PASSWORD 'student_password'; -- 授予AdminRole权限 GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE account_account_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE venue_venue_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE student_student_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE coach_coach_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE appointment_appointment_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE feedback_feedback_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE invoice_invoice_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE personal_info_info_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE training_record_record_id_seq TO AdminRole; GRANT USAGE, SELECT, UPDATE ON SEQUENCE booking_slot_slot_id_seq TO AdminRole; -- 授予CoachRole权限 GRANT SELECT, INSERT, UPDATE ON appointment TO CoachRole; GRANT SELECT, INSERT, UPDATE ON feedback TO CoachRole; GRANT SELECT, INSERT, UPDATE ON training_record TO CoachRole; -- 授予StudentRole权限 GRANT SELECT, INSERT, UPDATE ON appointment TO StudentRole; GRANT SELECT, INSERT, UPDATE ON feedback TO StudentRole; GRANT SELECT, INSERT, UPDATE ON training_record TO StudentRole; GRANT SELECT ON invoice TO StudentRole;