Ausführen von dynamischen SQL in einer SQL Server 2005-Funktion
-
02-07-2019 - |
Frage
Ich werde diese Frage Vorwort mit den Worten: Ich glaube nicht, es lösbar ist. Ich habe auch ein Problem zu umgehen, ich eine gespeicherte Prozedur mit einem OUTPUT dies zu erreichen, schaffen kann, ist es einfach leichter ist, die Abschnitte zu codieren, wo ich diese Prüfsumme brauche eine Funktion verwenden.
Dieser Code wird nicht wegen der Exec SP_ExecuteSQL @SQL
Anrufe arbeiten. Wer weiß, wie dynamische SQL in einer Funktion auszuführen? (Und noch einmal, ich glaube nicht, es ist möglich. Wenn es aber ist, würde ich gerne wissen, wie um es zu bekommen!)
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
Lösung
Es „normalerweise“ nicht getan werden kann, wie SQL Server-Funktionen als deterministisch behandelt, was bedeutet, dass für einen bestimmten Satz von Eingaben, es sollte immer die gleichen Ausgänge zurück. Eine gespeicherte Prozedur oder dynamische SQL kann nicht-deterministisch sein, weil es externen Zustand ändern kann, wie zum Beispiel einer Tabelle, die auf sich verlassen.
Da in SQL-Server-Funktionen immer deterministisch sind, wäre es eine schlechte Idee von einer künftigen Wartung Perspektive zu sein, dies zu versuchen zu umgehen, da es ziemlich große Verwirrung für jedermann dazu führen könnte, die den Code in Zukunft zu unterstützen haben.
Andere Tipps
Hier ist die Lösung
Lösung 1: Gibt die dynamische Zeichenfolge Funktion dann
Declare @SQLStr varchar(max)
DECLARE @tmptable table (<columns>)
set @SQLStr=dbo.function(<parameters>)
insert into @tmptable
Exec (@SQLStr)
select * from @tmptable
Lösung 2: verschachtelte Funktionen aufrufen Parameter übergeben.
Sie können dies umgehen, indem eine erweiterte gespeicherte Prozedur aufrufen, mit all den damit verbundenen Aufwand und Sicherheitsprobleme.
http: //decipherinfosys.wordpress. com / 2008/07/16 / UDF-Grenzen-in-sQL-Server /
http: //decipherinfosys.wordpress. com / 2007/02/27 / mit-getdate-in-a-UDF /
Da Funktionen gut mit den Abfrage-Optimierer zu spielen haben, gibt es durchaus ein paar Einschränkungen auf sie. Dieser Link verweist zu einem Artikel, der die Grenzen der UDF in der Tiefe diskutiert.
Vielen Dank für die Antworten.
Ron. FYI, dass Verwendung einen Fehler werfen
Ich bin damit einverstanden, dass nicht zu tun, was ich ursprünglich die beste Lösung gedacht ist, habe ich beschlossen, einen anderen Weg zu gehen. Meine zwei Möglichkeiten waren sum(cast(BINARY_CHECKSUM(*) as float))
oder einen Ausgabeparameter in einer gespeicherten Prozedur verwenden. Nach Einheit Prüfgeschwindigkeit von jedem, habe ich beschlossen, mit sum(cast(BINARY_CHECKSUM(*) as float))
zu gehen, um einen vergleichbaren Prüfsummenwert für die Daten jeder Tabelle zu erhalten.