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; 
}