可通过sys.sql_modules关联sys.objects(type='p'且is_ms_shipped=0)提取用户存储过程定义,注意处理加密对象、bom字符及生成create or alter脚本等细节。

用 sys.sql_modules 配合 sys.objects 提取完整定义
SQL Server 不提供一键导出全部存储过程的内置命令,但可以通过系统视图拼出完整脚本。关键点是:不能只查 sys.sql_modules,因为它不包含对象名和类型信息;必须关联 sys.objects 过滤 type = 'P'(存储过程),同时注意 sql_modules.definition 是 nvarchar(max),能覆盖超长脚本。
常见错误是漏掉 AND o.is_ms_shipped = 0,导致把系统自带的存储过程(如 sp_help)也导出来,干扰后续使用。
- 只查用户数据库,别在
master或msdb里执行 - 确保当前用户有
VIEW DEFINITION权限,否则definition字段返回NULL - 如果存储过程含
GO分隔符或注释跨行,直接拼接不会自动补全,需靠客户端工具处理换行
生成带 CREATE OR ALTER 的可重跑脚本
SQL Server 2016+ 支持 CREATE OR ALTER,比先 DROP 再 CREATE 更安全。但 sys.sql_modules.definition 返回的是原始 CREATE 语句,需要手动替换开头部分。
不能简单用 REPLACE(definition, 'CREATE PROC', 'CREATE OR ALTER PROC') —— 因为有些过程用 CREATE PROCEDURE,有些缩写为 CREATE PROC,还有可能带 schema(如 CREATE PROC dbo.usp_xxx)。稳妥做法是先提取对象名,再拼接新头。
- 用
QUOTENAME(SCHEMA_NAME(o.schema_id)) + '.' + QUOTENAME(o.name)拼出标准三段式名称 - 定义字段可能含 BOM 或不可见控制字符,导出前建议用
TRIM和REPLACE(definition, CHAR(0), '')清理 - 若目标环境是 SQL Server 2014 或更早,必须改回
IF EXISTS (SELECT ...) DROP PROC ...结构
用 sqlcmd 命令行批量保存到文件
SSMS 的“生成脚本”向导容易卡死或漏对象,尤其当库中有几百个存储过程时。用 sqlcmd 直接调用查询,输出到文件更稳定。
命令示例:sqlcmd -S localhost -d YourDB -E -Q "SELECT m.definition FROM sys.objects o INNER JOIN sys.sql_modules m ON o.object_id = m.object_id WHERE o.type = 'P' AND o.is_ms_shipped = 0 ORDER BY o.name" -o "procs.sql" -h -1 -s "" -w 1000
-
-h -1关闭列标题,避免第一行出现definition字符串 -
-s ""设置分隔符为空,防止每行末尾多出制表符 -
-w 1000扩大行宽,避免 definition 被截断换行 - 该命令只输出定义体,不含
CREATE头——如需完整脚本,得把前面拼CREATE OR ALTER的逻辑写进查询里
注意加密存储过程无法导出明文定义
如果某个存储过程创建时用了 WITH ENCRYPTION,那么 sys.sql_modules.definition 就是 NULL,且没有任何替代视图能还原它。这是 SQL Server 的硬性限制,不是权限或版本问题。
检查方式很简单:SELECT name FROM sys.objects WHERE type = 'P' AND object_id IN (SELECT object_id FROM sys.sql_modules WHERE definition IS NULL)
- 结果列表里的过程,导出脚本时只能留空或加注释说明“ENCRYPTED”
- 不要尝试用 DAC 或内存 dump 等非常规手段——既违法授权协议,又极易损坏数据库
- 生产库中若有大量加密过程,建议推动逐步解密并加入源码管理,而不是依赖导出应急
真正麻烦的不是怎么导,而是导出来之后要不要验证每个脚本都能独立执行——比如有跨数据库引用、依赖特定排序规则、或用到了尚未导出的自定义类型。这些没法靠一个查询解决,得结合实际部署流程来兜底。










