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
Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top