0

我在下面的存储过程创建了默认值的默认值:获取存储过程的参数

CREATE PROCEDURE [dbo].[Sample1] 
    @OrderID INT = 10285 
AS 
    SELECT ProductName, OrderID 
    FROM Products P, [Order Details] Od 
    WHERE Od.ProductID = P.ProductID 
     AND Od.OrderID = @OrderID 

我试着去使用sys.parameters参数的默认值(10285)。

Select a.object_id, a.default_value 
from sys.parameters a 
inner join sys.types b on b.system_type_id = a.system_type_id 
where Object_id = object_id('[dbo].[Sample1]') 

但我得到NULL作为default_value,而我期待10285default_value

有没有什么办法可以得到默认值?

+0

[不良习惯踢:使用旧样式的JOIN(http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/bad-habits-to-kick-using-old -style-joins.aspx) - 在ANSI - ** 92 ** SQL标准中(** 25年*),旧式*逗号分隔的表*样式列表已替换为* proper * ANSI'JOIN'语法*之前),其使用是不鼓励的 –

回答

0

它看起来是Microsoft has neglected this topic并没有找到参数的默认值非同小可方式即使默认值存在或不按特定参数:

大家都知道,T-SQL存储过程存储在sys.parameters,all_parameters和system_parameters中的参数默认值不是 。它们 也不通过sp_sproc_columns,sys.columns或 sp_procedure_params_rowset公开。从微软

反馈:

张贴由蒂博尔Karaszi,BOL文件,“SQL Server只 保持默认值在此目录视图CLR对象; 因此,此列的值0 for Transact-SQL objects。要查询 查看Transact-SQL对象中参数的默认值,请查询 sys.sql_modules目录视图的定义列,或使用 OBJECT_DEFINITION系统函数。

我们甚至不存储指示参数在Yukon中的默认值为 的值。

我已经测试过的第一个代码段in this answer,它似乎为您简单的例子工作:

SELECT 
     data3.name 
    , [default_value] = REVERSE(RTRIM(SUBSTRING(
      data3.rtoken 
     , CASE 
      WHEN CHARINDEX(N',', data3.rtoken) > 0 
       THEN CHARINDEX(N',', data3.rtoken) + 1 
      WHEN CHARINDEX(N')', data3.rtoken) > 0 
       THEN CHARINDEX(N')', data3.rtoken) + 1 
      ELSE 1 
      END 
     , LEN(data3.rtoken) 
    ))) 
FROM (
    SELECT 
      data2.name 
     , rtoken = REVERSE(
      SUBSTRING(ptoken 
        , CHARINDEX('=', ptoken, 1) + 1 
        , LEN(data2.ptoken)) 
       ) 
    FROM (
     SELECT 
       data.name 
      , ptoken = SUBSTRING(
        data.tokens 
       , token_pos + name_length + 1 
       , ISNULL(ABS(next_token_pos - token_pos - name_length - 1), LEN(data.tokens)) 
      ) 
     FROM (
      SELECT 
        sm3.tokens 
       , p.name 
       , name_length = LEN(p.name) 
       , token_pos = CHARINDEX(p.name, sm3.tokens) 
       , next_token_pos = CHARINDEX(p2.name, sm3.tokens) 
      FROM (
       SELECT 
         sm2.[object_id] 
        , sm2.[type] 
        , tokens = REVERSE(SUBSTRING(sm2.tokens, ISNULL(CHARINDEX('SA', sm2.tokens) + 2, 0), LEN(sm2.tokens))) 
       FROM (
        SELECT 
          sm.[object_id] 
         , o.[type] 
         , tokens = REVERSE(SUBSTRING(
             sm.[definition] 
            , CHARINDEX(o.name, sm.[definition]) + LEN(o.name) + 1 
            , ABS(CHARINDEX(N'AS', sm.[definition])) 
           ) 
         ) 
        FROM sys.sql_modules sm WITH (NOLOCK) 
        JOIN sys.objects o WITH (NOLOCK) ON sm.[object_id] = o.[object_id] 
        JOIN sys.schemas s WITH (NOLOCK) ON o.[schema_id] = s.[schema_id] 
        WHERE o.[type] = 'P ' 
         AND s.name + '.' + o.name = 'dbo.Sample1' 
       ) sm2 
       WHERE sm2.tokens LIKE '%=%' 
      ) sm3 
      JOIN sys.parameters p WITH (NOLOCK) ON sm3.[object_id] = p.[object_id] 
      OUTER APPLY (
       SELECT p2.name 
       FROM sys.parameters p2 WITH (NOLOCK) 
       WHERE p2.is_output = 0 
        AND sm3.[object_id] = p2.[object_id] 
        AND p.parameter_id + 1 = p2.parameter_id 
      ) p2 
      WHERE p.is_output = 0 
     ) data 
    ) data2 
    WHERE data2.ptoken LIKE '%=%' 
) data3 

但是,对于一个预计将很容易从系统的观点可查询任务真难看。

0

我同意默认的存储过程参数值应暴露通过SQL Server目录视图。

T-SQL解析方法可能在许多情况下工作,但是很脆弱。考虑使用TransactSQL ScriptDOM。下面是一个使用PowerShell和C#混合使用的例子。并不是说这对所有情况都是完美的,但它好像处理了我所有的参数。

我在本例中使用了我的SSMS安装中的Microsoft.SqlServer.TransactSql.ScriptDom.dll程序集,但它可以从NuGet Gallery下载。

