Exécution de SQL dynamique dans une fonction SQLServer 2005
-
02-07-2019 - |
Question
Je vais commencer cette question en disant: je ne pense pas que ce soit soluble. J'ai aussi une solution de contournement, je peux créer une procédure stockée avec une OUTPUT pour ce faire, il est simplement plus facile de coder les sections où j'ai besoin de cette somme de contrôle à l'aide d'une fonction.
Ce code ne fonctionnera pas à cause des appels Exec SP_ExecuteSQL @SQL
. Quelqu'un sait comment exécuter SQL dynamique dans une fonction? (Et encore une fois, je ne pense pas que ce soit possible. Si c'est le cas, j'aimerais savoir comment le contourner!)
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
La solution
Il " ordinairement " ne peut pas être effectué car SQL Server traite les fonctions comme déterministes, ce qui signifie que pour un ensemble d'entrées donné, il doit toujours renvoyer les mêmes sorties. Une procédure stockée ou un SQL dynamique peut être non déterministe, car il peut modifier un état externe, tel qu'une table, sur laquelle on se fie.
Etant donné que dans SQL Server, les fonctions du serveur sont toujours déterministes, ce serait une mauvaise idée de tenter de le contourner du point de vue de la maintenance, car cela risquerait de créer une grande confusion pour les utilisateurs qui devront prendre en charge le code à l'avenir.
Autres conseils
Voici la solution
Solution 1: Renvoie la chaîne dynamique depuis Function puis
.Declare @SQLStr varchar(max)
DECLARE @tmptable table (<columns>)
set @SQLStr=dbo.function(<parameters>)
insert into @tmptable
Exec (@SQLStr)
select * from @tmptable
Solution 2: appeler des fonctions imbriquées en passant des paramètres.
Vous pouvez contourner ce problème en appelant une procédure stockée étendue, avec tous les problèmes liés à la surveillance et aux problèmes de sécurité.
http: //decipherinfosys.wordpress. com / 2008/07/16 / udf-limitations-in-sql-server /
http: //decipherinfosys.wordpress. com / 2007/02/27 / using-getdate-in-a-udf /
Etant donné que les fonctions doivent bien fonctionner avec l’optimiseur de requêtes, elles sont soumises à quelques restrictions. Ce lien renvoie à un article qui traite en profondeur des limitations des fonctions UDF.
Merci à tous pour vos réponses.
Ron: Pour votre information, utiliser cette option génère une erreur.
Je conviens que ne pas faire ce que j'avais initialement prévu était la meilleure solution, j'ai décidé de choisir une autre voie. Mes deux choix consistaient à utiliser sum (transtypé (BINARY_CHECKSUM (*) en tant que float))
ou un paramètre de sortie dans une procédure stockée. Après avoir testé la vitesse de chaque unité, j'ai décidé d'utiliser sum (converti (BINARY_CHECKSUM (*) en tant que float))
pour obtenir une valeur de somme de contrôle comparable pour les données de chaque table.