【问题标题】:Is Order Guaranteed When Inserting Multiple Rows with Identity?插入具有标识的多行时是否保证顺序?
【发布时间】:2016-04-09 20:07:47
【问题描述】:

在表中插入多行时,是否可以保证它们按我指定的顺序插入?例如,采取以下措施:

DECLARE @blah TABLE
(
    ID INT IDENTITY(1, 1),
    Name VARCHAR(100) NOT NULL
);

INSERT INTO @blah (Name)
    VALUES('Timmy'),
    ('Jonny'),
    ('Sally');

SELECT * FROM @blah

是否可以保证Sally 的主键高于Timmy?

【问题讨论】:

  • 既然你在使用身份,为什么这很重要?您正在有效地使用随机(尽管是可预测的)数字。我很确定它们会按指定的顺序插入,但这真的重要吗?
  • 是的,这很重要。这是我能想出的最简单的问题形式,但在“现实世界”场景中,我正在输出身份,并在其他地方使用它们。
  • 你永远不应该使用这样的标识列。如果您需要保证数字遵循某种可预测的序列,那么您应该明确生成该序列。您不是在寻找身份列,而是在寻找在数据库中具有某种业务意义的东西,您应该定义该含义并为其提供服务。
  • 如果您要在其他地方使用分配的标识值,那么您应该使用 OUTPUT 子句。这样您就可以 100% 确定哪个标识值与输入值中的哪一行匹配。
  • 您似乎依赖于跨多个表的身份属性值来保持同步。这是非常脆弱的。让身份发挥作用并利用该价值。试图估计它可能会导致重大问题。

标签: sql sql-server sql-server-2012


【解决方案1】:

您最好的两个选择是:

单独处理行 - 插入父行,获取 ID,然后插入子行,然后插入下一个父行,等等。

或者,假设数据在现实世界中具有实际标识符(例如,电子邮件地址、SSN 等),那么您可以在插入子表时使用它来连接回父表。

【讨论】:

    【解决方案2】:

    之前问过非常相似的question。

    您可以在INSERT 中指定ORDER BY。

    如果你这样做,IDENTITY 值的生成顺序保证与INSERT 中指定的ORDER BY 匹配。

    用你的例子:

    DECLARE @blah TABLE
    (
        ID INT IDENTITY(1, 1) NOT NULL,
        Name VARCHAR(100) NOT NULL
    );
    
    INSERT INTO @blah (Name)
    SELECT T.Name
    FROM
        (
            VALUES
            ('Timmy'),
            ('Jonny'),
            ('Sally')
        ) AS T(Name)
    ORDER BY T.Name;
    
    SELECT
        T.ID
        ,T.Name
    FROM @blah AS T
    ORDER BY T.ID;
    

    结果是:

    +----+-------+
    | ID | Name  |
    +----+-------+
    |  1 | Jonny |
    |  2 | Sally |
    |  3 | Timmy |
    +----+-------+
    

    即Name已经按照这个顺序进行了排序并生成了ID。保证 Jonny 的 ID 最低,Timmy 的 ID 最高,Sally 的 ID 介于两者之间。生成的 ID 值之间可能存在间隙,但它们的相对顺序是有保证的。

    如果您未在 INSERT 中指定 ORDER BY,则生成的 IDENTITY ID 可以按不同的顺序生成。

    请注意,即使INSERT 中的ORDER BY 也不能保证表中行的实际物理顺序,唯一的保证是生成的 ID。

    MS 的 INSERT INTO as SELECT with ORDER BYUmachandar Jayachandran 在一个问题中说:

    唯一的保证是身份值将根据生成 在 ORDER BY 子句上。但是不能保证顺序 将行插入到表中。

    他还提供了一个指向 Ordering guarantees in SQL Server 的链接,来自 SQL Server 引擎团队的 Conor Cunningham 说:

    1. 使用带有 ORDER BY 的 SELECT 来填充行的 INSERT 查询保证了标识值的计算方式,但不保证计算的顺序 行已插入

    该帖子的 cmets 中有一个指向 MS 知识库文章的链接:The behavior of the IDENTITY function when used with SELECT INTO or INSERT .. SELECT queries that contain an ORDER BY clause,其中对其进行了更详细的解释。它说:

    如果您希望按顺序分配 IDENTITY 值 遵循ORDER BY 子句中的顺序,创建一个表 包含具有IDENTITY 属性的列,然后运行INSERT ... SELECT ... ORDER BY 查询来填充此表。

    我会将这篇知识库文章视为官方文档,并认为这种行为是有保证的。

    【讨论】:

    • 这是保证还是当前行为?我不会将 Umachandar Jayachandran 的声明视为此处的官方产品文档。
    • 在任何情况下,标识值都可能存在间隙,因此无法恢复它们。不确定他是否需要那个。大概吧。
    • @usr,Ordering guarantees in SQL Server 帖子有一个指向 MS 知识库文章 The behavior of the IDENTITY function when used with SELECT INTO or INSERT .. SELECT queries that contain an ORDER BY clause 的链接,其中更详细地解释了它。所以,是的,我会将其视为官方文档,并认为这种行为是有保证的。
    • @usr,是的,生成的标识值可能有差距,但问题是“是否可以保证 Sally 的主键比 Timmy 更高?”答案是:“是的,如果您在INSERT 中使用适当的ORDER BY”,而您的回答是:“否”。
    • @TomH,我没有问他们是否是连续的。我问是否可以保证订单。 (“是否可以保证 Sally 的主键会比 Timmy 更高?”)我这样说是因为我知道无法保证不会有间隙。
    猜你喜欢
    • 1970-01-01
    • 2011-02-08
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    • 2022-08-02
    相关资源
    最近更新 更多