8.9 KiB
SQL Server DDL 模板技术文档(Jinja2 模板)
简介
sqlserver_ddl_tmpl 是一个基于 Jinja2 模板引擎 的 SQL Server 数据定义语言(DDL)生成模板。该模板用于根据元数据动态生成创建表、索引以及添加字段描述的完整 T-SQL 脚本。
支持功能包括:
- 字段类型映射
- 主键定义
- 唯一/普通索引创建
- 使用
sp_addextendedproperty添加中文注释(MS_Description) - 自动删除旧表(可选)
模板结构概览
{% macro typeStr(type, len, dec) %}...{% endmacro %}
{% macro nullStr(nullable) %}...{% endmacro %}
{% macro primary() %}...{% endmacro %}
drop table dbo.{{summary[0].name}};
CREATE TABLE dbo.{{summary[0].name}}
(
...
)
-- 创建索引
-- 添加表和列的描述信息
宏(Macros)说明
typeStr(type, len, dec)
将通用字段类型转换为 SQL Server 对应的数据类型。
| 输入参数 | 类型 | 说明 |
|---|---|---|
type |
string | 字段逻辑类型(如 'str', 'int' 等) |
len |
int | 长度或精度(适用于字符串、数值等) |
dec |
int | 小数位数(适用于浮点数) |
映射规则:
| 逻辑类型 | SQL Server 类型 | 说明 |
|---|---|---|
str |
NVARCHAR(len) |
变长 Unicode 字符串 |
char |
CHAR(len) |
定长字符 |
long/int/short |
NUMERIC |
整数类型统一用 NUMERIC(无精度限制) |
float/double/ddouble |
numeric(len, dec) |
精确数值类型,支持小数 |
date/time |
DATE |
日期类型 |
timestamp |
TIMESTAMP |
时间戳(行版本号),注意:非 datetime 类型 |
text |
NVARCHAR(MAX) |
大文本字段 |
bin |
IMAGE |
二进制大对象(已弃用,建议使用 VARBINARY(MAX)) |
| 其他未知类型 | 原样输出 {{type}} |
扩展兼容性 |
⚠️ 注意:SQL Server 的
TIMESTAMP实际是 rowversion 类型,若需时间记录请使用DATETIME2。
nullStr(nullable)
控制字段是否允许为空。
| 参数 | 值示例 | 输出结果 |
|---|---|---|
nullable |
'no' |
NOT NULL |
其他值(如 'yes', 空等) |
—— | (空字符串,即允许 NULL) |
primary()
生成主键约束语句。
- 使用
summary[0].primary中定义的字段列表。 - 输出格式:
, primary key (col1, col2, ...) - 仅在存在主键字段时插入。
主体 DDL 逻辑
1. 删除原表
drop table dbo.{{summary[0].name}};
⚠️ 此操作会 无条件删除现有表及其数据,生产环境慎用。
2. 创建表
CREATE TABLE dbo.{{summary[0].name}}
(
{% for field in fields %}
{{field.name}} {{typeStr(field.type,field.length,field.dec)}} {{nullStr(field.nullable)}}
{%- if not loop.last -%},{%- endif %}
{% endfor %}
{% if summary[0].primary and len(summary[0].primary)>0 %}
{{primary()}}
{% endif %}
)
字段循环说明:
- 遍历
fields列表中每个字段对象。 - 生成字段名 + 类型 + 是否非空。
- 使用
{%- if not loop.last %},{% endif %}控制逗号不加在最后一行。
主键添加条件:
- 当
summary[0].primary存在且长度 > 0 时,调用primary()宏添加主键定义。
3. 创建索引
{% for v in indexes %}
CREATE {% if v.idxtype=='unique' %}UNIQUE{% endif %} INDEX {{summary[0].name}}_{{v.name}}
ON {{summary[0].name}}({{",".join(v.idxfields)}});
{% endfor %}
支持索引类型:
v.idxtype |
生成语句 |
|---|---|
'unique' |
CREATE UNIQUE INDEX ... |
其他(如 'normal', 空值等) |
CREATE INDEX ... |
索引命名规则:
<表名>_<索引名>
例如:user_idx_email 表示表 user 上名为 idx_email 的索引。
4. 添加表与字段描述(MS_Description)
利用系统存储过程 sys.sp_addextendedproperty 添加注释。
表级描述:
EXEC sys.sp_addextendedproperty
@name=N'MS_Description',
@value=N'{{summary[0].title}}',
@level0type=N'SCHEMA', @level0name=N'dbo',
@level1type=N'TABLE', @level1name=N'{{summary[0].name}}'
字段级描述(逐个循环):
{% for field in fields %}
EXEC sys.sp_addextendedproperty
@name=N'MS_Description',
@value=N'{{field.title}}',
@level0type=N'SCHEMA', @level0name=N'dbo',
@level1type=N'TABLE', @level1name=N'{{summary[0].name}}',
@level2type=N'COLUMN', @level2name=N'{{field.name}}'
{% endfor %}
✅ 这些描述可在 SSMS 的“属性”面板或通过查询
sys.extended_properties查看。
输入变量要求(上下文 Context)
模板运行需要以下变量注入:
| 变量名 | 类型 | 必须 | 说明 |
|---|---|---|---|
summary |
list[dict] | 是 | 表基本信息列表,通常只取 [0] |
fields |
list[dict] | 是 | 字段列表 |
indexes |
list[dict] | 否 | 索引配置列表(可为空) |
summary[0] 结构示例:
{
"name": "user_info", # 表名
"title": "用户基本信息表" # 表中文名/描述
"primary": ["id"] # 主键字段数组
}
fields 元素结构示例:
[
{
"name": "id",
"type": "long",
"length": 19,
"dec": 0,
"nullable": "no",
"title": "用户ID"
},
{
"name": "username",
"type": "str",
"length": 50,
"dec": 0,
"nullable": "no",
"title": "用户名"
}
]
indexes 元素结构示例:
[
{
"name": "idx_email",
"idxtype": "unique",
"idxfields": ["email"]
},
{
"name": "idx_dept",
"idxtype": "normal",
"idxfields": ["dept_id", "status"]
}
]
示例输出(渲染后)
假设输入如下元数据:
summary = [{
"name": "user",
"title": "用户表",
"primary": ["id"]
}]
fields = [
{"name": "id", "type": "long", "length": 19, "dec": 0, "nullable": "no", "title": "用户ID"},
{"name": "name", "type": "str", "length": 100, "dec": 0, "nullable": "yes", "title": "姓名"},
{"name": "email", "type": "str", "length": 255, "dec": 0, "nullable": "no", "title": "邮箱"}
]
indexes = [
{"name": "uk_email", "idxtype": "unique", "idxfields": ["email"]}
]
渲染结果:
drop table dbo.user;
CREATE TABLE dbo.user
(
id NUMERIC NOT NULL,
name NVARCHAR(100),
email NVARCHAR(255) NOT NULL,
primary key(id)
)
CREATE UNIQUE INDEX user_uk_email ON user(email);
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'user'
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户ID' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'user', @level2type=N'COLUMN',@level2name=N'id'
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'姓名' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'user', @level2type=N'COLUMN',@level2name=N'name'
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'邮箱' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'user', @level2type=N'COLUMN',@level2name=N'email'
使用建议与注意事项
-
🔐 谨慎使用
DROP TABLE
生产环境中应避免直接删除表。建议改为判断是否存在再操作,或提供开关控制。 -
💡 推荐扩展:增加
IF NOT EXISTS判断表是否存在:IF OBJECT_ID('dbo.{{summary[0].name}}', 'U') IS NOT NULL DROP TABLE dbo.{{summary[0].name}}; -
🛠 替代 IMAGE 类型:
IMAGE已被弃用,推荐替换为:{%- elif type=='bin' -%} VARBINARY(MAX) -
📅 时间戳类型澄清:
若需存储时间,请使用DATETIME2并修改模板中timestamp分支。 -
🔍 支持更多类型:可根据项目需求扩展
typeStr宏以支持xml,hierarchyid,geometry等高级类型。 -
🧪 测试建议:
在自动化脚本中集成此模板前,务必进行单元测试验证类型映射正确性。
总结
本模板是一个高效、灵活的 SQL Server 表结构自动生成工具,适用于代码生成器、ETL 工具、模型同步系统等场景。结合元数据驱动设计,可大幅提升数据库开发效率并保证一致性。
✅ 优点:
- 类型自动映射
- 支持注释与索引
- 结构清晰易维护
⚠️ 风险提示:
- 包含
DROP TABLE,使用需谨慎 TIMESTAMP和IMAGE类型需按实际需求调整
📅 最后更新:2025-04-05
📦 所属模块:数据建模 / DDL 自动生成