try 
{ 
    Add-type -LiteralPath @("C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\Extensions\Application\Microsoft.SqlServer.TransactSql.ScriptDom.dll"); 
    Add-type ` 
     -ReferencedAssemblies @("C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\Extensions\Application\Microsoft.SqlServer.TransactSql.ScriptDom.dll") ` 
     -TypeDefinition @" 
using System; 
using System.Collections.Generic; 
using System.Text; 
using Microsoft.SqlServer.TransactSql.ScriptDom; 
using System.IO; 
public static class ProcParser 
{ 

    public static List<StoredProcedureParameter> GetStoredProcedureParameters(string storedProcedureDefinition) 
    { 

     StringReader reader = new StringReader(storedProcedureDefinition); 
     var parser = new TSql140Parser(true); 

     IList<ParseError> errors; 
     TSqlFragment sqlFragment = parser.Parse(reader, out errors); 

     if (errors.Count > 0) 
     { 
      throw new Exception(`"Error parsing stored procedure definition`"); 
     } 

     SQLVisitor sqlVisitor = new SQLVisitor(); 
     sqlFragment.Accept(sqlVisitor); 

     return sqlVisitor.StoredProcedureParameters; 

    } 

} 

internal class SQLVisitor : TSqlFragmentVisitor 
{ 

    public List<StoredProcedureParameter> StoredProcedureParameters = new List<StoredProcedureParameter>(); 

    public override void ExplicitVisit(ProcedureParameter node) 
    { 

     var p = StoredProcedureParameter.CreateProcedureParameter(node); 
     StoredProcedureParameters.Add(p); 

    } 

} 

public class StoredProcedureParameter 
{ 
    public string ParameterName; 
    public string ParameterType; 
    public string ParameterDirection = null; 
    public string DefaultParameterValue = null; 

    public static StoredProcedureParameter CreateProcedureParameter(ProcedureParameter node) 
    { 
     var param = new StoredProcedureParameter(); 

     //parameter name 
     param.ParameterName = node.VariableName.Value; 

     //data type 
     switch (((ParameterizedDataTypeReference)node.DataType).Parameters.Count) 
     { 
      case 0: 
       if (node.DataType.Name.Identifiers.Count == 1) 
       { 
        param.ParameterType = node.DataType.Name.Identifiers[0].Value; 
       } 
       else 
       { 
        //schema-qualified type name 
        param.ParameterType = node.DataType.Name.Identifiers[0].Value + `".`" + node.DataType.Name.Identifiers[1].Value; 
       } 
       break; 
      case 1: 
       param.ParameterType = node.DataType.Name.Identifiers[0].Value + "(" + ((ParameterizedDataTypeReference)node.DataType).Parameters[0].Value + ")"; 
       break; 
      case 2: 
       param.ParameterType = node.DataType.Name.Identifiers[0].Value + "(" + ((ParameterizedDataTypeReference)node.DataType).Parameters[0].Value + "," + ((ParameterizedDataTypeReference)node.DataType).Parameters[1].Value + ")"; 
       break; 
     } 

     //default value 
     if (node.Value != null) 
     { 
      param.DefaultParameterValue = node.ScriptTokenStream[node.LastTokenIndex].Text; 
     } 

     //direction 
     if (node.Modifier == ParameterModifier.Output) 
     { 
      param.ParameterDirection = `"OUTPUT`"; 
     } 
     else if (node.Modifier == ParameterModifier.ReadOnly) 
     { 
      param.ParameterDirection = `"READONLY`"; 
     } 
     else 
     { 
      param.ParameterDirection = `"INPUT`"; 
     } 

     return param; 

    } 

    public override string ToString() 
    { 

     var sb = new StringBuilder(); 
     sb.Append(ParameterName); 
     sb.Append(`" `"); 
     sb.Append(ParameterType); 
     if (DefaultParameterValue != null) 
     { 
      sb.Append(`" `"); 
      sb.Append(DefaultParameterValue); 
     } 
     sb.Append(`" `"); 
     sb.Append(ParameterDirection); 
     return sb.ToString(); 

    } 

} 
"@ 

} 
catch [System.Reflection.ReflectionTypeLoadException] 
{ 
    Write-Host "Message: $($_.Exception.Message)" 
    Write-Host "StackTrace: $($_.Exception.StackTrace)" 
    Write-Host "LoaderExceptions: $($_.Exception.LoaderExceptions)" 
    throw; 
} 

Function Get-ProcText($connectionString, $procName) 
{ 
    $connection = New-Object System.Data.SqlClient.SqlConnection($connectionString); 
    $connection.Open(); 
    $command = New-Object System.Data.SqlClient.SqlCommand("SELECT definition FROM sys.sql_modules WHERE object_id = OBJECT_ID(@ProcName);", $connection); 
    $procNameParameter = $command.Parameters.Add((New-Object System.Data.SqlClient.SqlParameter("@ProcName", [System.Data.SqlDbType]::NVarChar, 261))); 
    $procNameParameter.Value = $procName; 
    $procText = $command.ExecuteScalar(); 
    $connection.Close(); 
    return $procText; 
} 

############ 
### main ### 
############ 
try { 

    # get proc text definition from database 
    $procText = Get-ProcText ` 
     -connectionString "Data Source=.;Initial Catalog=tempdb;Integrated Security=SSPI" ` 
     -procName "dbo.testproc"; 

    # parse parameters from proc text 
    $procParameters = [ProcParser]::GetStoredProcedureParameters($procText); 

    # display parameter values 
    foreach($procParameter in $procParameters) 
    { 
     Write-Host "ParameterName=$($procParameter.ParameterName)"; 
     Write-Host "`tParameterType=$($procParameter.ParameterType)"; 
     Write-Host "`tDefaultParameterValue=$($procParameter.DefaultParameterValue)"; 
     Write-Host "`tParameterDirection=$($procParameter.ParameterDirection)"; 
    } 

} 
catch { 
    throw; 
}