2009-11-04 16 views
9

यदि कोई SQL सर्वर संग्रहीत प्रक्रिया पैरामीटर डिफ़ॉल्ट है तो प्रोग्रामेटिक रूप से निर्धारित करने का कोई तरीका है? (बोनस पॉइंट्स यदि आप निर्धारित कर सकते हैं कि डिफ़ॉल्ट क्या है।) SqlCommandBuilder.DeriveParameters() भी कोशिश नहीं करता है।मैं कैसे निर्धारित कर सकता हूं कि SQL सर्वर संग्रहीत प्रक्रिया पैरामीटर डिफ़ॉल्ट है या नहीं?

आपकी मदद के लिए अग्रिम धन्यवाद!

संपादित करें: मैं ईमानदारी से परवाह नहीं है अगर यह एक एसक्यूएल क्वेरी, एक एसएमओ वस्तु, आदि

उत्तर

14

मैं एक तरह से एसएमओ का उपयोग कर पाया:

Server srv; 
srv = new Server("ServerName"); 

Database db; 
db = srv.Databases["MyDatabase"]; 

var Params = db.StoredProcedures["MyStoredProc"].Parameters; 

foreach(StoredProcedureParameter param in Params) { 
    Console.WriteLine(param.Name + "-" + param.DefaultValue); 
} 
+0

+1 उत्कृष्ट! –

+0

प्रतिभा जानना अच्छा है, धन्यवाद :) –

1

भागो builtin sp_help संग्रहीत प्रक्रिया है?

+2

कहाँ sp_help के लिए resultset यह संकेत मिलता है एक पैरामीटर एक है कि क्या में चूक? – GuyBehindtheGuy

+1

पैरामीटर सूचीबद्ध करता है - लेकिन यह नहीं कि उनके पास डिफ़ॉल्ट मान है या नहीं, और यह क्या होगा :-( –

6

नहीं SQL सर्वर 2005 में और ऊपर एक बड़ी बात:

SELECT 
    pa.NAME, 
    t.name 'Type', 
    pa.max_length, 
    pa.has_default_value, 
    pa.default_value 
FROM 
    sys.parameters pa 
INNER JOIN 
    sys.procedures pr ON pa.object_id = pr.object_id 
INNER JOIN 
    sys.types t ON pa.system_type_id = t.system_type_id 
WHERE 
     pr.Name = 'YourStoredProcName' 

दुर्भाग्य से, भले ही यह केक का एक टुकड़ा तरह लग रहा था - यह

:-(काम नहीं करता है

टेकनेट से:

एसक्यूएल सर्वर केवल डिफ़ॉल्ट इस सूची में के लिए मान देखें; इसलिए, इस कॉलम में ट्रांजैक्ट-एसक्यूएल ऑब्जेक्ट्स के लिए 0 का मान है। किसी Transact SQL वस्तु में एक पैरामीटर का डिफ़ॉल्ट मान देखने के लिए, क्वेरी sys.sql_modules सूची दृश्य की परिभाषा स्तंभ, या OBJECT_DEFINITION प्रणाली समारोह का उपयोग करें।

तो सब आप कर सकते हैं या तो क्वेरी sys.sql_modules या फोन SELECT object_definition(object_id) मूल रूप से अपने संग्रहीत proc के लिए एसक्यूएल परिभाषा (T-SQL स्रोत कोड) प्राप्त करने के लिए है और फिर आपको लगता है कि पार्स करने के लिए आवश्यकता होगी (बेकार है !! बड़ा समय .....)

लगता है वहाँ वास्तव में यह करने के लिए कोई दूसरा रास्ता नहीं है जैसे ... मैं हैरान और appaled हूँ .....

शायद एसक्यूएल सर्वर 2008 R2 में

? :-) मार्क

+0

हम्म ... क्या आप वास्तव में इसे चला चुके हैं? एसक्यूएल 2008 पर डीबी संगतता के साथ "100" पर सेट है, 'has_default_value प्रत्येक पंक्ति के लिए 0 है, भले ही पैरामीटर निश्चित रूप से एक डिफ़ॉल्ट है! – GuyBehindtheGuy

+0

हाँ मैंने इसे चलाया - दुर्भाग्यवश, मेरे सभी sprocs के पास कभी भी डिफ़ॉल्ट मान नहीं हैं, इसलिए मैं वास्तव में सत्यापित नहीं कर सका - मुझे जांचने दें ... –

+3

वाह। ऐसा करने के लिए अनुशंसित तरीका है संग्रहीत प्रक्रिया_ के शरीर को _parse करना ?! वह बेकार है। – GuyBehindtheGuy

1

संग्रहित प्रक्रियाओं के लिए, मेरा मानना ​​है कि आप कुछ है कि T-SQL पार्स करता है, या use the T-SQL parser कि माइक्रोसॉफ्ट प्रदान करता है लिखने के लिए होगा।

पार्सर और स्क्रिप्ट जनरेटर दो असेंबली में रहते हैं। Microsoft.Data.Schema.ScriptDom प्रदाता नास्तिक वर्गों और Microsoft.Data.Schema.ScriptDom.Sql विधानसभा कि एसक्यूएल सर्वर विशिष्ट हैं पार्सर और स्क्रिप्ट जनरेटर के लिए कक्षाएं शामिल हैं।

विशेष रूप से मानकों को और क्या वे चूक रहे हैं शामिल नहीं है और हो सकता है कुछ आप पर काम करना (शायद प्रयास के एक सौदे के साथ) नमूना कोड का उपयोग कर होगा पहचान करने के लिए इस का उपयोग कैसे करें।

+0

दिलचस्प विचार। हालांकि, मुझे वीएसटीएस डाटाबेस संस्करण के लिए लाइसेंस की आवश्यकता होगी। :-) – GuyBehindtheGuy

