-- 用户表索引 CREATE INDEX idx_username ON 用户表 (用户名); CREATE INDEX idx_email ON 用户表 (邮箱);
-- 影片表索引 CREATE INDEX idx_movie_name ON 影片表 (影片名称); CREATE INDEX idx_director ON 影片表 (导演); CREATE INDEX idx_movie_rating ON 影片表 (电影评分);
-- 影院表索引 CREATE INDEX idx_cinema_name ON 影院表 (影院名称);
-- 放映厅表索引 CREATE INDEX idx_screening_room_name ON 放映厅表 (放映厅名称);
-- 订单表索引 CREATE INDEX idx_user_id ON 订单表 (所属用户编号); CREATE INDEX idx_showtime_id ON 订单表 (所属场次编号);
-- 订单详情表索引 CREATE INDEX idx_hall_id ON 订单详情表 (所属放映厅); CREATE INDEX idx_movie_id ON 订单详情表 (放映的电影编号);
-- 评论表索引 CREATE INDEX idx_user_id_comment ON 评论表 (所属用户编号); CREATE INDEX idx_movie_id_comment ON 评论表 (所属电影编号);
-- 创建用户信息视图 CREATEVIEW 用户信息视图 AS SELECT 编号 AS 用户编号, 用户名, 邮箱, 角色 FROM 用户表;
-- 创建正在上映电影视图 CREATEVIEW 正在上映电影视图 AS SELECT 编号 AS 电影编号, 影片名称, 上映时间, 票房, 电影状态 FROM 影片表 WHERE 电影状态 ='正在上映';
-- 创建影院放映厅信息视图 CREATEVIEW 影院放映厅信息视图 AS SELECT c.编号 AS 影院编号, c.影院名称, c.影院地址, r.编号 AS 放映厅编号, r.放映厅名称, r.放映厅容量 FROM 影院表 c JOIN 放映厅表 r ON c.编号 = r.所属影院编号;
-- 创建用户订单详情视图 CREATEVIEW 用户订单详情视图 AS SELECT o.编号 AS 订单编号, u.用户名, m.影片名称, d.电影放映时间, o.电影票座位信息, o.订单状态 FROM 订单表 o JOIN 用户表 u ON o.所属用户编号 = u.编号 JOIN 订单详情表 d ON o.所属场次编号 = d.编号 JOIN 影片表 m ON d.放映的电影编号 = m.编号;
-- 创建用户电影评论视图 CREATEVIEW 用户电影评论视图 AS SELECT c.编号 AS 评论编号, u.用户名, m.影片名称, c.评论内容, c.评分, c.评论时间 FROM 评论表 c JOIN 用户表 u ON c.所属用户编号 = u.编号 JOIN 影片表 m ON c.所属电影编号 = m.编号;
-- 创建用户注册存储过程 CREATEOR REPLACE PROCEDURE 用户注册 ( p_username IN VARCHAR2, p_password IN VARCHAR2, p_email IN VARCHAR2, p_role IN VARCHAR2 ) AS BEGIN INSERT INTO 用户表 (用户名, 密码, 邮箱, 角色) VALUES (p_username, p_password, p_email, p_role); END 用户注册; /
-- 创建更新订单状态存储过程 CREATEOR REPLACE PROCEDURE 更新订单状态 ( p_order_id IN NUMBER, p_new_status IN VARCHAR2 ) AS BEGIN UPDATE 订单表 SET 订单状态 = p_new_status WHERE 编号 = p_order_id;
COMMIT; -- 提交事务 END 更新订单状态; /
-- 创建计算电影平均评分函数 CREATEOR REPLACE FUNCTION 计算电影平均评分 ( p_movie_id IN NUMBER ) RETURN NUMBER AS v_average_rating NUMBER; BEGIN SELECTAVG(评分) INTO v_average_rating FROM 评论表 WHERE 所属电影编号 = p_movie_id;
RETURN NVL(v_average_rating, 0); -- 如果没有评分,则返回0 END 计算电影平均评分; /
-- 创建查询用户订单总数函数 CREATEOR REPLACE FUNCTION 查询用户订单总数 ( p_user_id IN NUMBER ) RETURN NUMBER AS v_order_count NUMBER; BEGIN SELECTCOUNT(*) INTO v_order_count FROM 订单表 WHERE 所属用户编号 = p_user_id;
RETURN v_order_count; END 查询用户订单总数; /
-- 自动更新影片评分和参评人数 CREATEOR REPLACE TRIGGER 更新影片评分 AFTER INSERTORUPDATEORDELETEON 评论表 FOREACHROW DECLARE v_电影编号 影片表.编号%TYPE; BEGIN IF INSERTING THEN v_电影编号 := :NEW.所属电影编号; UPDATE 影片表 SET 电影评分 = (SELECTAVG(评分) FROM 评论表 WHERE 所属电影编号 = v_电影编号), 电影参评人数 = (SELECTCOUNT(*) FROM 评论表 WHERE 所属电影编号 = v_电影编号) WHERE 编号 = v_电影编号; ELSIF DELETING THEN v_电影编号 := :OLD.所属电影编号; UPDATE 影片表 SET 电影评分 = (SELECTAVG(评分) FROM 评论表 WHERE 所属电影编号 = v_电影编号), 电影参评人数 = (SELECTCOUNT(*) FROM 评论表 WHERE 所属电影编号 = v_电影编号) WHERE 编号 = v_电影编号; ELSE -- 处理电影变更的情况 IF :NEW.所属电影编号 != :OLD.所属电影编号 THEN -- 更新原电影 UPDATE 影片表 SET 电影评分 = (SELECTAVG(评分) FROM 评论表 WHERE 所属电影编号 = :OLD.所属电影编号), 电影参评人数 = (SELECTCOUNT(*) FROM 评论表 WHERE 所属电影编号 = :OLD.所属电影编号) WHERE 编号 = :OLD.所属电影编号;
-- 更新新电影 UPDATE 影片表 SET 电影评分 = (SELECTAVG(评分) FROM 评论表 WHERE 所属电影编号 = :NEW.所属电影编号), 电影参评人数 = (SELECTCOUNT(*) FROM 评论表 WHERE 所属电影编号 = :NEW.所属电影编号) WHERE 编号 = :NEW.所属电影编号; ELSE -- 只更新当前电影 UPDATE 影片表 SET 电影评分 = (SELECTAVG(评分) FROM 评论表 WHERE 所属电影编号 = :NEW.所属电影编号), 电影参评人数 = (SELECTCOUNT(*) FROM 评论表 WHERE 所属电影编号 = :NEW.所属电影编号) WHERE 编号 = :NEW.所属电影编号; END IF; END IF; END; /
-- 订单支付后更新场次座位 CREATEOR REPLACE TRIGGER 更新场次座位 AFTER UPDATEOF 订单状态 ON 订单表 FOREACHROW WHEN (NEW.订单状态 ='已支付'AND OLD.订单状态 !='已支付') DECLARE v_座位数 NUMBER; BEGIN -- 计算订单中的座位数量(以逗号分隔) v_座位数 := REGEXP_COUNT(:NEW.电影票座位信息, ',') +1;
UPDATE 订单详情表 SET 剩余座位数 = 剩余座位数 - v_座位数 WHERE 编号 = :NEW.所属场次编号; END; /
-- 自动更新场次状态 CREATEOR REPLACE TRIGGER 更新场次状态 AFTER UPDATEOF 剩余座位数 ON 订单详情表 FOREACHROW BEGIN IF :NEW.剩余座位数 <=0THEN UPDATE 订单详情表 SET 场次状态 ='已售罄' WHERE 编号 = :NEW.编号; ELSIF :NEW.剩余座位数 < (:NEW.剩余座位数 + :NEW.剩余座位数 *0.2) THEN-- 示例:少于20%座位时 UPDATE 订单详情表 SET 场次状态 ='即将售罄' WHERE 编号 = :NEW.编号; ELSE UPDATE 订单详情表 SET 场次状态 ='可预订' WHERE 编号 = :NEW.编号; END IF; END; /
-- 新评论自动关联用户名 CREATEOR REPLACE TRIGGER 填充评论用户名 BEFORE INSERTON 评论表 FOREACHROW BEGIN SELECT 用户名 INTO :NEW.所属用户 FROM 用户表 WHERE 编号 = :NEW.所属用户编号; END; /
-- 票房自动累加 CREATEOR REPLACE TRIGGER 更新影片票房 AFTER UPDATEOF 订单状态 ON 订单表 FOREACHROW WHEN (NEW.订单状态 ='已支付'AND OLD.订单状态 !='已支付') DECLARE v_电影编号 影片表.编号%TYPE; BEGIN -- 获取关联的电影编号 SELECT 放映的电影编号 INTO v_电影编号 FROM 订单详情表 WHERE 编号 = :NEW.所属场次编号;
-- 更新票房 UPDATE 影片表 SET 票房 = 票房 + :NEW.订单价格 WHERE 编号 = v_电影编号; END; /
-- 场次时间冲突检查 CREATEOR REPLACE TRIGGER 检查场次冲突 BEFORE INSERTORUPDATEON 订单详情表 FOREACHROW DECLARE v_conflict_count NUMBER; BEGIN SELECTCOUNT(*) INTO v_conflict_count FROM 订单详情表 WHERE 所属放映厅 = :NEW.所属放映厅 AND 编号 != :NEW.编号 -- 排除自身 AND 电影放映时间 BETWEEN :NEW.电影放映时间 -INTERVAL'2'HOUR AND :NEW.电影放映时间 +INTERVAL'2'HOUR;
IF v_conflict_count >0THEN RAISE_APPLICATION_ERROR(-20001, '该放映厅在此时间段已有其他场次安排'); END IF; END; /
-- 票房排行榜 SELECT 影片名称, 票房 FROM 影片表 WHERE 票房 ISNOT NULL ORDERBY 票房 DESC FETCHFIRST10ROWSONLY;
3.1.3. 影院管理操作
-- 新增影院 INSERT INTO 影院表 (影院名称, 影院地址) VALUES ('万达影城(北京CBD店)', '北京市朝阳区建国路93号万达广场');
-- 新增放映厅 INSERT INTO 放映厅表 (放映厅名称, 放映厅容量, 所属影院编号) VALUES ('IMAX厅', 250, (SELECT 编号 FROM 影院表 WHERE 影院名称 ='万达影城(北京CBD店)'));
3.1.4. 场次管理操作
-- 创建新场次 INSERT INTO 订单详情表 ( 所属放映厅, 放映的电影编号, 电影放映时间, 售价, 剩余座位数, 场次状态 ) VALUES ( (SELECT 编号 FROM 放映厅表 WHERE 放映厅名称 ='IMAX厅'), (SELECT 编号 FROM 影片表 WHERE 影片名称 ='流浪地球'), TIMESTAMP'2023-05-20 19:30:00', 65.00, (SELECT 放映厅容量 FROM 放映厅表 WHERE 放映厅名称 ='IMAX厅'), '可预订' );
-- 查询可用场次 SELECT m.影片名称, c.影院名称, h.放映厅名称, s.电影放映时间, s.售价, s.剩余座位数 FROM 订单详情表 s JOIN 影片表 m ON s.放映的电影编号 = m.编号 JOIN 放映厅表 h ON s.所属放映厅 = h.编号 JOIN 影院表 c ON h.所属影院编号 = c.编号 WHERE m.影片名称 ='流浪地球' AND s.电影放映时间 > SYSDATE AND s.剩余座位数 >0;
3.1.5. 订单管理操作
-- 创建新订单 INSERT INTO 订单表 ( 所属用户编号, 所属场次编号, 电影票座位信息, 订单状态, 订单价格 ) VALUES ( (SELECT 编号 FROM 用户表 WHERE 邮箱 ='zhangsan@example.com'), (SELECT 编号 FROM 订单详情表 WHERE 电影放映时间 =TIMESTAMP'2023-05-20 19:30:00'), 'A5,A6,A7', '待支付', 195.00 );
-- 支付订单 UPDATE 订单表 SET 订单状态 ='已支付', 订单支付时间 = SYSDATE WHERE 编号 = (SELECTMAX(编号) FROM 订单表);
-- 查询用户历史订单 SELECT o.订单支付时间, m.影片名称, c.影院名称, h.放映厅名称, s.电影放映时间, o.电影票座位信息, o.订单价格 FROM 订单表 o JOIN 订单详情表 s ON o.所属场次编号 = s.编号 JOIN 影片表 m ON s.放映的电影编号 = m.编号 JOIN 放映厅表 h ON s.所属放映厅 = h.编号 JOIN 影院表 c ON h.所属影院编号 = c.编号 WHERE o.所属用户编号 = (SELECT 编号 FROM 用户表 WHERE 邮箱 ='zhangsan@example.com');
3.1.6. 评论管理操作
-- 添加评论 INSERT INTO 评论表 (所属用户编号, 评论内容, 所属电影编号, 评分) VALUES ( (SELECT 编号 FROM 用户表 WHERE 邮箱 ='zhangsan@example.com'), '特效震撼,中国科幻的里程碑作品', (SELECT 编号 FROM 影片表 WHERE 影片名称 ='流浪地球'), 9.0 );
-- 查询影片评论 SELECT u.用户名, c.评论内容, c.评分, c.评论时间 FROM 评论表 c JOIN 用户表 u ON c.所属用户编号 = u.编号 WHERE c.所属电影编号 = (SELECT 编号 FROM 影片表 WHERE 影片名称 ='流浪地球') ORDERBY c.评论时间 DESC;
3.1.7. 事务处理示例 (购票全流程)
DECLARE v_user_id 用户表.编号%TYPE; v_session_id 订单详情表.编号%TYPE; v_seats VARCHAR2(100) :='B10,B11'; v_seat_count NUMBER :=2; v_price NUMBER; BEGIN -- 获取用户ID SELECT 编号 INTO v_user_id FROM 用户表 WHERE 邮箱 ='zhangsan@example.com';
-- 获取场次信息和价格 SELECT 编号, 售价 INTO v_session_id, v_price FROM 订单详情表 WHERE 编号 =101; -- 假设场次ID为101
-- 验证座位可用性 IF (SELECT 剩余座位数 FROM 订单详情表 WHERE 编号 = v_session_id) < v_seat_count THEN RAISE_APPLICATION_ERROR(-20001, '座位不足'); END IF;
-- 锁定座位 (通过更新场次) UPDATE 订单详情表 SET 剩余座位数 = 剩余座位数 - v_seat_count WHERE 编号 = v_session_id;
-- 模拟支付成功 UPDATE 订单表 SET 订单状态 ='已支付', 订单支付时间 = SYSDATE WHERE 所属用户编号 = v_user_id AND 所属场次编号 = v_session_id;
COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACKTO start_transaction; RAISE; END; /
3.1.8. 复杂查询示例
-- 查询各类型影片平均评分 SELECT 电影类型, ROUND(AVG(电影评分), 2) AS 平均评分, COUNT(*) AS 影片数量 FROM 影片表 GROUPBY 电影类型 HAVINGAVG(电影评分) >6.0 ORDERBY 平均评分 DESC;
-- 查询热门影片(评分高且评论多) SELECT m.影片名称, m.电影评分, COUNT(c.编号) AS 评论数量, SUM(o.订单价格) AS 总票房 FROM 影片表 m LEFTJOIN 评论表 c ON m.编号 = c.所属电影编号 LEFTJOIN 订单详情表 s ON m.编号 = s.放映的电影编号 LEFTJOIN 订单表 o ON s.编号 = o.所属场次编号 GROUPBY m.影片名称, m.电影评分 HAVINGCOUNT(c.编号) >1000 ORDERBY m.电影评分 DESC, 评论数量 DESC;
-- 查询用户观影偏好 SELECT u.用户名, m.电影类型, COUNT(*) AS 观影次数, SUM(o.订单价格) AS 总消费 FROM 订单表 o JOIN 用户表 u ON o.所属用户编号 = u.编号 JOIN 订单详情表 s ON o.所属场次编号 = s.编号 JOIN 影片表 m ON s.放映的电影编号 = m.编号 GROUPBY u.用户名, m.电影类型 ORDERBY 观影次数 DESC;