Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 获取存储过程参数的默认值_Sql Server_Stored Procedures_Parameters_Default Value_Ssms 2012 - Fatal编程技术网

Sql server 获取存储过程参数的默认值

Sql server 获取存储过程参数的默认值,sql-server,stored-procedures,parameters,default-value,ssms-2012,Sql Server,Stored Procedures,Parameters,Default Value,Ssms 2012,我创建了以下具有默认值的存储过程: 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获取参数的默认值

我创建了以下具有默认值的存储过程:

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\u值
,而我期望
10285
作为
default\u值

有什么方法可以获得默认值吗?

看起来,没有简单的方法可以找到参数的默认值,即使特定参数上存在或没有默认值:

众所周知,T-SQL存储过程参数默认值不是 存储在sys.parameters、所有_参数和系统_参数中。他们 也不会通过sp_存储过程_列、sys.columns或 sp_程序_参数_行集

微软的反馈:

正如Tibor Karaszi所发布的,BOL文档“仅限SQL Server 维护此目录视图中CLR对象的默认值; 因此,对于Transact-SQL对象,此列的值为0 查看Transact-SQL对象中参数的默认值,查询 sys.sql_模块目录视图的定义列,或使用 对象定义系统函数。”

我们甚至不存储指示参数为默认值的位 育空地区的价值

我已经测试了第一个代码片段,它似乎适用于您的简单示例:

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

然而,对于一个期望可以从系统视图轻松查询的任务来说,这实在是一件难事。

我同意默认存储过程参数值应该通过SQL Server目录视图公开

T-SQL解析方法在许多情况下都可以工作,但很脆弱。考虑使用TraceSQL SQL StuttOM。下面是一个混合使用PowerShell和C#的示例。并不是说这对所有情况都是完美的,但它似乎处理了我在thusfar中抛出的所有参数

在本例中,我使用了SSMS安装中的
Microsoft.SqlServer.transact-sql.ScriptDom.dll
程序集,但可以从下载

试试看
{
添加类型-LiteralPath@(“C:\ProgramFiles(x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\Extensions\Application\Microsoft.SqlServer.Transact-SQL.ScriptDom.dll”);
添加类型`
-ReferenceAssemblys@(“C:\Program Files(x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\Extensions\Application\Microsoft.SqlServer.Transact-SQL.ScriptDom.dll”)`
-类型定义@”
使用制度;
使用System.Collections.Generic;
使用系统文本;
使用Microsoft.SqlServer.Transact-SQL.ScriptDom;
使用System.IO;
公共静态类解析器
{
公共静态列表GetStoredProcedureParameters(字符串storedProcedureDefinition)
{
StringReader=新StringReader(存储过程定义);
var parser=新的TSql140Parser(true);
IList错误;
TSqlFragment sqlFragment=parser.Parse(reader,out错误);
如果(errors.Count>0)
{
抛出新异常(`Error parsing storage procedure definition`);
}
SQLVisitor SQLVisitor=新SQLVisitor();
Accept(sqlVisitor);
返回sqlVisitor.StoredProcedureParameters;
}
}
内部类SQLVisitor:TSqlFragmentVisitor
{
public List StoredProcedureParameters=新列表();
public override void ExplicitVisit(过程参数节点)
{
var p=StoredProcedureParameter.CreateProcedureParameter(节点);
存储过程参数。添加(p);
}
}
公共类存储过程参数
{
公共字符串参数名;
公共字符串参数类型;
公共字符串参数direction=null;
公共字符串DefaultParameterValue=null;
公共静态存储过程参数CreateProcedureParameter(过程参数节点)
{
var param=新存储的过程参数();
//参数名
param.ParameterName=node.VariableName.Value;
//数据类型
开关(((ParameteredDataTypeReference)node.DataType).Parameters.Count)
{
案例0:
if(node.DataType.Name.Identifiers.Count==1)
{
param.ParameterType=node.DataType.Name.Identifiers[0]。值;
}
其他的
{
//架构限定类型名
param.ParameterType=node.DataType.Name.Identifiers[0]。值+`“`”+node.DataType.Name.Identifiers[1]。值;
}
打破
案例1:
param.ParameterType=node.DataType.Name.Identifiers[0].Value+“(“+((ParameteredDataTypeReference)node.DataType).参数[0].Value+”;
打破
案例2:
param.ParameterType=node.DataType.Name.Identifiers[0].Value+“(+((ParameteredDataTypeReference)node.DataType).参数[0].Value+”,“+((ParameteredDataTypeReference)node.DataType).参数[1].Value+”;
打破
}
//默认值
if(node.Value!=null)
{
param.DefaultParameterValue=node.ScriptTokenStream[node.LastTokenIndex].Text;
}
//方向
if(node.Modifier==ParameterModifier.Output)
{
param.ParameterDirection=`OUTPUT`;
}
else if(node.Modifier==ParameterModifier.ReadOnly)
{
param.ParameterDirection=`READONLY`;
}
其他的
{
param.ParameterDirection=`INPUT`;
}
返回参数;
}
公共重写字符串ToString()
{
var sb=新的StringBuilder();
sb.Append(参数名);
某人加上(``);
sb.Append(参数类型);
if(DefaultParameterValue!=null)
{
某人加上(``);
sb.Append(DefaultParameterValue);
}
某人加上(``);
sb.追加(参数方向);
使某人返回字符串();
}
}
"@
}
catch[System.Refl
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;
}