1

यह एक हैक की तरह है, लेकिन आप हमेशा से ही वैकल्पिक पैरामीटर की तरह एक विशेष नाम दे सकता है:

@AgeOptional = 15

... तो एक सरल विधि है कि एक पैरामीटर की जाँच करता है देखने के लिए लिख अगर यह वैकल्पिक है। आदर्श नहीं है, लेकिन स्थिति को देखते हुए, यह वास्तव में एक सभ्य समाधान हो सकता है।

1

यही वह है जो मैंने इसे प्राप्त करने के लिए किया था। एएस कथन तक पहले पैरामीटर से शुरू की गई संग्रहीत प्रक्रिया के अनुभाग को पकड़ें। घोषित घोषणाओं के साथ एक अस्थायी संग्रहीत प्रक्रिया बनाई गई है और सभी पैरामीटर आईडी, नाम, कॉलम प्रकार, यदि उनके पास डिफ़ॉल्ट है, और उनके मूल्य को यूनियन लौटा रहा है। और उसके बाद संग्रहित प्रक्रिया को निष्पादित किया गया कि क्या उनके पास पैरामीटर के बीच एक समान चिह्न है, और यदि उनके पास डिफ़ॉल्ट नहीं है, तो निष्पादन के दौरान पैरामीटर में शून्य हो गया है, या तो परिणामसेट पढ़ा गया है या यदि संग्रहित प्रक्रिया मौजूद है एक अस्थायी तालिका ताकि मैं इसे बाद में पूछ सकूं। मैंने जांच की है कि क्या पैरामीटर के बीच कोई समान संकेत है और यदि हां शुरू में मुझे लगता है कि उनके पास डिफ़ॉल्ट हैं। यदि कोई टिप्पणी आदि है तो बराबर चिह्न के साथ प्रक्रिया का अर्थ है कि उनके पास डिफ़ॉल्ट नहीं है और निष्पादन के दौरान मैंने कोई पैरामीटर नहीं पारित किया है, निष्पादन विफल रहा है, मैंने त्रुटि संदेश पकड़ा है, पैरामीटर नाम पढ़ा है और इस बार प्रक्रिया को निष्पादित किया है पैरामीटर के लिए शून्य। प्रक्रिया में मैंने एक सीएलआर स्ट्रिंग कॉन्सट फ़ंक्शन का उपयोग किया था, इस कारण से यदि आप सीधे निष्पादित करते हैं तो यह संकलित नहीं होगा, लेकिन आप शायद एक्सएमएल पथ के साथ प्रतिस्थापित कर सकते हैं या फिर मुझे ईमेल कर सकते हैं, अगर आप चाहते हैं तो मैं आपको क्लियर के माध्यम से मार्गदर्शन कर सकता हूं । जब से मैं संघ सभी मापदंडों किया मैं उन्हें varchar के रूप में casted (अधिकतम)

