[英]Is there a solution for getting the default value of the parameters of a given stored procedure?
我现在使用INFORMATION_SCHEMA.PARAMETERS
获取有关存储过程参数的信息。 我需要知道参数的默认值。 是否有获取给定存储过程参数默认值的解决方案?
Declare @pSProcName NVARCHAR(MAX)='ProcedureName'
DECLARE @SQLTEXT NVARCHAR(MAX),@start int ,@end int,@SearchCode NVARCHAR(MAX)
SELECT @SQLTEXT =OBJECT_DEFINITION(OBJECT_ID(@pSProcName))
SELECT @start=CHARINDEX('@',@SQLTEXT,1)
SELECT @end =min(val) FROM (
SELECT PATINDEX('%'+CHAR(10)+'AS'+CHAR(10)+'%',@SQLTEXT ) AS val
UNION ALL SELECT PATINDEX('%'+CHAR(10)+'AS'+CHAR(13)+'%',@SQLTEXT )
UNION ALL SELECT PATINDEX('%'+CHAR(13)+'AS'+CHAR(10)+'%',@SQLTEXT )
UNION ALL SELECT PATINDEX('%'+CHAR(13)+'AS'+CHAR(13)+'%',@SQLTEXT )
UNION ALL SELECT PATINDEX('%'+CHAR(10)+'AS'+CHAR(32)+'%',@SQLTEXT )
UNION ALL SELECT PATINDEX('%'+CHAR(32)+'AS'+CHAR(10)+'%',@SQLTEXT )
UNION ALL SELECT PATINDEX('%'+CHAR(32)+'AS'+CHAR(32)+'%',@SQLTEXT )
UNION ALL SELECT PATINDEX('%'+CHAR(13)+'AS'+CHAR(32)+'%',@SQLTEXT )
UNION ALL SELECT PATINDEX('%'+CHAR(32)+'AS'+CHAR(13)+'%',@SQLTEXT )
) S
Where s.val <> 0
SELECT @SearchCode=SUBSTRING(@sqltext,@start,@end - @start)
SELECT S2.parameter_id,S2.ParameterName,S2.DataType,S1.Default_Value FROM
(
SELECT CASE WHEN Data like '%=%' then RIGHT(Data,len(Data)-CHARINDEX('=',Data,1)) ELSE '' END as Default_Value,
CASE WHEN Data like '%=%' then 1 ELSE 0 END as Has_default_Value
,Data FROM(
SELECT LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) AS Data
FROM
(
SELECT CAST ('<M>' + REPLACE(@SearchCode, ',', '</M><M>') + '</M>' AS XML) AS Data
) AS A CROSS APPLY Data.nodes ('/M') AS Split(a))s
)S1
INNER JOIN
(
Select p.parameter_id,p.name as ParameterName,UPPER(t.name) AS DataType from sys.all_parameters p
Inner JOIN sys.types t
on t.user_type_id = p.user_type_id
where Object_name(OBJECT_ID) = @pSProcName
) S2
ON S1.Data LIKE '%'+S2.ParameterName+'%'+S2.DataType+'%'
如果您通过 SQL 命令解析 SQL 代码...
该信息未存储在系统表中。 从sys.parameters (您期望的位置)、has_default_value 和 default_value 列中,我们被告知要解析 SQL:
SQL Server 仅维护此目录视图中 CLR 对象的默认值; 因此,对于 Transact-SQL 对象,此列的值为 0。 要查看 Transact-SQL 对象中参数的默认值,请查询 sys.sql_modules 目录视图的定义列,或使用 OBJECT_DEFINITION 系统函数。
如果 has_default_value 为 1,则该列的值为该参数的默认值; 否则,NULL。
证明:
CREATE PROC dbo.Paramtest (@foo int = 42)
AS
SET NOCOUNT ON;
GO
SELECT OBJECT_NAME(object_id), has_default_value, default_value
FROM sys.parameters
WHERE name = '@foo' AND object_id = OBJECT_ID('dbo.Paramtest')
-- gives Paramtest, 0, NULL
@N.Dinesh.Reddy 有一个惊人的答案。 我对其进行了一些修改,以支持参数定义之间的换行,以及支持默认值包含 XML 字符的@Parameter1 NVARCHAR(MAX) = N'<'
(例如@Parameter1 NVARCHAR(MAX) = N'<'
)。
DECLARE @ProcedureName NVARCHAR(MAX) = N'dbo.TestProcedure';
DECLARE @ObjectId INT = OBJECT_ID(@ProcedureName);
DECLARE @DefinitionText NVARCHAR(MAX) = REPLACE(REPLACE(OBJECT_DEFINITION(@ObjectId), CHAR(10), N' '), CHAR(13), N' ');
DECLARE @FirstParameterIndex INT = CHARINDEX('@',@DefinitionText, 1);
-- Pull out only the parameters, and xml-encode them.
SET @DefinitionText = (SELECT SUBSTRING(@DefinitionText, @FirstParameterIndex, PATINDEX(N'% AS %', @DefinitionText) - @FirstParameterIndex) FOR XML PATH(N''));
-- Find the parameter names.
SELECT b.parameter_id, b.name, b.system_type_id, b.user_type_id, b.max_length, b.is_output, a.has_default_value FROM (
SELECT LEFT(ParameterDefinition, CHARINDEX(N' ', ParameterDefinition, 1)) parameter_name, CAST(CASE WHEN EqualSignIndex = 0 THEN 0 ELSE 1 END AS BIT) has_default_value FROM (
SELECT ParameterDefinition, CHARINDEX(N'=', ParameterDefinition, 1) EqualSignIndex FROM (
SELECT LTRIM(RTRIM(Split.ParameterDefinition.value(N'.', N'NVARCHAR(100)'))) ParameterDefinition FROM (
SELECT CAST(CONCAT('<a>', REPLACE(@DefinitionText, ',', '</a><a>'), '</a>') AS XML) Xml
) a CROSS APPLY Xml.nodes('/a') AS Split(ParameterDefinition)
) a
) a
) a
FULL JOIN sys.all_parameters b ON a.parameter_name = b.name
WHERE b.object_id = @ObjectId;
我仔细研究了 SQL Server Management Studio 的反汇编,以了解 Microsoft 自己是如何做到的,因为我想确保我的方法完全正确。
正如其他海报推测,让我吃惊(阅读:震惊休克)SSMS运行的正则表达式对sys.sql_modules.definition
到不提供提取参数信息sys.parameters
。
如SQL Server Management Studio中18的,这样做的逻辑是在Microsoft.SqlServer.SqlEnum.dll
,具体地,类Microsoft.SqlServer.Management.Smo.PostProcessParam
。 您也会在其中找到其他有用的正则表达式。
这是模式:
如果您的过程是使用SET QUOTED_IDENTIFIER
保存的,则使用此模式:
new Regex( "(/\\*(([^/\\*])|(\\*(?=[^/]))|(/(?=[^\\*])))*|(/\\*(?>/\\*(?<DEPTH>)|\\*/(?<-DEPTH>)|(.|[\n])?)*(?(DEPTH)(?!))\\*/)\\*/)|(--[^\n]*)|(\"((\"\")|[^\"])*\")|(//[^\n]*)|(?<delim>\\b((AS)|(RETURNS))\\b)|(?:(?<param>@[\\w_][\\w\\d_$$@#]*)((\\s)|((--[^\n]*))|((/\\*(([^/\\*])|(\\*(?=[^/]))|(/(?=[^\\*])))*|(/\\*(?>/\\*(?<DEPTH>)|\\*/(?<-DEPTH>)|(.|[\n])?)*(?(DEPTH)(?!))\\*/)\\*/)))*(AS){0,1})|(?<val>(((\"((\"\")|[^\"])*\"))|((N{0,1}'(('')|[^'])*)')|((0x[0-9a-f]+))|(((\\+|\\-){0,1}((\\d+\\.\\d*)|(\\d*\\.\\d+)|(\\d+))(e((\\+)|(\\-))\\d+){0,1}))|((\\[((\\]\\])|[^\\]])*\\]))|(([\\w_][\\w;\\d_]*))))|(?<comma>,)|(?<eq>=)|(\\([\\d, ]*\\))", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
如果您的过程没有使用SET QUOTED_IDENTIFIER
保存,则使用此模式:
new Regex( "(/\\*(([^/\\*])|(\\*(?=[^/]))|(/(?=[^\\*])))*|(/\\*(?>/\\*(?<DEPTH>)|\\*/(?<-DEPTH>)|(.|[\n])?)*(?(DEPTH)(?!))\\*/)\\*/)|(--[^\n]*)|(//[^\n]*)|(?<delim>\\b((AS)|(RETURNS))\\b)|(?:(?<param>@[\\w_][\\w\\d_$$@#]*)((\\s)|((--[^\n]*))|((/\\*(([^/\\*])|(\\*(?=[^/]))|(/(?=[^\\*])))*|(/\\*(?>/\\*(?<DEPTH>)|\\*/(?<-DEPTH>)|(.|[\n])?)*(?(DEPTH)(?!))\\*/)\\*/)))*(AS){0,1})|(?<val>(((\"((\"\")|[^\"])*\"))|((N{0,1}'(('')|[^'])*)')|((0x[0-9a-f]+))|(((\\+|\\-){0,1}((\\d+\\.\\d*)|(\\d*\\.\\d+)|(\\d+))(e((\\+)|(\\-))\\d+){0,1}))|((\\[((\\]\\])|[^\\]])*\\]))|(([\\w_][\\w;\\d_]*))))|(?<comma>,)|(?<eq>=)|(\\([\\d, ]*\\))", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
要获取每个参数的默认值,请针对您的sql.sql_modules_definition
运行适当的正则表达式并观察val
组。
这是使其工作所需的完整说明:
csc.exe
这样您就可以自己编译 SQL-CLR 程序集。GetParameterDefaults.cs
文件。GetParameterDefaults.cs
编译为 SQL-CLR 程序集ProcParamDefs.dll
: csc.exe /noconfig /nowarn:1701,1702,2008 /fullpaths /nostdlib+ /errorreport:prompt /warn:4 /define:DEBUG;TRACE /errorendlocation /preferreduilang:en-US /highentropyva+ /reference:"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\mscorlib.dll" /reference:"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Data.dll" /reference:"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.dll" /reference:"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.dll" /debug+ /debug:full /optimize- /out:ProcParamDefs.dll /subsystemversion:6.00 /target:library /warnaserror- /utf8output /langversion:7.3 GetParameterDefaults.cs
ProcParamDefs.dll
并将其转换为十六进制二进制字符串(Base 16)。
( Get-Content ".\\ProcParamDefs.dll" | Format-Hex | Select-Object -Expand Bytes | ForEach-Object { '{0:x2}' -f $_ }) -join ''
Install.sql
文件(在本文末尾)复制并粘贴到 SSMS 会话中。<PASTE BASE-16 (HEX) DLL HERE KEEP THE LEADING 0x PREFIX>
替换为步骤 3 中的 Base16/hex。注意前导0x
需要存在,尾随;
,所以它应该是这样的:CREATE ASSEMBLY [ProcParamDefs]
AUTHORIZATION [dbo]
FROM 0x0x4D5A90000300000004000000FFFF0000B800etc
;
运行它,您应该可以使用 UDF dbo.GetParameterDefaults
、 dbo.[GetParameterDefaultsByProcedureObjectId
和dbo.ParseParameterDefaultValues
。
例如,请参阅此屏幕截图:
请注意,它仅列出具有默认值的参数。 它不会列出没有任何默认定义的参数。
GetParameterDefaults.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Text.RegularExpressions;
using Microsoft.SqlServer.Server;
/// <summary>
/// This SQL-CLR table-valued UDF will parse and expose the default-values for SQL Server stored procedures as this information is not normally available through INFORMATION_SCHEMA nor sys.parameters.<br />
/// By Dai Rees on StackOverflow: https://stackoverflow.com/questions/6992561/is-there-a-solution-for-getting-the-default-value-of-the-parameters-of-a-given-s<br />
/// This also may find its way onto my GitHub eventually too.<br />
/// The crucial regular-expressions inside this UDF were copied from Microsoft's SqlEnum.dll (they're *the exact same* regexes that SSMS uses to show parameter information) btw.<br />
/// I guess the regexes are Microsoft's copyright, but SSMS is given-away for free and Microsoft made no attempt to obscure/hide them, so I guess this is fair-use? If so, then consider my code as MIT licensed, so happy forking!
/// </summary>
public partial class UserDefinedFunctions
{
private static readonly Regex _paramRegexQI = new Regex("(/\\*(([^/\\*])|(\\*(?=[^/]))|(/(?=[^\\*])))*|(/\\*(?>/\\*(?<DEPTH>)|\\*/(?<-DEPTH>)|(.|[\n])?)*(?(DEPTH)(?!))\\*/)\\*/)|(--[^\n]*)|(\"((\"\")|[^\"])*\")|(//[^\n]*)|(?<delim>\\b((AS)|(RETURNS))\\b)|(?:(?<param>@[\\w_][\\w\\d_$$@#]*)((\\s)|((--[^\n]*))|((/\\*(([^/\\*])|(\\*(?=[^/]))|(/(?=[^\\*])))*|(/\\*(?>/\\*(?<DEPTH>)|\\*/(?<-DEPTH>)|(.|[\n])?)*(?(DEPTH)(?!))\\*/)\\*/)))*(AS){0,1})|(?<val>(((\"((\"\")|[^\"])*\"))|((N{0,1}'(('')|[^'])*)')|((0x[0-9a-f]+))|(((\\+|\\-){0,1}((\\d+\\.\\d*)|(\\d*\\.\\d+)|(\\d+))(e((\\+)|(\\-))\\d+){0,1}))|((\\[((\\]\\])|[^\\]])*\\]))|(([\\w_][\\w;\\d_]*))))|(?<comma>,)|(?<eq>=)|(\\([\\d, ]*\\))", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled );
private static readonly Regex _paramRegex = new Regex("(/\\*(([^/\\*])|(\\*(?=[^/]))|(/(?=[^\\*])))*|(/\\*(?>/\\*(?<DEPTH>)|\\*/(?<-DEPTH>)|(.|[\n])?)*(?(DEPTH)(?!))\\*/)\\*/)|(--[^\n]*)|(//[^\n]*)|(?<delim>\\b((AS)|(RETURNS))\\b)|(?:(?<param>@[\\w_][\\w\\d_$$@#]*)((\\s)|((--[^\n]*))|((/\\*(([^/\\*])|(\\*(?=[^/]))|(/(?=[^\\*])))*|(/\\*(?>/\\*(?<DEPTH>)|\\*/(?<-DEPTH>)|(.|[\n])?)*(?(DEPTH)(?!))\\*/)\\*/)))*(AS){0,1})|(?<val>(((\"((\"\")|[^\"])*\"))|((N{0,1}'(('')|[^'])*)')|((0x[0-9a-f]+))|(((\\+|\\-){0,1}((\\d+\\.\\d*)|(\\d*\\.\\d+)|(\\d+))(e((\\+)|(\\-))\\d+){0,1}))|((\\[((\\]\\])|[^\\]])*\\]))|(([\\w_][\\w;\\d_]*))))|(?<comma>,)|(?<eq>=)|(\\([\\d, ]*\\))", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled );
private const String _tableDefinition = @"ParameterName nvarchar(100), DefaultValueExpr nvarchar(4000)";
[SqlFunction(
DataAccess = DataAccessKind.Read,
FillRowMethodName = nameof(FillRow),
IsDeterministic = false,
Name = nameof(GetParameterDefaults),
SystemDataAccess = SystemDataAccessKind.Read,
TableDefinition = _tableDefinition
)]
public static IEnumerable/*<(String parameterName, String defaultValueExpr)>*/ GetParameterDefaults( String procedureName )
{
// Despite the fact the function returns an IEnumerable and the SQLCLR docs saying how great streaming is, it's actually very difficult to use `yield return`:
// See here: https://stackoverflow.com/questions/591191/sqlfunction-fails-to-open-context-connection-despite-dataaccesskind-read-present
// SQLCLR will handle ArgumentExceptions just fine:
// https://docs.microsoft.com/en-us/archive/blogs/sqlprogrammability/server-side-error-handling-part-2-errors-and-error-messages
// https://docs.microsoft.com/en-us/archive/blogs/sqlprogrammability/exception-handling-in-sqlclr
if( procedureName is null ) throw new ArgumentNullException( paramName: nameof(procedureName) );
if( String.IsNullOrWhiteSpace( procedureName ) ) throw new ArgumentException( message: "Value cannot be empty nor whitespace.", paramName: nameof(procedureName) );
//
( Boolean ok, String definition, Boolean isQuotedId ) = TryGetProcedureDefinitionFromName( procedureName );
if( !ok )
{
throw new ArgumentException( message: "Could not find the definition of a procedure with the name \"" + procedureName + "\".", paramName: nameof(procedureName) );
}
// We can't do this, boo:
// foreach( var t in ParseParams( definition, quotedId ? _paramRegexQI : _paramRegex ) ) yield return t;
return ParseParameterDefaultValues( definition, isQuotedId );
}
[SqlFunction(
DataAccess = DataAccessKind.Read,
FillRowMethodName = nameof(FillRow),
IsDeterministic = false,
Name = nameof(GetParameterDefaultsByProcedureObjectId),
SystemDataAccess = SystemDataAccessKind.Read,
TableDefinition = _tableDefinition
)]
public static IEnumerable/*<(String parameterName, String defaultValueExpr)>*/ GetParameterDefaultsByProcedureObjectId( Int32 procedureObjectId )
{
( Boolean ok, String definition, Boolean isQuotedId ) = TryGetProcedureDefinitionFromId( procedureObjectId );
if( !ok )
{
throw new ArgumentException( message: "Could not find the definition of a procedure with OBJECT_ID = " + procedureObjectId.ToString(), paramName: nameof(procedureObjectId) );
}
// We can't do this, boo:
// foreach( var t in ParseParams( definition, quotedId ? _paramRegexQI : _paramRegex ) ) yield return t;
return ParseParameterDefaultValues( definition, isQuotedId );
}
[SqlFunction(
DataAccess = DataAccessKind.Read,
FillRowMethodName = nameof(FillRow),
IsDeterministic = false,
Name = nameof(ParseParameterDefaultValues),
SystemDataAccess = SystemDataAccessKind.Read,
TableDefinition = _tableDefinition
)]
public static IEnumerable/*<(String parameterName, String defaultValueExpr)>*/ ParseParameterDefaultValues( String procedureDefinition, Boolean isQuotedId )
{
List<(String parameterName, String defaultValueExpr)> list = new List<(String parameterName, String defaultValueExpr)>();
foreach( (String name, String value) t in ParseParams( procedureDefinition, isQuotedId ? _paramRegexQI : _paramRegex ) )
{
list.Add( t );
}
return list;
}
private static ( Boolean ok, String definition, Boolean quotedId ) TryGetProcedureDefinitionFromName( String procedureName )
{
using( SqlConnection c = new SqlConnection( "context connection=true" ) )
{
c.Open();
using( SqlCommand cmd = c.CreateCommand() )
{
cmd.CommandText = @"
SELECT
c.[definition],
CONVERT( bit, OBJECTPROPERTY( c.object_id, N'ExecIsQuotedIdentOn' ) ) AS IsQuotedId
FROM
sys.sql_modules AS c
WHERE
c.object_id = OBJECT_ID( @procedureName );";
_ = cmd.Parameters.Add( new SqlParameter( "@procedureName", SqlDbType.NVarChar ) { Value = procedureName } );
using( SqlDataReader rdr = cmd.ExecuteReader() )
{
if( rdr.Read() )
{
String definition = rdr.GetString(0);
Boolean quotedId = rdr.GetBoolean(1);
return ( ok: true, definition, quotedId );
}
else
{
// Validate the object-name:
return ( ok: false, definition: null, quotedId: default );
}
}
}
/*
using( SqlCommand cmdPostMortem = c.CreateCommand() )
{
cmdPostMortem.CommandText = @"
SELECT OBJECT_ID( @procedureName ) AS oid";
_ = cmdPostMortem.Parameters.Add( new SqlParameter( "@procedureName", SqlDbType.NVarChar ) { Value = procedureName } );
Object objectId = cmdPostMortem.ExecuteScalar();
if( objectId is null || objectId == DBNull.Value )
{
}
}
*/
}
}
private static ( Boolean ok, String definition, Boolean quotedId ) TryGetProcedureDefinitionFromId( Int32 procedureObjectId )
{
using( SqlConnection c = new SqlConnection( "context connection=true" ) )
{
c.Open();
using( SqlCommand cmd = c.CreateCommand() )
{
cmd.CommandText = @"
SELECT
c.[definition],
CONVERT( bit, OBJECTPROPERTY( c.object_id, N'ExecIsQuotedIdentOn' ) ) AS IsQuotedId
FROM
sys.sql_modules AS c
WHERE
c.object_id = @objId;";
_ = cmd.Parameters.Add( new SqlParameter( "@objId", SqlDbType.Int ) { Value = procedureObjectId } ); // `OBJECT_ID` returns `int` values btw.
using( SqlDataReader rdr = cmd.ExecuteReader() )
{
if( rdr.Read() )
{
String definition = rdr.GetString(0);
Boolean quotedId = rdr.GetBoolean(1);
return ( ok: true, definition, quotedId );
}
else
{
return ( ok: false, definition: null, quotedId: default );
}
}
}
}
}
private static IEnumerable<(String name, String value)> ParseParams( String definition, Regex r )
{
Boolean inParam = false;
String currentParameterName = null;
Match m = r.Match( definition );
while( m.Success && !m.Groups["delim"].Success )
{
if( m.Groups["eq"].Success )
{
inParam = true;
}
if( m.Groups["comma"].Success )
{
inParam = false;
currentParameterName = null;
}
if( inParam && currentParameterName != null && m.Groups["val"].Success )
{
String defaultValue = m.Groups["val"].Value;
inParam = false;
yield return ( currentParameterName, defaultValue );
}
if( m.Groups["param"].Success )
{
currentParameterName = m.Groups["param"].Value;
}
m = m.NextMatch();
}
}
public static void FillRow( Object tupleObj, out SqlString parameterName, out SqlString defaultValueExpr )
{
if( tupleObj is ValueTuple<String,String> vt )
{
parameterName = vt.Item1;
defaultValueExpr = vt.Item2;
}
else if( tupleObj is null )
{
throw new ArgumentNullException( paramName: nameof(tupleObj) );
}
else
{
throw new ArgumentException( message: "Expected first argument to be of type ValueTuple<String,String> but encountered " + tupleObj.GetType().FullName, paramName: nameof(tupleObj) );
}
}
}
Install.sql
/* You may need to run these statements too:
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'clr strict security', 0;
RECONFIGURE;
EXEC sp_configure 'clr enabled', 1;
RECONFIGURE;
GO
*/
CREATE ASSEMBLY [ProcParamDefs] AUTHORIZATION [dbo]
FROM 0x<PASTE BASE-16 (HEX) DLL HERE KEEP THE LEADING 0x PREFIX>
WITH PERMISSION_SET = SAFE
GO
CREATE FUNCTION [dbo].[GetParameterDefaults] (@procedureName [nvarchar](MAX))
RETURNS TABLE (ParameterName nvarchar(100), DefaultValueExpr nvarchar(4000))
AS EXTERNAL NAME [ProcParamDefs].[UserDefinedFunctions].[GetParameterDefaults];
GO
CREATE FUNCTION [dbo].[GetParameterDefaultsByProcedureObjectId] (@procedureObjectId [int])
RETURNS TABLE (ParameterName nvarchar(100), DefaultValueExpr nvarchar(4000))
AS EXTERNAL NAME [ProcParamDefs].[UserDefinedFunctions].[GetParameterDefaultsByProcedureObjectId];
GO
CREATE FUNCTION [dbo].[ParseParameterDefaultValues] (@procedureDefinition [nvarchar](MAX), @isQuotedId [bit])
RETURNS TABLE (ParameterName nvarchar(100), DefaultValueExpr nvarchar(4000))
AS EXTERNAL NAME [ProcParamDefs].[UserDefinedFunctions].[ParseParameterDefaultValues];
GO
如前所述,这不受 T-SQL 支持。
你必须使用某种程序语言来实现它(除非你想用 T-SQL 处理文本解析)。
我发现为此使用 SMO 非常容易。
例如,在 Powershell 中:
param
(
[string]$InstanceName = $env:COMPUTERNAME,
[string]$DBName = "MyDB",
[string]$ProcedureSchema = "dbo",
[string]$ProcedureName = "MyProcedure"
)
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null
$serverInstance = New-Object ('Microsoft.SqlServer.Management.Smo.Server') $InstanceName
$serverInstance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure], $false)
$procedure = $serverInstance.Databases[$DBName].StoredProcedures[$ProcedureName, $ProcedureSchema];
$procedure.Parameters | Select-Object Parent, Name, DataType, DefaultValue, @{Name="Properties";Expression={$_.Properties | Select Name, Value }}
或者,使用 C#:
Server svr = new Server(new ServerConnection(new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString)));
svr.SetDefaultInitFields(typeof(StoredProcedure), false);
StoredProcedure sp = svr.Databases["MyDatabase"].StoredProcedures["mySproc", "myScheme"];
Dictionary<string, string> defaultValueLookup = new Dictionary<string, string>();
foreach (StoredProcedureParameter parameter in sp.Parameters)
{
string defaultValue = parameter.DefaultValue;
string parameterName = parameter.Name;
defaultValueLookup.Add(parameterName, defaultValue);
}
(最后一个来源: https://stackoverflow.com/a/9977237/3114728 )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.