以编程方式检索与SQL Server Management Studio gui返回的源相同的SQL Server存储过程源吗?


67

关于如何从SQL Server 2005中以编程方式获取完全相同的存储过程源的任何指示,就像我在SQL Server Management Studio中右键单击该存储过程并选择“修改”一样?

我正在尝试使用SMO,但有一些文本差异。该过程始终具有CREATE而不是ALTER,并且标头中存在一些差异,例如,我以编程方式获取的版本中缺少GO。我可以解决这些问题,但是也许有更好的方法?

同样,我在SQL Server 2005中,使用SMSE。通过Visual Studio 8 2008使用SMO。

更新:得到了一些答案,这些答案讲述了如何检索存储过程的基础知识。我正在寻找的是检索与GUI生成的文本相同(或几乎相同)的文本。

示例:对于sp_mysp,请在Management Studio中右键单击,然后选择“修改”。这将产生:

    使用[MY_DB]  
    走  
    / ******对象:StoredProcedure [dbo]。[sp_mysp]脚本日期:2009年1月1日17:43:18 ****** /  
    设置ANSI_NULLS ON  
    走  
    将QUOTED_IDENTIFIER设置为ON  
    走  
    -============================================
    -作者:      
    -创建日期: 
    -说明: 
    -============================================
    更改程序[dbo]。[sp_mysp]

