【问题标题】:how save SQL stored procedures to .sql files via batch如何通过批处理将 SQL 存储过程保存到 .sql 文件
【发布时间】:2009-02-20 08:34:11
【问题描述】:

我想将我的 MS SQL Server 2005 存储过程自动保存到 .sql 文件(我更喜欢可以通过 .bat 调用的工具),这样我就不必手动单击每个存储过程并保存它。

我已经从 devio IT 找到了 SMOscript,但它会收集所有表和存储过程,这需要一些时间。是否有任何类似的工具可以定义要导出的存储过程?此外,与手动导出为 CREATE 的脚本存储过程相比,我还缺少 SMOScript 未添加到导出文件中的 USE 子句。

最好的问候 肖恩

【问题讨论】:

    标签: sql sql-server-2005 stored-procedures export


    【解决方案1】:

    使用脚本创建批处理文件(抱歉格式化,但确实应该内联执行批处理):

    osql -U %1 -P %2 -S %3 -d %4 -h-1 -Q "SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -n -o "sp_list.txt"
    for /f %%a in (sp_list.txt) do osql -U %1 -P %2 -S %3 -d %4 -h-1 -Q "SELECT ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_NAME = '%%a'" -n -o "%%a.sql"
    

    将其命名为“run.bat”。现在,要执行批量使用参数:
    run.bat [用户名] [密码] [服务器名] [数据库]
    例如:
    run.bat sa pwd111 localhost\SQLEXPRESS master
    首先,所有存储过程名称将存储在文件 sp_list.txt 中,然后一个接一个地存储在单独的脚本文件中。唯一的问题 - 每个脚本的最后一行带有结果计数 - 我正在处理它:)

    已编辑:已修复查询中的错误

    删除“受影响的行”行
    好的,现在我们需要再创建一批:

    type %1 | findstr /V /i %2  > xxxtmpfile 
    copy xxxtmpfile %1 /y /v
    del xxxtmpfile
    

    将其命名为“line_del.bat”。看,第一个参数是要处理的文件,第二个 - 搜索要删除的行的字符串。现在修改主批处理(再次抱歉格式化):

    osql -U %1 -P %2 -S %3 -d %4 -h-1 -Q "SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -n -o "sp_list.txt"
    call line_del sp_list.txt "rows affected"
    call line_del sp_list.txt "row affected"
    for /f %%a in (sp_list.txt) do osql -U %1 -P %2 -S %3 -d %4 -h-1 -Q "SELECT ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_NAME = '%%a'" -n -o "%%a.sql" 
    for /f %%a in (sp_list.txt) do call line_del %%a.sql "rows affected"
    for /f %%a in (sp_list.txt) do call line_del %%a.sql "row affected"
    

    查看相关文章:
    Simple programming commands in a batch environment
    osql Utility
    MSSQL: How do you script Stored Procedure creation with code?
    Delete certain lines in a txt file via a batch file

    :) 你可能会注意到,最后两个来自 SO!

    【讨论】:

    • 非常感谢!我已经尝试了一些,但在身份验证方面遇到了一些问题(osql 无法连接)。我会在接下来的几天再试一次......最好的问候
    • 这不会中断大型触发吗?当我运行时: SELECT ROUTINE_NAME , max(len(ROUTINE_DEFINITION)) FROM INFORMATION_SCHEMA.Routines group by ROUTINE_NAME order by 2 desc;我得到了很多 4000 个字符的 proc。很确定您需要退出 sys.cmets 才能获得正确的数据。
    • 糟糕,这应该是上面评论中的 syscmets。
    【解决方案2】:

    在 SQL Server Management Studio 中有一个替代方案,为数据库编写脚本...

    展开对象资源管理器视图以找到数据库,右键单击并选择“任务:生成脚本”

    您可以从那里编写所有对象的脚本,只是存储的 preocedures,以及介于两者之间的任何内容。一页上有很多选项,尽管我更改的主要选项是: - “如果不存在则包括”

    通过将该选项设置为“FALSE”,您将获得 CREATE 语句的完整列表。

    然后您可以选择将对象编写到新的查询窗口或文件中。

    【讨论】:

    • 感谢您的提示,不幸的是,这对我来说有一些缺点 - 我每次都必须手动完成所有步骤(没有自动/批处理) - 所有选定的存储过程都保存到一个 .sql 中文件 - 不保存任何 cmets
    【解决方案3】:

    添加 SET NOCOUNT ON 确实消除了对 line_del.bat 的需要,但是用 sys.sql_modules 替换 syscmets 会导致每个存储过程被截断为 258 个字符。因此,为了获得最佳结果,我使用的代码是:

    sqlcmd -E -S SERVER-d DB -h-1 -Q "SET NOCOUNT ON SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -o "sp_list.txt"
    for /f %%a in (sp_list.txt) do sqlcmd -E -S SERVER-d DB -h-1 -Q "SET NOCOUNT ON SELECT text from dbo.syscomments WHERE id = OBJECT_ID('%%a')" -o "%%a.sql"
    

    哪个有效,并且不需要使用 line_del.bat。当我使用 SSMS 向导(任务/生成脚本/存储过程/全选)进行手动导出时,我没有得到的是:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    

    在每个 .sql 的开头,以及尾随的 GO 命令。不是非常重要,但有一点需要注意。感谢 Max Gontar、Seansilver 和 Lee 的贡献!我现在可以自动备份数据库中的存储过程,并应用版本控制。

    【讨论】:

      【解决方案4】:

      不久前我想做同样的事情,最后我做了一个小的 vbscript。

      看这里Source Control and stored procedures

      【讨论】:

        【解决方案5】:

        我使用了 sqlcmd 和 -E 而不是用户,通过。到目前为止,这工作正常,只有超过 4000 个字符的存储过程会有换行符

        sqlcmd -E -S SERVER -d DB -h-1 -Q "SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -o "sp_list.txt"
        call line_del sp_list.txt "rows affected"
        call line_del sp_list.txt "row affected"
        for /f %%a in (sp_list.txt) do sqlcmd -E -S SERVER -d DB -h-1 -Q "SELECT text from dbo.syscomments WHERE id = OBJECT_ID('%%a')" -o "%%a.sql"
        for /f %%a in (sp_list.txt) do call line_del %%a.sql "rows affected"
        for /f %%a in (sp_list.txt) do call line_del %%a.sql "row affected"
        

        最好的问候 肖恩

        【讨论】:

          【解决方案6】:

          我添加了 SET NOCOUNT ON 以消除对 line_del.bat 的需要。还将 syscmets 替换为 sys.sql_modules (SQL 2005)。我也可以使用 OBJECT_DEFINITION 函数,但它比 sys.sql_modules 慢。

          sqlcmd -E -S SERVER -d DB -h-1 -Q "SET NOCOUNT ON SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -o "sp_list.txt" for /f %%a in (sp_list.txt) do sqlcmd -E -S SERVER -d DB -h-1 -Q "SET NOCOUNT ON SELECT definition from sys.sql_modules WHERE object_id = OBJECT_ID('%%a')" -o "%%a.sql"
          

          【讨论】:

          • 不是一个独立的答案,应该是对您正在谈论的答案的评论。
          【解决方案7】:

          感谢以上所有人的帮助,并将此处留给像我这样的其他 sqlcmd 菜鸟可以找到。适用于 sql server 2005。objectName 是一个过程、视图等名称。

          :reset
          
          -- :setvar ObjectName "objectName"  -- works
          :setvar ObjectName objectName  -- works too
          declare @sql varchar(max);
          set @sql = 'select text from dbo.syscomments where id = object_id(upper("' + '$(ObjectName)' + '"))';
          -- exec sp_helptext $(ObjectName)  -- quick n easy but gets chopped to 256 width
          /*   4000 byte limit
          set @sql = 
             'select view_definition 
              from information_schema.views 
              where upper(table_name) = upper("' + '$(ObjectName)' + '")';
          */
          :out $(ObjectName).sql
          
          exec(@sql)
          go
          
          :out stdout
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-21
            • 2011-03-29
            • 2012-10-10
            • 2013-05-17
            • 1970-01-01
            • 2020-06-03
            相关资源
            最近更新 更多