【问题标题】:A SQL Server function to generate of sequential numbers用于生成序列号的 SQL Server 函数
【发布时间】:2011-10-29 00:33:03
【问题描述】:

我想要一个 SQL Server 函数dbo.GetNextNumber(),它会为每个调用生成序列号。据我了解,使用本机 T-SQL 函数是不可能的,因为 SQL Server 坚持认为函数必须是确定性的。但是,如果您可以向我展示一个执行此操作的本机 T-SQL 函数,那真的会让我很开心。

我想也许这可以使用 CLR 函数来编写。由于 CLR 函数是静态的,因此序列号需要存储在 set 操作的调用上下文中,因为将其存储为静态变量会导致多个连接使用相同的序列,从而导致序列号不那么连续。我对嵌入式 CLR 了解得不够多,无法从 CLR 端访问设置操作(选择、更新、删除、插入)的调用上下文。

最后,下面的查询

select dbo.GetNextNumber() from sysobjects

必须返回结果

1
2
3
4
5

如果需要另一个函数来重置上下文是可以的,比如

exec dbo.ResetSequenceNumbers()

为了防止一些误解并减少浪费时间回答错误问题的机会,请注意,我不是在寻找表格的 ID 生成功能,而且我知道一些技巧(尽管使用 proc 不是函数)这涉及一些带有标识列的临时表。 ROW_NUMBER() 函数已关闭,但它也没有剪切。

非常感谢您的任何回复

凯末尔

附:令人惊奇的是,SQL Server 确实为此提供了内置函数。一个函数(前提是它不能用在连接和 where 子句中)确实很容易做并且非常有用,但由于某种原因它没有被包括在内。

【问题讨论】:

  • 与其要求“sql server function dbo.GetNextNumber()”,不如告诉我们您实际要解决的问题。
  • 您可以使用只有一个 ID INT IDENTITY(1,1) 列的“帮助”表,并在每次插入后获取值(使用 SELECT SCOPE_IDENTITY()),或者您可以等待 SQL Server“Denali”(2011 / 2012) 将有 SEQUENCES as native database objects 用于此目的
  • SQL-Server 函数不必是确定性的。在某些情况下,需要确定性函数(例如计算列)。

标签: sql-server sqlclr sequences clr-hosting


【解决方案1】:

在 SQL Server 的下一版本中,您可以使用 SEQUENCE 来执行此操作。在早期版本中,通过插入单独的“序列表”(只有一个 IDENTITY 列的表)然后使用 SCOPE_IDENTITY() 函数检索值很容易。您无法在函数中执行此操作,但可以使用存储过程。

【讨论】:

  • 这不行,因为 sql server 不允许在函数中封装这个逻辑。也许,我应该创建一个 CLR 函数来做到这一点。但这将是一个 hack,而不是一个优雅的解决方案
  • 我想每个人都想知道的是,为什么在函数而不是过程中执行此操作对您如此重要。您正在尝试将函数用于它们不适合的用途。
【解决方案2】:

你能提供更多关于为什么ROW_NUMBER() 没有删减它的信息吗?在您给出的具体示例中,ROW_NUMBER()(对OVER(ORDER BY) 进行了适当的澄清)似乎符合您的标准。

但在某些情况下ROW_NUMBER() 可能没有用,在这些情况下,通常还有其他技术。

也许拥有这个通用函数对你来说似乎很有用,但在大多数情况下,我发现一个更适合手头问题的解决方案比通用函数更好,后者最终会导致更多困难 - 就像你的抽象泄漏一直在工作。您特别提到需要具有重置功能。 ROW_NUMBER() 不需要这样的东西,因为它具有允许您指定分组的 OVER(PARTITION BY ORDER BY)

【讨论】:

  • row_number 需要一个过度谓词,它会强制您指定 order by 子句。在我的某些情况下,我需要在自然顺序很重要的临时表上使用该函数。而且,在其他一些情况下,可以在那里指定的列直到运行时才知道,这迫使您使用动态 sql。最后,您必须将所有内容包装到子查询中才能使用 row_number() 的值。不太好
  • @Kemal Erdogan SQL 中没有自然顺序这样的东西。如果您依赖插入顺序或聚集索引或其他任何东西,则没有 ORDER BY 就无法保证顺序。虽然您可能碰巧收到了订单并且它看起来很可靠,但没有 ORDER BY 就无法保证。 SQL 是一种声明性语言,没有声明或您的愿望,就无法保证。
  • @Kemal Erdogan 仅仅因为插入顺序在表的页面结构中是完整的,就意味着稍后返回值或加入其他事物或进行任何操作时都没有任何意义。坦率地说,我要再说一遍,在没有ORDER BY 的情况下依靠稍后以任何顺序拉出的行是不负责任的。 blogs.msdn.com/b/sqltips/archive/2005/07/20/441053.aspxstackoverflow.com/questions/1387008/…blogs.msdn.com/b/queryoptteam/archive/2006/03/24/560396.aspx
  • @Kemal Erdogan 堆表有一个普通的非聚集索引覆盖您的特定查询,这样堆表就不会被实际访问?所以现在我们要处理未连接到查询中任何其他内容的未索引堆表。
  • @Kemal,即使在堆表中也没有“自然顺序”之类的东西。堆表不保留插入顺序,当然也不能以任何方式在后续 SQL 查询中利用。
【解决方案3】:

SQL Server Denali 为开发人员提供了新的序列结构 Denali 之后在 SQL Server 中管理和维护序列号很容易 您可以在Sequence Numbers in SQL Server中找到详细信息

对于 Denali 以外的其他版本,您可以使用序列表。 这是Sequence Table in SQL Server 的示例 要从序列表中读取序列号,您应该从这个启用自动标识的 sql 表中插入虚拟记录

【讨论】:

    【解决方案4】:

    由于您已经根据我关于运行总计计算的文章实现了 CLR 序列,因此您可以使用 ROW_NUBER() 函数实现相同的功能。

    ROW_NUMBER() 函数需要在OVER 子句中使用ORDER BY,但是有一个很好的解决方法来避免由于ORDER BY 而进行排序。您不能将表达式按顺序排列,但您可以将SELECT aConstant 放在那里。因此,您可以使用以下语句轻松实现数字生成。

    SELECT
        ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNumber,
        *
    FROM aTable
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-08
      • 1970-01-01
      • 1970-01-01
      • 2015-04-13
      • 2017-03-03
      • 2023-02-18
      • 2014-05-03
      • 1970-01-01
      相关资源
      最近更新 更多