【问题标题】:export stored procedures through SQL script通过 SQL 脚本导出存储过程
【发布时间】:2011-07-25 13:53:13
【问题描述】:

曾是:如何使用查询备份选定的存储过程

我想通过命令行(在 SQL Server Management Studio 中)备份 200 个存储过程中的 10 个。有没有简单的方法来做到这一点?

现在我正在使用 Database->Tasks->Generate Scripts 选项,这将引导我通过一系列对话框,在其中选择要导出的 SP。我想让这个过程变得简单,所以我不必从头再来。

注意:我所说的“导出”是指将其打印在屏幕上,这样我就可以将其复制并保存在文本文件中。

【问题讨论】:

  • 顺便说一句,保存到文本文件并不重要,只需在 SSMS 中打印结果就足够了,我可以自己复制并保存。
  • 你能制作一个小型控制台应用程序来读取 SP 定义并将它们写入文本文件吗?不知道你将如何在 tsql 中完成所有这些操作......游标和打印语句会变得很难看。
  • 我的意思是这对我来说是可以接受的。我在 2012 年 1 月之后更新的所有程序,我只想导出这些程序。这实际上会解决我的问题。
  • 当你说“命令行”时,你是指“cmd.exe”命令行,还是SQL Servery查询窗口?
  • @Norla,不是 cmd.exe。我的意思是 SQL Server 管理查询。谢谢。请看下面的一些查询。他们帮助了我,但并不完全。

标签: sql sql-server-2005 stored-procedures backup ssms


【解决方案1】:

使用 INFORMATION_SCHEMA.Routines 怎么样?

DECLARE MY_CURSOR Cursor
FOR
SELECT r.Routine_Definition
FROM INFORMATION_SCHEMA.Routines r 
OPEN MY_CURSOR
    DECLARE @sproc VARCHAR(MAX) 
    FETCH NEXT FROM MY_CURSOR INTO @sproc
    WHILE (@@FETCH_STATUS <> -1)
    BEGIN
        IF (@@FETCH_STATUS <> -2)
        PRINT @sproc
        FETCH NEXT FROM MY_CURSOR INTO @sproc
    END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
GO

编辑

听起来您可能希望在结果集中包含 LAST_ALTERED 日期和定义。

SELECT
    r.LAST_ALTERED,
    r.ROUTINE_NAME,
    r.Routine_Definition
FROM INFORMATION_SCHEMA.Routines r 

【讨论】:

  • 超级。一个问题是,如果查询长度超过 4000 个字符,它会截断查询。有没有办法解决这个问题。如果您将单个存储过程作为单独的记录提取,我也可以。如果要编辑,请添加新查询,保持原样。
  • 还有一种方法可以给它最后修改日期或传递存储过程名称
  • 这太棒了!我必须添加一个过滤器,所以它只返回我的用户创建的程序
【解决方案2】:

您可以使用以下查询选择所需的 SP:

SELECT obj.Name as SPName,

modu.definition as SPDefinition,

obj.create_date as SPCreationDate

FROM sys.sql_modules modu

INNER JOIN sys.objects obj

ON modu.object_id = obj.object_id

WHERE obj.type = 'P'  AND obj.Name IN ('sp1','sp2', ect)

另请参阅:http://www.sqlservercurry.com/2009/03/list-all-stored-procedures-of-database.htmlhttp://www.sqlservercurry.com/2007/12/redirect-select-query-output-to-text.html

【讨论】:

  • 我看到它们只列为 10 条记录,我希望它在 SSMS 中打印结构。正在努力
  • 如何将“modu.definition”的结果添加到临时表中。然后循环遍历该临时表并打印每个结果。您只需要 20 条记录,因此您可以使用 cursus
  • 我想选择这个答案,但是它将所有 SP 打印在一行中,有没有办法提高可读性?
  • Ivo,你能改变一下结果中包含换行符吗?这似乎是唯一的问题。
  • 你可以通过添加 char(13) 和 char(10) 得到一个新行,所以像这样,modu.definition + CHAR(13) + CHAR(10) AS SPDefinition
