SQL存储过程本身不支持继承,所谓“模拟”是通过主表+子表关联、CASE分发或对象类型组合等方式复用逻辑、区分类型、避免重复判断。

SQL 存储过程本身不支持继承——没有 class、extends 或 virtual 方法,所谓“模拟”,本质是用数据结构 + 逻辑封装逼近继承的语义效果。关键不是语法像不像,而是能否复用父逻辑、区分子类型、避免重复判断。
用主表 + 子表关联实现“继承式建模”
这是最常用也最可控的方式:把公共字段(如 id、created_at、status)放在主表,特有字段(如 admin_level、guest_expiry)拆到子表,靠外键关联。
- 主表(
users)只存通用身份信息,所有角色共享 - 子表(
admins、guests)各自存扩展字段,user_id是外键且唯一 - 存储过程中查“管理员”时,必须
JOIN admins ON users.id = admins.user_id,不能只查users - 插入时先写主表,再根据类型写对应子表;删除需按顺序清理(先子后主),否则外键报错
ERROR 1451 (HY000)
在存储过程中用 CASE WHEN + 类型字段做行为分发
当所有字段都挤在一张表里(比如用 type 字段区分角色),就得靠条件逻辑模拟“多态调用”。这不是真继承,但能统一入口、分流处理。
-
type字段必须非空且受约束(ENUM或CHECK),否则容易漏判 - 不要在每个
IF分支里重复写相同字段赋值,先把公共部分提取出来(如SELECT name, email INTO @name, @email FROM users WHERE id = ?) - 分支内访问特有字段前,务必确认类型匹配,例如
IF @type = 'admin' THEN SELECT admin_level FROM users WHERE id = ?,否则可能读到NULL还以为是业务值 - 性能上,单表加
WHERE type = 'xxx'能走索引;但CASE内部嵌套太多分支会让执行计划变复杂,超过 3–4 种类型建议改用子表
用表值参数 + 用户定义类型封装“类实例”
SQL Server 的 CREATE TYPE ... AS TABLE 可以模拟轻量级“对象实例”,配合存储过程参数,实现类似构造函数 + 方法调用的效果。
- 定义类型时字段名要和业务实体对齐(如
EmployeeType包含id、dept、hire_date),别用泛化名field1 - 存储过程接收该类型参数后,可直接
INSERT INTO real_table SELECT * FROM @input,省去逐字段拼接 - 但它不带行为——你不能在类型定义里写“计算工龄”的方法,只能靠存储过程内部逻辑实现
- 注意:表值参数是只读的,不能在过程中修改它本身;想返回新状态得用输出参数或临时表
Oracle 对象类型里的“伪继承”陷阱
Oracle 支持 OBJECT TYPE 和 TYPE BODY,看起来最接近 OOP,但它的“继承”是靠组合(super ParentType)模拟的,不是语言级特性。
- 子类型里声明
super ParentType字段,本质是嵌套对象,不是真正的this继承链 - 调用
self.super.print_info()是显式委托,不是自动方法查找;如果父类型方法改名,子类型代码不会报错,运行时才崩 -
TYPE BODY必须单独编译,修改父类型后,所有依赖它的子类型体都要手动重新编译,CI/CD 流程里容易漏掉 - 这种写法只适用于 Oracle,MySQL / SQL Server 完全不兼容,跨数据库迁移成本极高
真正难的不是怎么写,而是怎么让团队一致理解“这个 users 表既是基类又是具体类型”“那个 admin_level 字段到底归谁校验”。字段归属模糊、类型判断散落在多处、子表缺失时不报错而是静默返回空——这些才是线上事故最常见的根因。

















