web-dev-qa-db-fra.com

Utilisation non valide d'un opérateur ayant des effets secondaires Insérer dans une fonction

J'ai le code suivant dans ma fonction SQL:

if @max_chi > -999
begin
    INSERT INTO CH_TABLE(X1, X2, VALUE)
    VALUES(cur_out.sessionnumber, maxpos, max_chi)

    commit
end

Voici une requête SQL Server 2008 qui me donne une erreur:

Utilisation non valide d'un opérateur ayant un effet secondaire 'INSERT' dans une fonction.

Pourquoi ne suis-je pas autorisé à faire cela? Que puis-je faire pour résoudre ce problème?

40
user2496503

Vous ne pouvez pas utiliser une fonction pour insérer des données dans une table de base. Fonctions retour données. Ceci est répertorié comme la tout d'abord limitation dans la documentation :

Les fonctions définies par l'utilisateur ne peuvent pas être utilisées pour effectuer des actions modifiant l'état de la base de données.

"Modifier l'état de la base de données" inclut la modification des données de la base de données (bien qu'une variable de table soit une exception évidente, le PO ne l'aurait pas considéré il y a 3 ans - cette variable de table ne vit que pendant la durée de l'appel de fonction et n'affecte pas les tables sous-jacentes de quelque manière que ce soit).

Vous devriez utiliser une procédure stockée, pas une fonction.

68
Aaron Bertrand

J'ai trouvé un moyen de faire une insertion ou une mise à jour, il vous suffit donc de remplacer le code à l'intérieur de @sql variable.

CREATE FUNCTION [dbo].[_tmp_func](@orderID NVARCHAR(50))
RETURNS INT
AS
BEGIN
DECLARE @sql varchar(4000), @cmd varchar(4000)
SELECT @sql = 'INSERT INTO _ord (ord_Code) VALUES (''' + @orderID + ''') '
SELECT @cmd = 'sqlcmd -S ' + @@servername +
              ' -d ' + db_name() + ' -Q "' + @sql + '"'
EXEC master..xp_cmdshell @cmd, 'no_output'
RETURN 1
END
9
Yurii Tsurul

Les fonctions ne peuvent pas être utilisées pour modifier les informations de la table de base, utilisez une procédure stockée.

8
Sonam

Il existe une exception (j'utilise SQL 2014) lorsque vous utilisez uniquement Insérer/Mettre à jour/Supprimer sur les tables déclarées. Ces instructions Insert/Update/Delete ne peuvent pas contenir d'instruction OUTPUT. L'autre restriction est que vous n'êtes pas autorisé à faire une fusion, même dans une table déclarée. J'ai divisé mes instructions de fusion qui ne fonctionnaient pas en instructions d'insertion/mise à jour/suppression qui fonctionnaient.

La raison pour laquelle je ne l'ai pas convertie en procédure stockée est que la fonction table était plus rapide (même sans MERGE) que la procédure stockée. Ceci malgré la procédure stockée me permettant d'utiliser des tables temporaires contenant des statistiques. J'avais besoin que la fonction table soit très rapide car elle s'appelle 20-K fois/jour. Cette fonction de table ne met jamais à jour la base de données.

J'ai également remarqué que les fonctions NewId () et Rand () SQL ne sont pas autorisées dans une fonction.

3
Michael Barash