在 SQL Server 中使用基于多个字段的自动序列创建触发器

Posted

技术标签:

【中文标题】在 SQL Server 中使用基于多个字段的自动序列创建触发器【英文标题】:Creating a Trigger in SQL Server with auto sequence based on multiple fields 【发布时间】:2019-11-05 20:16:43 【问题描述】:

我正在尝试为我在 SQL Server 中的 UniqueID 字段创建一个自动序列触发器,该触发器依赖于多个字段。例如,我有一个名为animals 的表,列有Species, Sex, UniqueID。我正在尝试创建一个触发器,用于输入物种和性别时,UniqueID 字段会根据该物种和性别的最后一个序列号自动填充。需要看起来像DeerM0001。这是我到目前为止所拥有的,但它不起作用。

CREATE TRIGGER tr_animalID
ON  animal
AFTER INSERT, UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    DECLARE @ID varchar(8)
    SET @ID = (SELECT max(Species) FROM animal);

    UPDATE animal
    SET UniqueID = CONCAT(Species, Sex) +0001 
    WHERE UniqueID = @ID;
END
GO

【问题讨论】:

说“它不起作用”是没有用的。你需要解释什么不起作用。从发布的代码中,我看到了很多错误。你的触发器有一个重大缺陷。它假设您只会插入一行。您也没有引用插入的虚拟表。您正在尝试为字符添加数字。 这在多用户环境中不起作用,因为选择和更新之间存在时间间隔。您需要引入锁定以防止竞争条件。 一开始我会引导你不要尝试像这样给每只动物编号。当你删除一行时会发生什么?突然你的编号全错了。您要么有一个间隙,要么可能插入一个新动物,其“UniqueID”与最后一个被删除的动物具有相同的“UniqueID”。这是XY Problem 今天不会,但将来可能会。您在这里尝试做的是违反 1NF,因为您将三条信息推送到一个元组中。这也是为什么你在逻辑上挣扎的原因。这不是关系数据的设计方式。 我会完全使用 guid 或其他东西。您在这里的设计过于依赖这种逻辑。如果每个数字都可以是唯一的,那么您可以轻松地利用计算列和标识。或者,也许您可​​以为您可以使用的每个物种生成一个序列。 【参考方案1】:

这是一个使用具有标识的计算列来处理此类事情的示例。我建议将 Species 存储为字符串不是一个好计划。您应该有一个 Species 表以避免一遍又一遍地输入名称。它可以防止拼写错误,还可以轻松支持多种语言。另外,请注意,使用 0 进行右填充,就像您对系统有内置限制一样。它最终会用完数字。

create table Animal
(
    AnimalID int identity
    , Species varchar(10) --this should really be a foreign key instead of the name over and over
    , Sex char(1) not null
    , UniqueID as Concat(Species, Sex) + right(replicate('0', 8) + convert(varchar(10), AnimalID), 6) --this pads the identity value to a max length of 6.
)

insert Animal values
('Deer', 'M')
, ('Deer', 'M')
, ('Deer', 'M')
, ('Deer', 'F')
, ('Deer', 'F')
, ('Deer', 'F')
, ('Deer', 'F')
, ('Deer', 'F')
, ('Goat', 'F')
, ('Goat', 'F')
, ('Goat', 'M')
, ('Goat', 'M')
, ('Goat', 'M')
, ('Goat', 'M')

select *
from Animal

如果你真的想使用一个序列,基本语法就是这么简单。

create sequence MySequence as int start with 1 increment by 1

select next value for MySequence

您可以找到数千个其他示例here。

【讨论】:

我尝试运行您的示例,但它不会重新启动雌鹿的序列。例如:鹿 M 是 DeerM0000001,但鹿 F 是 DeerF0000002。我需要它是 DeerF0000001,因为它是第一只雌鹿。绝对同意添加物种表。 对。正如我所说,这不会重新启动序列(提示序列是 sql server 中的一个对象)。这是一个简单的解决方案,不需要很多开销。您所描述的内容将需要每个物种的不同序列。而且您必须在每次插入时都从正确的序列中获取下一个值。您所追求的编号类型很常见,但不容易实现。 谢谢。您能否提供一个示例或链接,说明该序列的语法可能是什么样的?真的很感激。

以上是关于在 SQL Server 中使用基于多个字段的自动序列创建触发器的主要内容,如果未能解决你的问题,请参考以下文章

SQL server 数据库字段自动生成20位的随机数

SQL server怎么在更新数据的时候让字段自动加1,

sql server 2005 一个索引多个字段,字段的排列顺序对搜索有啥影响??

sql server 2008中如何取某字段最大值所在的一条数据(多个字段)

如何在 SQL Server 的触发器中获取多个字段的旧值和新值?

SQL SERVER 从 If Exists 中选择多个字段