سؤال

سأستهل هذا السؤال بالقول، لا أعتقد أنه قابل للحل.لدي أيضًا حل بديل، يمكنني إنشاء إجراء مخزن باستخدام OUTPUT لإنجاز ذلك، فمن الأسهل ترميز الأقسام التي أحتاج فيها إلى هذا المجموع الاختباري باستخدام دالة.

لن يعمل هذا الرمز بسبب Exec SP_ExecuteSQL @SQL المكالمات.هل يعرف أحد كيفية تنفيذ SQL الديناميكي في إحدى الوظائف؟(ومرة أخرى، لا أعتقد أن هذا ممكن.إذا كان الأمر كذلك، فأنا أحب أن أعرف كيفية التغلب عليه!)

Create Function Get_Checksum
(
    @DatabaseName      varchar(100),
    @TableName         varchar(100)
)
RETURNS FLOAT
AS
BEGIN

 Declare @SQL        nvarchar(4000)
 Declare @ColumnName varchar(100)
 Declare @i          int
 Declare @Checksum   float
 Declare @intColumns table (idRecord int identity(1,1), ColumnName varchar(255))
 Declare @CS         table (MyCheckSum bigint)

 Set @SQL = 
        'Insert Into @IntColumns(ColumnName)' + Char(13) + 
        'Select Column_Name' + Char(13) +
        'From   ' + @DatabaseName + '.Information_Schema.Columns (NOLOCK)' + Char(13) +
        'Where  Table_Name = ''' + @TableName + '''' + Char(13) +
        '       and Data_Type = ''int''' 

 -- print @SQL

 exec sp_executeSql @SQL

 Set @SQL = 
        'Insert Into @CS(MyChecksum)' + Char(13) + 
        'Select '

 Set @i = 1

 While Exists(
       Select 1
       From   @IntColumns
       Where  IdRecord = @i)
 begin
       Select @ColumnName = ColumnName
       From   @IntColumns
       Where  IdRecord = @i

       Set @SQL = @SQL + Char(13) + 
            CASE WHEN @i = 1 THEN 
                 '    Sum(Cast(IsNull(' + @ColumnName + ',0) as bigint))'
                 ELSE
                 '    + Sum(Cast(IsNull(' + @ColumnName + ',0) as bigint))'
            END

       Set @i = @i + 1
 end

 Set @SQL = @SQL + Char(13) + 
      'From ' + @DatabaseName + '..' + @TableName + ' (NOLOCK)'

 -- print @SQL

 exec sp_executeSql @SQL

 Set @Checksum = (Select Top 1 MyChecksum From @CS)

 Return isnull(@Checksum,0)

END
GO
هل كانت مفيدة؟

المحلول

لا يمكن القيام بذلك "عادة" لأن SQL Server يعامل الوظائف على أنها حتمية، مما يعني أنه بالنسبة لمجموعة معينة من المدخلات، يجب دائمًا إرجاع نفس المخرجات.يمكن أن يكون الإجراء المخزن أو SQL الديناميكي غير حتمي لأنه يمكن أن يغير الحالة الخارجية، مثل الجدول الذي يتم الاعتماد عليه.

نظرًا لأن وظائف خادم SQL تكون دائمًا حتمية، فسيكون من السيئ من منظور الصيانة المستقبلية محاولة التحايل على هذا لأنه قد يسبب ارتباكًا كبيرًا إلى حد ما لأي شخص يتعين عليه دعم الكود في المستقبل.

نصائح أخرى

هنا هو الحل

الحل 1:قم بإرجاع السلسلة الديناميكية من الوظيفة بعد ذلك

Declare @SQLStr varchar(max) 
DECLARE @tmptable table (<columns>)
set @SQLStr=dbo.function(<parameters>)
insert into @tmptable
Exec (@SQLStr)

select * from @tmptable

الحل 2:استدعاء الوظائف المتداخلة عن طريق تمرير المعلمات.

يمكنك التغلب على ذلك عن طريق استدعاء إجراء مخزن موسع، مع كل ما يصاحب ذلك من متاعب ومشكلات أمنية.

http://decipherinfosys.wordpress.com/2008/07/16/udf-limitations-in-sql-server/

http://decipherinfosys.wordpress.com/2007/02/27/using-getdate-in-a-udf/

نظرًا لأن الوظائف يجب أن تعمل بشكل جيد مع مُحسِّن الاستعلام، فهناك عدد غير قليل من القيود عليها. هذا الرابط يشير إلى مقال يناقش القيود المفروضة على UDF بعمق.

شكرا لكم جميعا على الردود.

رون:لمعلوماتك، سيؤدي استخدام ذلك إلى حدوث خطأ.

أوافق على أن عدم القيام بما كنت أنويه في الأصل هو الحل الأفضل، فقررت أن أسلك طريقًا مختلفًا.كان خياري اثنين للاستخدام sum(cast(BINARY_CHECKSUM(*) as float)) أو معلمة إخراج في إجراء مخزن.بعد اختبار سرعة الوحدة لكل منها، قررت أن أذهب معها sum(cast(BINARY_CHECKSUM(*) as float)) للحصول على قيمة مجموع اختباري قابلة للمقارنة لبيانات كل جدول.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top