web-dev-qa-db-fra.com

Type d'objet incompatible lors de la création et de la modification d'une fonction de valeur de table dans SQL

Je reçois l'erreur ci-dessous pour la fonction donnée.

Msg 2010, niveau 16, état 1, procédure GetTableFromDelimitedValues, ligne 2 Impossible d'effectuer une modification sur 'dbo.GetTableFromDelimitedValues' car il s'agit d'un type d'objet incompatible.

IF NOT EXISTS(SELECT 1 FROM sys.objects 
              WHERE object_id = OBJECT_ID('[GetTableFromDelimitedValues]'))
BEGIN
   EXECUTE('CREATE FUNCTION [dbo].[GetTableFromDelimitedValues](@input varchar(max),
       @delimiter char(1) = ",")) RETURNS @Result TABLE (
       Value nvarchar(4000)) AS BEGIN RETURN END')
END
GO


ALTER FUNCTION [dbo].[GetTableFromDelimitedValues](
       @input varchar(max),
       @delimiter char(1) = ',')
RETURNS @Result TABLE
(
       Value nvarchar(4000)
)
AS
BEGIN
    DECLARE @position int;
    DECLARE @column nvarchar(4000);

    WHILE LEN(@input) > 0
    BEGIN
        SET @position = CHARINDEX(@delimiter, @input);
        IF (@position < 0) OR (@position IS NULL)
        BEGIN
            SET @position = 0;
        END

        IF @position > 0 
        BEGIN
            SET @column = SUBSTRING(@input, 1, @position - 1);
            SET @input = SUBSTRING(@input, @position + 1, LEN(@input) - @position)
        END
        ELSE
        BEGIN
            SET @column = @input;
            SET @input = '';
        END 

        INSERT @Result (Value) 
        SELECT @column;
    END;

    RETURN;                
END
GO

Quelqu'un peut-il m'aider s'il vous plaît à obtenir le type compatible en corrigeant la fonction?

12
ary

Vous devezD&EACUTE;POSERetCR&EACUTE;ERla fonction dans ce contexte particulier 

Puisqu'il y a un changement de type de retour de fonction, nous devons abandonner puis recréer la fonction.

Il existe trois types de fonctions,

  • Scalaire
  • Table en ligne évaluée et
  • Multi Statement

ALTER ne peut pas être utilisé pour changer le type de fonction.

26
SharK
IF  EXISTS (SELECT [name] FROM sys.objects 
            WHERE object_id = OBJECT_ID('GetTableFromDelimitedValues'))
BEGIN
   DROP FUNCTION [GetTableFromDelimitedValues];
END
GO

/*  Now create function */
CREATE FUNCTION [dbo].[GetTableFromDelimitedValues](
       @input varchar(max),
       @delimiter char(1) = ',')
RETURNS @Result TABLE (
       Value nvarchar(4000)
)
AS
BEGIN
..
..
..
RETURN;
END

dans la fonction OBJECT_ID, vous ne devez transmettre que le nom de la fonction, pas le schéma. et pourquoi le créerait le 1 er, puis le Alter. Il suffit de vérifier l'existence tout d'abord si elle existe, puis supprimez une fonction et créez votre fonction comme je l'ai montré ci-dessus. 

De même, n’ajoutez pas Type dans la clause where lors de la vérification de l’existence, s’il existe un autre objet, non pas une fonction, mais un autre objet du même nom, il ne le prendra pas dans votre instruction select et vous finirez par créer une fonction avec nommer un objet existe déjà (cela jettera une erreur). 

SI vous voulez le faire à votre façon, voici comment vous vous y prendrez 

IF NOT EXISTS(SELECT 1 FROM sys.objects 
              WHERE object_id = OBJECT_ID('[GetTableFromDelimitedValues]'))
BEGIN
   EXECUTE('CREATE FUNCTION [dbo].[GetTableFromDelimitedValues]() RETURNS @Result TABLE (
       Value nvarchar(4000)) AS BEGIN RETURN END')
