sqlor/aidocs/ddl_template_sqlserver.md
2025-10-05 11:24:24 +08:00

333 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SQL Server DDL 模板技术文档Jinja2 模板)
---
## 简介
`sqlserver_ddl_tmpl` 是一个基于 **Jinja2 模板引擎** 的 SQL Server 数据定义语言DDL生成模板。该模板用于根据元数据动态生成创建表、索引以及添加字段描述的完整 T-SQL 脚本。
支持功能包括:
- 字段类型映射
- 主键定义
- 唯一/普通索引创建
- 使用 `sp_addextendedproperty` 添加中文注释MS_Description
- 自动删除旧表(可选)
---
## 模板结构概览
```jinja2
{% 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. 删除原表
```sql
drop table dbo.{{summary[0].name}};
```
> ⚠️ 此操作会 **无条件删除现有表及其数据**,生产环境慎用。
---
### 2. 创建表
```sql
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. 创建索引
```jinja2
{% 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` 添加注释。
#### 表级描述:
```sql
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}}'
```
#### 字段级描述(逐个循环):
```sql
{% 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]` 结构示例:
```python
{
"name": "user_info", # 表名
"title": "用户基本信息表" # 表中文名/描述
"primary": ["id"] # 主键字段数组
}
```
### `fields` 元素结构示例:
```python
[
{
"name": "id",
"type": "long",
"length": 19,
"dec": 0,
"nullable": "no",
"title": "用户ID"
},
{
"name": "username",
"type": "str",
"length": 50,
"dec": 0,
"nullable": "no",
"title": "用户名"
}
]
```
### `indexes` 元素结构示例:
```python
[
{
"name": "idx_email",
"idxtype": "unique",
"idxfields": ["email"]
},
{
"name": "idx_dept",
"idxtype": "normal",
"idxfields": ["dept_id", "status"]
}
]
```
---
## 示例输出(渲染后)
假设输入如下元数据:
```python
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"]}
]
```
### 渲染结果:
```sql
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'
```
---
## 使用建议与注意事项
1. 🔐 **谨慎使用 `DROP TABLE`**
生产环境中应避免直接删除表。建议改为判断是否存在再操作,或提供开关控制。
2. 💡 推荐扩展:增加 `IF NOT EXISTS` 判断表是否存在:
```sql
IF OBJECT_ID('dbo.{{summary[0].name}}', 'U') IS NOT NULL
DROP TABLE dbo.{{summary[0].name}};
```
3. 🛠 替代 IMAGE 类型:
`IMAGE` 已被弃用,推荐替换为:
```jinja2
{%- elif type=='bin' -%}
VARBINARY(MAX)
```
4. 📅 时间戳类型澄清:
若需存储时间,请使用 `DATETIME2` 并修改模板中 `timestamp` 分支。
5. 🔍 支持更多类型:可根据项目需求扩展 `typeStr` 宏以支持 `xml`, `hierarchyid`, `geometry` 等高级类型。
6. 🧪 测试建议:
在自动化脚本中集成此模板前,务必进行单元测试验证类型映射正确性。
---
## 总结
本模板是一个高效、灵活的 SQL Server 表结构自动生成工具适用于代码生成器、ETL 工具、模型同步系统等场景。结合元数据驱动设计,可大幅提升数据库开发效率并保证一致性。
✅ **优点**
- 类型自动映射
- 支持注释与索引
- 结构清晰易维护
⚠️ **风险提示**
- 包含 `DROP TABLE`,使用需谨慎
- `TIMESTAMP` 和 `IMAGE` 类型需按实际需求调整
---
📅 最后更新2025-04-05
📦 所属模块:数据建模 / DDL 自动生成