<# 从《FMS新系统核心表结构设计》第 16 节生成 sql/fms_workflow.sql 用法(任意目录均可执行): pwsh -File sql/tools/gen_workflow_sql.ps1 约定: - §16 是表结构的唯一来源;改完文档重跑本脚本,不要手改生成物; - 生成物与 sql/fms_core.sql 同风格:GO 分隔、UTF-8 无 BOM; - SQL Server 不支持建表内联注释,列注释同时写入扩展属性 MS_Description; - 枚举在文档的列注释里按「编码(中文)」书写,脚本原样搬运到注释和扩展属性。 #> [CmdletBinding()] param( [string]$Doc, [string]$Section = '## 16. 工作流与审批', [string]$Out ) $ErrorActionPreference = 'Stop' $root = Split-Path (Split-Path $PSScriptRoot) if (-not $Doc) { $Doc = Join-Path $root 'FMS新系统核心表结构设计.md' } if (-not $Out) { $Out = Join-Path $root 'sql\fms_workflow.sql' } if (-not (Test-Path -LiteralPath $Doc)) { throw "找不到文档:$Doc" } $text = Get-Content -Raw -Encoding UTF8 -LiteralPath $Doc $start = $text.IndexOf($Section) if ($start -lt 0) { throw "文档中找不到章节:$Section" } $sec = $text.Substring($start) $buf = [System.Collections.Generic.List[string]]::new() $head = @( '/* ============================================================================' ' FMS 工作流与审批表建表脚本(wf_*)' '' ' 依据文档:FMS新系统核心表结构设计.md §16 工作流与审批' ' 语义设计见 FMS工作流与审批设计.md' '' ' 使用说明:' ' 1. 执行前先切换到目标数据库(USE [数据库名])。' ' 2. 脚本只建表、索引和说明属性,不含初始化数据。' ' 3. 不使用外键、CHECK、触发器;关联完整性和业务校验由业务层处理。' ' 4. SQL Server 不支持建表内联注释,列注释通过扩展属性 MS_Description 持久化,' ' SSMS 的表设计器和列属性说明直接读取。' ' 5. 脚本按新建表编写;表已存在时需先删除后重新执行。' ' ============================================================================ */' '' 'SET NOCOUNT ON;' 'GO' '' ) [void]$buf.AddRange([string[]]$head) $rxSection = [regex]'(?s)### (16\.\d+) ([^\r\n]+)\r?\n.*?```sql\r?\n(.*?)```' $tableCount = 0 $propCount = 0 foreach ($m in $rxSection.Matches($sec)) { $num = $m.Groups[1].Value $title = $m.Groups[2].Value.Trim() $lines = $m.Groups[3].Value -split '\r?\n' $ddl = [System.Collections.Generic.List[string]]::new() $idx = [System.Collections.Generic.List[string]]::new() $cols = [System.Collections.Generic.List[object]]::new() $tbl = '' $tblCmt = '' $inTable = $false for ($i = 0; $i -lt $lines.Count; $i++) { $ln = $lines[$i] if (-not $inTable -and $ln -match '^create table dbo\.(\w+) \(') { $tbl = $Matches[1] if ($i -gt 0 -and $lines[$i - 1] -match '^--\s*(.+)$') { $tblCmt = $Matches[1].Trim() } $inTable = $true $ddl.Add($ln) continue } if ($inTable) { $ddl.Add($ln) if ($ln -match '^\);\s*$') { $inTable = $false; continue } if ($ln -match '^\s*([a-z_][a-z0-9_]*)\s+.*?,\s*--\s*(.+?)\s*$') { $cols.Add([pscustomobject]@{ n = $Matches[1]; c = $Matches[2] }); continue } if ($ln -match '^\s*([a-z_][a-z0-9_]*)\s+.*?\s+--\s*(.+?)\s*$') { $cols.Add([pscustomobject]@{ n = $Matches[1]; c = $Matches[2] }); continue } continue } if ($ln -match '^create (unique )?index') { $idx.Add($ln); continue } if ($ln -match '^\s+on dbo\.' -and $idx.Count -gt 0) { $idx[$idx.Count - 1] = $idx[$idx.Count - 1] + "`n" + $ln } } if (-not $tbl) { continue } $tableCount++ $buf.Add('/* ============================================================================') $buf.Add(" $num $title") $buf.Add(' ============================================================================ */') $buf.Add('') foreach ($l in $ddl) { $buf.Add($l) } $buf.Add('GO'); $buf.Add('') foreach ($s in $idx) { foreach ($sl in ($s -split "`n")) { $buf.Add($sl) } $buf.Add('GO'); $buf.Add('') } $buf.Add('-- 说明属性(MS_Description):SSMS 表设计器与列属性说明的来源') $val = $tblCmt.Replace("'", "''") $buf.Add("exec sys.sp_addextendedproperty @name=N'MS_Description', @value=N'$val',") $buf.Add(" @level0type=N'SCHEMA', @level0name=N'dbo', @level1type=N'TABLE', @level1name=N'$tbl';") $propCount++ foreach ($c in $cols) { $cv = $c.c.Replace("'", "''") $buf.Add("exec sys.sp_addextendedproperty @name=N'MS_Description', @value=N'$cv',") $buf.Add(" @level0type=N'SCHEMA', @level0name=N'dbo', @level1type=N'TABLE', @level1name=N'$tbl', @level2type=N'COLUMN', @level2name=N'$($c.n)';") $propCount++ } $buf.Add('GO'); $buf.Add('') } if ($tableCount -eq 0) { throw "章节 $Section 中没有解析到建表语句" } $new = ($buf -join "`r`n") + "`r`n" $changed = $true if (Test-Path -LiteralPath $Out) { $old = [System.IO.File]::ReadAllText($Out, [System.Text.Encoding]::UTF8) $changed = ($old -ne $new) } [System.IO.File]::WriteAllText($Out, $new, (New-Object System.Text.UTF8Encoding($false))) $state = if ($changed) { '已更新' } else { '无变化' } Write-Output "$state:$Out" Write-Output "表 $tableCount 张、说明属性 $propCount 条、生成 $($buf.Count) 行"