USE Util 
GO 
CREATE AGGREGATE [dbo].[StringConcat] 
(@Value nvarchar(MAX), @Delimiter nvarchar(100)) 
RETURNS nvarchar(MAX) 
EXTERNAL NAME [UtilClr].[UtilClr.Concat] 
GO 
CREATE FUNCTION dbo.GetColumnType (@TypeName SYSNAME, 
            @MaxLength SMALLINT, 
            @Precision TINYINT, 
            @Scale TINYINT, 
            @Collation SYSNAME, 
            @DBCollation SYSNAME) 
RETURNS TABLE 
    AS 
RETURN 
    SELECT CAST(CASE WHEN @TypeName IN ('char', 'varchar') 
         THEN @TypeName + '(' + CASE WHEN @MaxLength = -1 THEN 'MAX' 
                ELSE CAST(@MaxLength AS VARCHAR) 
              END + ')' + CASE WHEN @Collation <> @DBCollation THEN ' COLLATE ' + @Collation 
                   ELSE '' 
                 END 
         WHEN @TypeName IN ('nchar', 'nvarchar') 
         THEN @TypeName + '(' + CASE WHEN @MaxLength = -1 THEN 'MAX' 
                ELSE CAST(@MaxLength/2 AS VARCHAR) 
              END + ')' + CASE WHEN @Collation <> @DBCollation THEN ' COLLATE ' + @Collation 
                   ELSE '' 
                 END 
         WHEN @TypeName IN ('binary', 'varbinary') THEN @TypeName + '(' + CASE WHEN @MaxLength = -1 THEN 'MAX' 
                          ELSE CAST(@MaxLength AS VARCHAR) 
                         END + ')' 
         WHEN @TypeName IN ('bigint', 'int', 'smallint', 'tinyint') THEN @TypeName 
         WHEN @TypeName IN ('datetime2', 'time', 'datetimeoffset') THEN @TypeName + '(' + CAST (@Scale AS VARCHAR) + ')' 
         WHEN @TypeName IN ('numeric', 'decimal') THEN @TypeName + '(' + CAST(@Precision AS VARCHAR) + ', ' + CAST(@Scale AS VARCHAR) + ')' 
         ELSE @TypeName 
       END AS VARCHAR(256)) AS ColumnType 
GO 
go 
USE [master] 
GO 
IF OBJECT_ID('dbo.sp_ParamDefault') IS NULL 
    EXEC('CREATE PROCEDURE dbo.sp_ParamDefault AS SELECT 1 AS ID') 
GO 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
ALTER PROCEDURE dbo.sp_ParamDefault 
    @ProcName SYSNAME = NULL OUTPUT 
AS 
SET NOCOUNT ON 
SET ANSI_WARNINGS OFF 
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 

DECLARE @SQL VARCHAR(MAX), 
    @ObjectId INT = OBJECT_ID(LTRIM(RTRIM(@ProcName))), 
    @FirstParam VARCHAR(256), 
    @LastParam VARCHAR(256), 
    @SelValues VARCHAR(MAX), 
    @ExecString VARCHAR(MAX), 
    @WhiteSpace VARCHAR(10) = '[' + CHAR(10) + CHAR(13) + CHAR(9) + CHAR(32) + ']', 
    @TableExists BIT = ABS(SIGN(ISNULL(OBJECT_ID('tempdb..#sp_ParamDefault'), 0))), 
    @DeclareSQL VARCHAR(MAX), 
    @ErrorId INT, 
    @ErrorStr VARCHAR(MAX) 