我想以编程方式获取相同的内容(请注意标头中的GO,并且它是ALTER PROCEDURE的事实。理想情况下,我想以最小的编程方式修复所获取的源代码。

我很高兴只收到与脚本日期详细信息不同的内容。。。


如果您担心将结果输入到源代码控制系统中,在我看来,唯一真正的限制是,每次使用相同的sproc生成时,它必须相同。为什么渴望保持事物看起来像UI生成的输出?
Mark Brittingham

好问题。我有一堆sps,最初是通过从gui保存而获得的。我只需要修改它们。我以为如果有一些钩子可以获取与gui相同的输出,为什么不这样做,但是看起来像是sp_helptext或smo(cur。mthd)。谢谢!
DWright

我们欢迎并感谢您选择我的答案答案。顺便说一句:我在SO上也有相同的经验-我提出一个问题,但最后没有答案,而是采取了不同的解决方案。
Mark Brittingham,2009年

哦,是的-并签出MS Database Publishing Wizard。如果您的数据库中还有一些要保存的“核心”信息,这将特别有用!
Mark Brittingham,2009年

Answers:


83
EXEC sp_helptext 'your procedure name';

这避免了INFORMATION_SCHEMA方法的问题,如果存储过程过长,该过程将被切断。

更新:David写道这与他的存储过程不同...也许是因为它以“记录”形式返回行以保留格式?如果要以更“自然”的格式查看结果,可以先使用Ctrl-T(以文本形式输出),并且它应该完全按照输入的内容打印出来。如果您在代码中执行此操作,那么进行一次foreach以完全相同的方式将结果汇总在一起是微不足道的。

更新2:这将为源提供一个“创建过程”,而不是一个“更改过程”,但是我知道没有办法使它使用“更改”。不过,这不是一件小事吗?

更新3:请参阅注释以获取有关如何在源代码控制系统中维护SQL DDL(数据库结构)的更多见解。这确实是这个问题的关键。


1
有用,但来源不同。
DWright

是的,相当琐碎。我正在尝试提出一种简单的方法,将SQL Server Express proc放入外部源代码控件中,并将当前proc(在db中)与该源代码控件进行比较-这就是为什么总能准确获得与GUI通过修改生成的源相同。
DWright

2
实际上,用于自动生成所有这些内容的存储过程非常简单。通过sys.objects进行游标,其中type ='P'以获取所有存储过程,将每个存储过程提交给sp_HelpText,然后在换出ALTER的情况下游标搜索结果。生成带有打印的输出,保存到文件。提交给SVN
Mark Brittingham,2009年

1
每次都会为您提供相同的输出,以便可以在源代码控制系统(例如SVN)中使用它。您可以做的另一件事是使用Microsoft SQL Server数据库发布向导(将其谷歌搜索)生成数据库的整个结构并将其提交给SVN。
Mark Brittingham

16

您将不得不手工编写代码,SQL Profiler显示了以下内容。

SMSE在生成语句时会执行很长的查询字符串。

以下查询(或其类似内容)用于提取文本:

SELECT
NULL AS [Text],
ISNULL(smsp.definition, ssmsp.definition) AS [Definition]
FROM
sys.all_objects AS sp
LEFT OUTER JOIN sys.sql_modules AS smsp ON smsp.object_id = sp.object_id
LEFT OUTER JOIN sys.system_sql_modules AS ssmsp ON ssmsp.object_id = sp.object_id
WHERE
(sp.type = N'P' OR sp.type = N'RF' OR sp.type='PC')and(sp.name=N'#test___________________________________________________________________________________________________________________00003EE1' and SCHEMA_NAME(sp.schema_id)=N'dbo')

它返回纯CREATE,然后在代码中的某处用ALTER替换。

SET ANSI NULL内容以及GO语句和日期都在此之前。

使用sp_helptext,它更简单...


12

你以编程方式说的对吧?我希望C#可以。我知道您说过您尝试过SMO,但它并没有完全满足您的要求,因此这可能对您的请求而言并不完美,但是它将以编程方式读出合法的SQL语句,您可以运行这些语句来重新创建存储过程。如果没有所需的GO语句,则可以假定的每个字符串StringCollection都可以在GO其后有一个。您可能未在日期和时间中得到该评论,但是在我类似的听起来很不错的项目(必须单独备份所有内容的大型部署工具)中,这样做相当不错。如果您有一个想要使用的以前的基础,但是仍然有原始数据库可以运行,那么我将考虑投入最初的精力并对该输出进行标准化。

using System.Data.SqlClient;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
…
string connectionString = … /* some connection string */;
ServerConnection sc = new ServerConnection(connectionString);
Server s = new Server(connection);
Database db = new Database(s, … /* database name */);
StoredProcedure sp = new StoredProcedure(db, … /* stored procedure name */);
StringCollection statements = sp.Script;

8

使用以下select语句获取所有完整定义:

select ROUTINE_DEFINITION from INFORMATION_SCHEMA.ROUTINES Where ROUTINE_NAME='someprocname'

我的猜测是SSMS和其他工具会读出来并在必要时进行更改,例如将CREATE更改为ALTER。据我所知,SQL不存储该过程的其他表示形式


2
这当然有助于检索主要的存储过程主体(尽管也可以使用sp_helptext)。但是,与右键单击该过程并选择“修改”时,GUI产生的结果并不相同。谢谢,不过。
DWright

DWright,您能发表一些小小的变化示例吗?就像您可以组成一个触发Northwind示例数据库的proc。然后发布两个来源。
BuddyJoe

2DWright:实际上,这是GUI存在缺陷,并且没有显示确切的来源(例如,行号被拧紧)。
ivan_pozdeev

5

我同意马克的看法。我将输出设置为文本模式,然后设置为sp_HelpText'sproc'。我将其绑定到Crtl-F1以使其变得容易。


@BankZ您如何将其绑定到ctrl-f1?
Max Hodges


2

我只想指出,您无需使用查找和替换来更改创建过程来更改过程,而是可以使用拖放,也可以将其放在顶部,并且确实需要文本搜索。

IF exists (SELECT * FROM sys.objects 
        WHERE object_id = OBJECT_ID(N'sp_name')
            and type in ('P','V') --procedure or view
        )
    DROP sp_name
GO

如果您确定它在那里,我想您也可以放下它,但是我不建议这样做。不要忘了走,因为创建过程必须是批处理中的第一个也是唯一的语句。

还是懒惰的方法:

IF OBJECT_ID(N'sp_name') is not null
    DROP sp_name
GO

4
危险是,如果后续创建失败,则您将丢失该过程。
siride

0

我通过link看到了一篇文章。有四种方法,我在这里做了简短的总结来帮助其他程序员。

  1. EXEC sp_helptext'sp_name';

  2. SELECT OBJECT_ID('sp_name')

  3. SELECT OBJECT_DEFINITION(OBJECT_ID('sp_name'))AS [定义];

  4. SELECT * FROM sys.sql_modules在哪里object_id = object_id('sp_name');


-2

要更改存储过程,请使用以下C#代码:

SqlConnection con = new SqlConnection("your connection string");
con.Open();
cmd.CommandType = System.Data.CommandType.Text;
string sql = File.ReadAllText(YUOR_SP_SCRIPT_FILENAME);
cmd.CommandText = sql;   
cmd.Connection = con;
cmd.ExecuteNonQuery();
con.Close();

注意事项:

  1. 确保连接字符串中的USER有权更改SP
  2. GO,SET ANSI_NULLS XX,SET QUOTED_IDENTIFIER从脚本文件中删除所有语句。(如果不这样做,则SqlCommand将引发错误)。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.