【解决方案3】:

下面的 SQL 应该做你想做的事。

SET NOCOUNT ON

DECLARE @procs AS TABLE( object_id INT
                        , definition NVARCHAR(MAX)
                        , uses_ansi_nulls BIT
                        , uses_quoted_identifier BIT
                        )
INSERT INTO @procs
SELECT m.object_id
     , m.definition
     , m.uses_ansi_nulls
     , m.uses_quoted_identifier
FROM sys.sql_modules AS m
INNER JOIN sys.objects AS o
    ON m.object_id = o.object_id
WHERE o.type = 'P'

--Change this part to suit your needs...
AND o.name IN ('sproc1'
              ,'sproc2'
              ,'sproc3'
              )
--Optionally filter by date?
--AND o.create_date >= '02/01/2012'


DECLARE @endStmt NCHAR(6)
      , @object_id INT
      , @definition NVARCHAR(MAX)
      , @uses_ansi_nulls BIT
      , @uses_quoted_identifier BIT
SELECT @object_id = MIN(object_id)
     , @endStmt = CHAR(13) + CHAR(10) + 'GO' + CHAR(13) + CHAR(10)
FROM @procs

WHILE ISNULL(@object_id,0) > 0
BEGIN
    SELECT @definition = definition
         , @uses_ansi_nulls = uses_ansi_nulls
         , @uses_quoted_identifier = uses_quoted_identifier
    FROM @procs

    IF @uses_ansi_nulls = 1
        PRINT 'SET ANSI_NULLS ON' + @endStmt
    ELSE
        PRINT 'SET ANSI_NULLS OFF' + @endStmt

    IF @uses_quoted_identifier = 1
        PRINT 'SET QUOTED_IDENTIFIER ON' + @endStmt
    ELSE
        PRINT 'SET QUOTED_IDENTIFIER OFF' + @endStmt

    IF LEN(@definition) <= 4000
        PRINT @definition 
    ELSE
    BEGIN
        DECLARE @crlf VARCHAR(2), @len BIGINT, @offset BIGINT, @part BIGINT
        SELECT @crlf = CHAR(13)+CHAR(10)
             , @len = LEN(@definition)
             , @offset = 1
             , @part = CHARINDEX(@crlf,@definition)-1

        WHILE @offset <= @len
        BEGIN
            PRINT SUBSTRING(@definition,@offset,@part)

            SET @offset = @offset + @part + LEN(@crlf)
            SET @part = CHARINDEX(@crlf,@definition,@offset)-@offset  
        END
    END

    PRINT @endStmt


    SELECT @object_id = MIN(object_id)
    FROM @procs
    WHERE object_id > @object_id
END

如果将上述 SQL 保存为名为 BackUpSprocs.SQL 的文件,则可以运行类似于以下的命令将输出保存到文件中。

SQLCMD -E -S SQLSERVER_NAME -d DATABASE_NAME -i BackUpSprocs.SQL -o Sprocs.txt

【讨论】:

  • 这很好用,但它不会拉长一个。可能它被设计成那样工作吗?
  • @Thecrocodilehunter :我的错,PRINT 语句一次只能打印 4000 个字符。请注意,如果您的 sproc 恰好有 4000 个连续字符而没有发生 CRLF,这肯定会失败,但这种情况不太可能发生。
  • 我明白了,这是打印的限制,我会将输出存储到一个文件中,看看它是如何工作的。
【解决方案4】:
declare @S nvarchar(max) 

set @S = N''
select @S = @S + [definition] + 
                 nchar(13) + nchar(10) + 
                 N'GO' + 
                 nchar(13) + nchar(10)
from sys.sql_modules as m
  inner join sys.objects as o
    on m.object_id = o.object_id
where o.create_date > '20120101' and
      o.name in ('Proc1', 'Proc2', 'ProcN')

select @S
for xml path('')

单击结果窗格中的链接以查看整个脚本。

