You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

-- 创建数据库
-- 创建数据表
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;