在SQL中创建和修改表值函数时出现不兼容的对象类型错误。

18

给定函数出现以下错误:

Msg 2010,级别16,状态1,过程GetTableFromDelimitedValues,行2 无法对'dbo.GetTableFromDelimitedValues'执行更改,因为它是不兼容的对象类型。

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

有人能否帮助我通过修复函数来获得兼容的类型?


以下回答中有没有解决这个问题? - Tab Alleman
6个回答

37

在这个特定的上下文中,你需要 DROP 并且 CREATE 函数。

由于函数返回类型发生了变化,我们必须先删除再重新创建该函数。

有三种类型的函数:

  • 标量
  • 内联表值
  • 多语句

无法使用 ALTER 改变函数类型。


5
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

OBJECT_ID函数中,您只需要传递函数名称而不是模式。为什么要先创建它,然后再使用Alter呢?首先检查它是否存在,如果存在,则删除函数并按照我上面展示的方式创建您的函数。
同时,在检查是否存在时,请勿在where子句中添加Type,如果有另一个对象而不是函数,但具有相同的名称,则不会在您的select语句中选择它,您最终将创建一个已经存在的对象名称的函数(这将引发错误)。
如果您想按照自己的方式操作,这就是您应该采取的步骤。
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

谢谢您的回复。最初我采用了您建议的相同方法(Drop|Create)来解决问题,但是由于DROP存在问题,有时执行用户可能没有在生产环境中进行DROP的权限,因此为了更安全起见,应该选择ALTER。 - ary
@ary 现在请看一下,我已经更新了我的答案以解决你在实际查询中遇到的问题。 - M.Ali
感谢您一直以来的帮助。 很抱歉它没有起作用,仍然显示相同的错误。 无法对“dbo.GetTableFromDelimitedValues”执行更改,因为它是不兼容的对象类型。 - ary

3

在我的情况下,这是因为我的表名和过程名完全相同。因此,更改过程名称或在过程中引用的表也应该可以解决此错误消息。


0

关于您代码相关的错误,我有一些通知:
这个错误说 Cannot perform alter on 'dbo.GetTableFromDelimitedValues' because it is an incompatible object type
这意味着您必须查看ALTER...之后的行。
而且确实有:
@input varchar(max)
SQL Server 2008 R2不接受对象varchar(MAX),但只适用于运行存储过程的情况。
因为如果您手动创建表,则完全接受它。
如果您想要一个大单元格,则可以键入varchar(1024)varchar(2048),两者都被接受。我几天前遇到了这个问题...
这是我的个人看法。

其他更改
请使用此文本

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


...注意从'到"

**其他更改**

我使用以下内容,也可以正常工作...没有任何问题...

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

尝试查看@delimiter char(1) = ','语法是否正确...无论如何,问题都来自这个区域。 - Lefteris Gkinis
对我来说很好用... 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 .... 注意从 '" 的更改 - Lefteris Gkinis
CREATE FUNCTION 中的执行在 IF NOT EXISTS 块内正常工作,但在后续的 ALTER FUNCTION 上出现问题,其中显示“无法对 'dbo.GetTableFromDelimitedValues' 执行 alter,因为它是不兼容的对象类型”。 - ary
嗨, 我已经更新了原始问题,完整的代码已经包含在内,该函数将返回逗号分隔输入的表值输出。IF块(其中编写CREATE FUNCTION的EXECUTE)如果我运行到IF块的末尾,则可以正常工作。这确保了语法是正确的。但是当我运行完整的脚本时,它会在ALTER FUNCTION处失败,说无法对'dbo.GetTableFromDelimitedValues'执行更改,因为它是不兼容的对象类型。 - ary
谢谢您的回复。@M.Ali也提出了同样的建议。最初我以相同的方式(Drop|Create)解决了这个问题,但是由于DROP存在问题,有时执行用户可能没有在生产环境中删除的权限,因此为了更安全起见,应该使用ALTER。 - ary
显示剩余2条评论

0

我确认下面的代码是有效的。似乎问题在于我的开发过程中创建了一个同名的标量值函数,并且由于脚本的多部分表值修改语句函数与它兼容,所以出现了错误。

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

enter image description here

  • 存在一个bug,函数创建后返回的数据未定义字段,只需在表格中添加字段即可解决。
  • 解决方案:
  • 删除该函数
  • 将关键词“Alter”更改为“Create”
  • 按下F5键创建函数,成功解决问题。

当前您的回答不够清晰明了,请进行[编辑]以添加更多细节帮助他人理解您的回答与问题相关。关于如何编写好的回答,您可以在帮助中心中找到更多信息。 - Community
请勿将代码包含在图片中。最好复制/粘贴。 - Elikill58

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接