【讨论】:

  • 我可以做select routine_name1,routine_name2, etc ,因为那是我想要的。
  • @Thecrocodilehunter - 不要以为我明白你想要什么。你想指定你想要的过程而不是获取所有过程还是......?
  • 我想要两个选项。但如果任何一个工作,那仍然是可以接受的。
  • @Thecrocodilehunter 好的。我已经使用 where 子句更新了答案,该子句过滤了按名称导出的过程。如果您想要所有程序,请不要使用它。
  • 我试过 Update1 查询,它没有打印整个子程序,只有两行。与我前一段时间从 answer1 得到的结果基本相同。
【解决方案5】:
SELECT SO.Name as Name, 

SM.definition as SPDefinition, 

obj.create_date as CreationDate 

FROM sys.sql_modules SM

INNER JOIN sys.objects SO

ON SM.object_id = SO.object_id 

WHERE SO.type = 'P'  AND SO.create_date >= '01-01-2012'

看看这个。这可能会对您有所帮助。

【讨论】:

  • obj.create_date 应该是 SO.created_date,但它仍然没有给我想要的输出。
【解决方案6】:

不是 SQL 方式,但我认为您可以通过使用 autoitSikuli 或其他方式自动化您的数据库->任务->生成脚本选项/...更多步骤图形用户界面测试工具。

我尝试了一点 Sikuli 的网络,但对我来说并不是 100% 可靠。

AutoIt v3 是一种免费软件,类似 BASIC 的脚本语言,专为 自动化 Windows GUI 和一般脚本。

