插入具有标识的多行时是否保证订单?

时间:2016-01-05 21:02:43

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

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

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更高?

3 个答案:

答案 0 :(得分:6)

以前曾问过非常相似的question

您可以在ORDER BY中指定INSERT

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

使用您的示例:

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值之间可能存在间隙,但它们的相对顺序是有保证的。

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

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

问题INSERT INTO as SELECT with ORDER BY来自MS的Umachandar Jayachandran说:

  

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

他给了Ordering guarantees in SQL Server的链接,来自SQL Server Engine团队的Conor Cunningham说:

  
      
  1. 使用SELECT和ORDER BY来填充行的INSERT查询保证了如何计算标识值,但不保证计算标识值的顺序   插入行
  2.   

在该帖子的评论中有一个指向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查询以填充此表。

我会将此知识库文章视为官方文档,并认为此行为得到保证。

答案 1 :(得分:0)

您最好的两个选择是:

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

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

答案 2 :(得分:0)

不,这不能保证。这相当于

INSERT INTO @blah (Name)
SELECT *
FROM (VALUES ('Timmy'),
    ('Jonny'),
    ('Sally')) x(y)

FROM子句只是一个无序集。

您可以引入一列作为唯一键:

INSERT INTO @blah (Name)
OUTPUT RowNum, INSERTED.ID
SELECT Name
FROM (VALUES (1, 'Timmy'),
    (2, 'Jonny'),
    (3, 'Sally')) x(RowNum, Name)

然后,您可以使用RowNum唯一标识行,并将其与生成的ID进行匹配。

可能INSERT语句不允许输出非插入列。您可以使用MERGE