【问题标题】:Row_Number() would return different return values as TSQL and User Defined functionRow_Number() 将返回不同的返回值作为 TSQL 和用户定义的函数
【发布时间】:2020-11-19 02:55:05
【问题描述】:

我有一个包含 57 行的表 Products。我有以下用户定义的功能

    Create alter FUNCTION [dbo]. [ufn_GenerateNewProductId]()
    RETURNS nvarchar (MAX)
    as
    begin
    declare @NewproductId nvarchar(MAX), @rowNum int
    select @rowNum=ROW_NUMBER() over (order by ProductId) from Products;
    set @rowNum=@rowNum+1+100;
    set @NewproductId='P' + cast(@rowNum as nvarchar(MAX));
    return @NewproductId;
    end

当我如下调用用户定义的函数时,它在@product 中有值“P158”:

declare @product nvarchar(max);

select @product= dbo.ufn_GenerateNewProductId();

print @product;

当我如下调用它时,它会返回值'P102'。

select dbo.ufn_GenerateNewProductId();

请帮助我理解为什么在这两种情况下 Row_Number() 的行为会有所不同。

【问题讨论】:

  • 您的用户定义函数没有意义。据推测,查询返回多行。然后将任意值分配给变量。
  • select @rowNum=ROW_NUMBER() over (order by ProductId) from Products; 并没有多大意义。 SELECT 我们将返回一个数据集,而您将分配给一个标量变量。那应该是SET @rowNum = (SELECT COUNT(*) FROM from Products);
  • 我还怀疑这里有一些标量内联“功能”,但这不是函数的错误,而是函数的编写方式。
  • 返回 nvarchar(max)?再试一次。
  • 另外,查看函数名称ufn_GenerateNewProductId 表明您这样做是为了为表创建一个新的 id。一旦您有 2 个或更多同时交易,这将无法正常工作。 SQL Server 有一个IDENTITY 属性和SEQUENCE 对象是有原因的。

标签: sql sql-server count window-functions sql-function


【解决方案1】:

查询返回多行,因此不确定哪个值实际关联到标量变量。

看起来你真的想要count(*)

create or alter function [dbo].[ufn_generatenewproductid]()
returns nvarchar (max)
as
begin
    declare @newproductid nvarchar(max), @cnt int;
    select @cnt = count(*) + 101 from products;
    set @newproductid='P' + cast(@cnt as nvarchar(max));
    return @newproductid;
end

请注意,您可以跳过其中一个变量并直接计算新产品 ID:

create or alter function [dbo].[ufn_generatenewproductid]()
returns nvarchar (max)
as
begin
    declare @newproductid nvarchar(max);
    select @newproductid = concat('P', count(*) + 101) from products;
    return @newproductid;
end

【讨论】:

  • 我偶然发现了这种行为,我只是想了解行为的差异。这个问题只是一个例子。
【解决方案2】:

我怀疑你要生成一个新的产品 id,其中 id 值比当前产品数量大一。

如果是这样,你想要这样的逻辑:

Create alter FUNCTION dbo.ufn_GenerateNewProductId()
RETURNS nvarchar (MAX)
as begin
    declare @NewproductId nvarchar(MAX), @rowNum int

    select @NewproductId = concat('P', COUNT(*) + 1)
    from Products;
    return @NewproductId;
end;

如果某些内容被删除,您可能希望使用当前值并添加 1:

Create alter FUNCTION dbo.ufn_GenerateNewProductId()
RETURNS nvarchar (MAX)
as begin
    declare @NewproductId nvarchar(MAX), @rowNum int

    select @NewproductId = concat('P', convert(int, max(stuff(productid, 1, 1, ''))) + 1)
    from Products;
    return @NewproductId;
end;

我强烈建议您不要执行其中任何一种方法——代码存在并发问题,并且比替代方法慢得多。只需使用 identity 列来定义 id。

【讨论】:

    猜你喜欢
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    相关资源
    最近更新 更多