【讨论】:

    【解决方案7】:

    我编辑了 MyItchyChin 的脚本,因为我发现了其中的一些缺陷。当@part END”)。我也做了其他小的改动。我的问题现在解决了!非常感谢 MyItchyChin 的初始脚本。

    Obs:我在 SQL Server 2008 R2 中使用此脚本。该脚本还可用于编写函数脚本。

     SET NOCOUNT ON
    
    DECLARE @procs AS TABLE( nome varchar(200),object_id INT
                            , definition NVARCHAR(MAX)
                            , uses_ansi_nulls BIT
                            , uses_quoted_identifier BIT
                            )
    INSERT INTO @procs
    SELECT o.name
         ,m.object_id
         , m.definition
         , m.uses_ansi_nulls
         , m.uses_quoted_identifier
    FROM sys.sql_modules AS m
    INNER JOIN sys.objects AS o
        ON m.object_id = o.object_id
    WHERE 1=1
    --and o.type = 'P'
    AND o.name IN ('proc1')
    
    
    
    DECLARE @endStmt NCHAR(6)
          , @object_id INT
          , @definition NVARCHAR(MAX)
          , @uses_ansi_nulls BIT
          , @uses_quoted_identifier BIT
    
    DECLARE @crlf VARCHAR(2), @len BIGINT, @offset BIGINT, @part BIGINT
    
    SELECT @object_id = MIN(object_id)
         , @endStmt = CHAR(13) + CHAR(10) + 'GO' + CHAR(13) + CHAR(10)
    FROM @procs
    
    declare c cursor for SELECT definition
    ,  uses_ansi_nulls
    ,  uses_quoted_identifier
    FROM @procs
    order by nome asc
    
    open c
    fetch next from c into @definition,@uses_ansi_nulls,@uses_quoted_identifier
    
    while @@fetch_status<>-1
    begin
        IF @uses_ansi_nulls = 1
            PRINT 'SET ANSI_NULLS ON' + @endStmt;
        ELSE
            PRINT 'SET ANSI_NULLS OFF' + @endStmt;
    
        IF @uses_quoted_identifier = 1
            PRINT 'SET QUOTED_IDENTIFIER ON' + @endStmt;
        ELSE
            PRINT 'SET QUOTED_IDENTIFIER OFF' + @endStmt;
    
        --PRINT @definition;
    
        IF LEN(@definition) <= 4000
            PRINT @definition
        ELSE
        BEGIN
    
            SELECT @crlf = CHAR(13)+CHAR(10)
                 , @len = LEN(@definition)
                 , @offset = 1
                 , @part = CHARINDEX(@crlf,@definition)-1
    
            WHILE @offset <= @len AND @part>=0
            BEGIN
    
                --PRINT @offset
                --PRINT @part
                --PRINT LEN(@crlf)
                --PRINT @len
    
                PRINT SUBSTRING(@definition,@offset,@part)
    
                SET @offset = @offset + @part + LEN(@crlf)
                SET @part = CHARINDEX(@crlf,@definition,@offset)-@offset
    
                --PRINT @offset
                --PRINT @part
                --PRINT @len
    
                IF @part < 0 
                PRINT SUBSTRING(@definition,@offset,100)
            END
        END
    
        PRINT @endStmt;
    
    
    fetch next from c into @definition,@uses_ansi_nulls,@uses_quoted_identifier
    end
    close c
    deallocate c
    

    【讨论】:

      【解决方案8】:

      我创建了以下程序,该程序通过所有 SP 和特定 DB 中的视图(可以扩展到函数,...)并将每个代码脚本一一存储到 TXT 文件中。在 MS SQL 2008 R2 和 2014 上测试

      第一部分将 SP 和 Views 的所有脚本插入到 Temp 表中。然后稍后使用 BCP 实用程序。如果您希望可以使用导出 SSIS 包而不是 SP,就像我在此示例中所做的那样。

      DECLARE  @File_name AS VARCHAR(255)
              ,@Folder_path AS VARCHAR(255)
              ,@File_Path_Name AS VARCHAR(255)
              ,@CMD AS VARCHAR(8000)
      
      IF OBJECT_ID('tempdb..#TEMP_AA') IS NOT NULL DROP TABLE #TEMP_AA;
      SELECT 
       T1.NAME AS ObjectName
      ,T1.type AS ObjectType
      ,STUFF(((SELECT ' ' + T.[TEXT]
               FROM (SELECT SC.[id],SC.colid,SC.[TEXT]
                     FROM SYSCOMMENTS sc
                     ) AS T
               WHERE T.[id] = T1.[id]
               ORDER BY T.colid
               FOR XML PATH(''),TYPE
               ).value('.[1]', 'NVARCHAR(MAX)')
               ), 1, 1, '')
       AS ObjectText
      INTO #TEMP_AA
      FROM SYSOBJECTS AS T1
      WHERE 1=1
        AND T1.type IN ('P', 'V') /* Procedures and Views*/
        AND NOT T1.[name] LIKE 'dt_%'
      

      循环通过临时表创建文件名,前缀为 P_ 或 V_,后缀为日期,格式为 YYYYMMDD:

      -- Exporting Scripts one by one into TXT files
      WHILE (SELECT TOP 1 objectName FROM #TEMP_AA) IS NOT NULL
      BEGIN
          SELECT TOP 1 
          @File_name = RTRIM(LTRIM(ObjectType)) + '_' + ObjectName +'_' + REPLACE(CAST(CAST(GETDATE()AS DATE) AS VARCHAR),'-','')
          FROM #TEMP_AA;
      
          IF OBJECT_ID('tempdb..##TEMP_BB') IS NOT NULL DROP TABLE ##TEMP_BB;
          CREATE TABLE ##TEMP_BB (ObjectText VARCHAR(MAX));
          INSERT INTO ##TEMP_BB
          SELECT TOP 1 ObjectText
          FROM #TEMP_AA;
      
          --'Setting File name'
          SET @Folder_Path = 'C:\AAAA\'
          SET @File_Path_Name = @Folder_Path + @File_name + '.txt'
          SET @CMD ='BCP ##TEMP_BB OUT "'+@File_Path_Name+'" -T -c -t "Your Server"'
           -- 'Output via BCP into TXT file'
          EXEC xp_cmdshell @CMD;
      
          --Delete Line From temp which has been procese already
          WITH  CTE AS (SELECT TOP 1 *  FROM  #TEMP_AA)
          DELETE FROM CTE;
      END 
      

      【讨论】:

        猜你喜欢
        • 2011-03-18
        • 2020-12-12
        • 1970-01-01
        • 2018-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多