IF @ObjectId IS NULL 
    BEGIN 
     SET @ProcName = NULL 
     PRINT '/* -- SILENCE OPERATION -- 
IF OBJECT_ID(''tempdb..#sp_ParamDefault'') IS NOT NULL DROP TABLE #sp_ParamDefault 
CREATE TABLE #sp_ParamDefault (Id INT, NAME VARCHAR(256), TYPE VARCHAR(256), HasDefault BIT, IsOutput BIT, VALUE VARCHAR(MAX)) 
*/ 

EXEC dbo.sp_ParamDefault 
    @ProcName = NULL 
' 
RETURN 
    END 

SELECT @SQL = definition, 
     @ProcName = QUOTENAME(OBJECT_SCHEMA_NAME(@ObjectId)) + '.' + QUOTENAME(OBJECT_NAME(@ObjectId)), 
     @FirstParam = FirstParam, 
     @LastParam = LastParam 
FROM sys.all_sql_modules m (NOLOCK) 
CROSS APPLY (SELECT MAX(CASE WHEN p.parameter_id = 1 THEN p.name 
         END) AS FirstParam, 
        Util.dbo.StringConcat(p.name, '%') AS Params 
      FROM sys.parameters p (NOLOCK) 
      WHERE p.object_id = m.OBJECT_ID) p 
CROSS APPLY (SELECT TOP 1 
        p.NAME AS LastParam 
      FROM sys.parameters p (NOLOCK) 
      WHERE p.object_id = m.OBJECT_ID 
      ORDER BY parameter_id DESC) l 
WHERE m.object_id = @ObjectId 
IF @FirstParam IS NULL 
    BEGIN 
     IF @TableExists = 0 
      SELECT CAST(NULL AS INT) AS Id, 
        CAST(NULL AS VARCHAR(256)) AS Name, 
        CAST(NULL AS VARCHAR(256)) AS Type, 
        CAST(NULL AS BIT) AS HasDefault, 
        CAST(NULL AS VARCHAR(MAX)) AS VALUE 
      WHERE 1 = 2 
     RETURN 
    END 

SELECT @DeclareSQL = SUBSTRING(@SQL, 1, lst + AsFnd + 2) + ' 
' 
FROM (SELECT PATINDEX ('%' + @WhiteSpace + @LastParam + @WhiteSpace + '%', @SQL) AS Lst) l 
CROSS APPLY (SELECT SUBSTRING (@SQL, lst, LEN (@SQL)) AS SQL2) s2 
CROSS APPLY (SELECT PATINDEX ('%' + @WhiteSpace + 'AS' + @WhiteSpace + '%', SQL2) AS AsFnd) af 


DECLARE @ParamTable TABLE (Id INT NOT NULL, 
          NAME SYSNAME NULL, 
          TYPE VARCHAR(256) NULL, 
          HasDefault BIGINT NULL, 
          IsOutput BIT NOT NULL, 
          TypeName SYSNAME NOT NULL) ; 
WITH pr 
      AS (SELECT p.NAME COLLATE SQL_Latin1_General_CP1_CI_AS AS ParameterName, 
         p.Parameter_id, 
         t.NAME COLLATE SQL_Latin1_General_CP1_CI_AS AS TypeName, 
         ct.ColumnType, 
         MAX(Parameter_id) OVER (PARTITION BY (SELECT 0)) AS MaxParam, 
         p.is_output 
       FROM  sys.parameters p (NOLOCK) 
       INNER JOIN sys.types t (NOLOCK) ON t.user_type_id = p.user_type_id 
       INNER JOIN sys.databases AS db (NOLOCK) ON db.database_id = DB_ID() 
       CROSS APPLY Util.dbo.GetColumnType(t.name, p.max_length, p.precision, p.scale, db.collation_name, db.collation_name) ct 
       WHERE  OBJECT_ID = @ObjectId) 
    INSERT @ParamTable 
      (Id, 
      NAME, 
      TYPE, 
      HasDefault, 
      IsOutput, 
      TypeName) 
      SELECT Parameter_id AS Id, 
        ParameterName AS NAME, 
        ColumnType AS TYPE, 
        HasDefault, 
        is_output AS IsOutput, 
        TypeName 
      FROM pr a 
      CROSS APPLY (SELECT ISNULL('%' + (SELECT Util.dbo.StringConcat (ParameterName, '%') FROM pr b WHERE b.parameter_id < a.parameter_id), '') + '%' 
           + ParameterName + '%=' + '%' + CASE WHEN parameter_id = MaxParam THEN @WhiteSpace + 'AS' + @WhiteSpace + '%' 
                    ELSE (SELECT Util.dbo.StringConcat (ParameterName, '%') FROM pr b 
                        WHERE b.parameter_id > a.parameter_id) + '%' 
                   END AS ptt) b 
      CROSS APPLY (SELECT SIGN (PATINDEX (ptt, @DeclareSQL)) AS HasDefault) hd 

AGAIN: 
SELECT @SelValues = CASE WHEN @TableExists = 1 THEN 'INSERT #sp_ParamDefault(Id, Name, Type, HasDefault, IsOutput, Value) 
'       ELSE '' 
        END + 'SELECT * FROM (VALUES' + Util.dbo.StringConcat('(' + CAST(Id AS VARCHAR) + ', ''' + Name + ''', ''' + Type + ''', ' 
                      + CAST(HasDefault AS VARCHAR) + ', ' + CAST(IsOutput AS VARCHAR) + ', ' 
                      + CASE WHEN TypeName NOT LIKE '%char%' THEN 'CAST(' + name + ' AS VARCHAR(MAX))' 
                        ELSE name 
                      END + ')', ', 
') + ' 
) d(Id, Name, Type, HasDefault, IsOutput, Value)', 
     @ExecString = 'EXEC#sp_ParamDefaultProc 
' + ISNULL(Util.dbo.StringConcat(CASE WHEN HasDefault = 0 THEN Name + ' = NULL' 
           END, ', 
'), '') 
FROM @ParamTable 

SET @SQL = 'CREATE PROCEDURE #sp_ParamDefaultProc 
' + SUBSTRING(@DeclareSQL, CHARINDEX(@FirstParam, @DeclareSQL), LEN(@DeclareSQL)) + ' 
' + @SelValues 

IF OBJECT_ID('TEMPDB..#sp_ParamDefaultProc') IS NOT NULL 
    DROP PROCEDURE #sp_ParamDefaultProc 
EXEC(@SQL) 

BEGIN TRY 
    EXEC(@ExecString) 
END TRY 
BEGIN CATCH 
    SELECT @ErrorStr = ERROR_MESSAGE(), 
      @ErrorId = ERROR_NUMBER() 
-- there must have been a comment containing equal sign between parameters 
    UPDATE p 
    SET  HasDefault = 0 
    FROM (SELECT PATINDEX ('%expects parameter ''@%', @ErrorStr) AS ii) i 
    CROSS APPLY (SELECT CHARINDEX ('''', @ErrorStr, ii + 20) AS uu) u 
    INNER JOIN @ParamTable p ON p.name = SUBSTRING(@ErrorStr, ii + 19, uu - ii - 19) 
    WHERE ii > 0 

    IF @@ROWCOUNT > 0 
     GOTO AGAIN 

    RAISERROR(@ErrorStr, 16, 1) 
    RETURN 30 
END CATCH 
GO 
EXEC sys.sp_MS_marksystemobject 
    sp_ParamDefault 
GO 
1

यह PowerShell में एसएमओ जवाब है:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null 

$srv = New-Object "Microsoft.SqlServer.Management.Smo.Server" "MyServer\MyInstance" 
$db = $srv.Databases["MyDatabase"]; 
$proc = $db.StoredProcedures["MyStoredProcedure"] 

foreach($parameter in $proc.Parameters) { 
    if ($parameter.DefaultValue){ 
    Write-Host "$proc , $parameter , $($parameter.DefaultValue)" 
    } 
    else{ 
    Write-Host "$proc , $parameter , No Default Value" 
    } 
} 
संबंधित मुद्दे

 संबंधित मुद्दे