END
GO
3
M.Ali

J'ai quelque chose à signaler à votre erreur liée à votre code: 
L'erreur dit Cannot perform alter on 'dbo.GetTableFromDelimitedValues' because it is an incompatible object type
Ce qui signifie que vous devez regarder sur vos lignes après le ALTER....
Et oui, il y a: 
@input varchar(max)
SQL Server 2008 R2 n'accepte pas les objets varchar(MAX), mais uniquement si vous exécutez une procédure stockée.
Parce que si vous créez une table à la main, vous l'acceptez entièrement.
Si vous voulez une grande cellule, tapez varchar(1024) ou varchar(2048), les deux sont acceptés. Je fais face à ce problème il y a quelques jours ...
C'est mon humble avis 

MODIFICATIONS COMPLEMENTAIRES
Utilisez ceci

IF NOT EXISTS(SELECT 1 FROM sys.objects 
WHERE object_id = OBJECT_ID('[GetTableFromDelimitedValues]')) 
BEGIN 
execute('CREATE FUNCTION [dbo].[GetTableFromDelimitedValues]( @input varchar(max), @delimiter char(1)= ",") RETURNS @Result TABLE ( Value nvarchar(4000)) AS BEGIN RETURN END')
END GO


.... Faites attention au passage de "à"

** MODIFICATIONS SUPPLÉMENTAIRES ** 

J'utilise ce qui suit qui fonctionne aussi très bien ... sans aucun problème ...

IF  EXISTS (SELECT [name] FROM sys.objects 
            WHERE object_id = OBJECT_ID('GetTableFromDelimitedValues'))
BEGIN
   DROP FUNCTION [GetTableFromDelimitedValues];
END
BEGIN
   execute('CREATE FUNCTION [dbo].[GetTableFromDelimitedValues]() 
    RETURNS 
    @Result TABLE (
    Value nvarchar(4000)) 
    AS 
    BEGIN 
    RETURN 
    END')
    execute('ALTER FUNCTION [dbo].[GetTableFromDelimitedValues](
       @input varchar(max),
       @delimiter char(1) = ",")
       RETURNS @Result TABLE (
       Value nvarchar(4000))
       AS 
    BEGIN 
    RETURN 
    END')
END
GO
0
Lefteris Gkinis

Je confirme que le code ci-dessous fonctionne. On dirait que le problème était en quelque sorte une fonction de valeur scalaire créée avec le même nom au cours de mon développement et a eu une erreur en raison de la compatibilité de la fonction de déclaration de valeur de table à plusieurs pièces du script. 

IF NOT EXISTS(SELECT 1 FROM sys.objects 
              WHERE object_id = OBJECT_ID('[GetTableFromDelimitedValues]'))
BEGIN
   EXEC sp_executesql 
    @statement = N'CREATE FUNCTION dbo.[GetTableFromDelimitedValues] () RETURNS @Result 
    TABLE(Value nvarchar(4000))
    AS 
    BEGIN 
      RETURN 
    END' ;
END
GO

ALTER FUNCTION [dbo].[GetTableFromDelimitedValues](
    @input varchar(max),
    @delimiter char(1) = ',')
RETURNS @Result TABLE
(
    Value nvarchar(4000)
)
AS
BEGIN
    DECLARE @position int;
    DECLARE @column nvarchar(4000);

    WHILE LEN(@input) > 0
    BEGIN
        SET @position = CHARINDEX(@delimiter, @input);
        IF (@position < 0) OR (@position IS NULL)
        BEGIN
            SET @position = 0;
        END

        IF @position > 0 
        BEGIN
            SET @column = SUBSTRING(@input, 1, @position - 1);
            SET @input = SUBSTRING(@input, @position + 1, LEN(@input) - @position)
        END
        ELSE
        BEGIN
            SET @column = @input;
            SET @input = '';
        END 

        INSERT @Result (Value) 
        SELECT @column;
    END;

    RETURN;                
END
GO
0
ary