4

我有一个典型的非规范化表 ( tempTable),其中包含多个编号的列 ( rep1, rep2,...)。所以我写了一个脚本来将非规范化的数据插入到一个规范化的表中(myTable):

insert into myTable
select idRep,rep FROM
(
    select idRep, ISNULL(rep1,'') as rep FROM tempTable
    union
    select idRep, ISNULL(rep2,'') as rep FROM tempTable
    union
    select idRep, ISNULL(rep3,'') as rep FROM tempTable
    union
    select idRep, ISNULL(rep4,'') as rep FROM tempTable
    union
    select idRep, ISNULL(rep5,'') as rep FROM tempTable
) as t

注意:该表myTable还包含一个自动递增的IDENTITY列作为其PRIMARY KEY.

在我的场景中,rep1、rep2、rep3、rep4、rep5 的顺序很重要。奇怪的是,当我执行脚本时,数据没有以正确的顺序插入,例如自动生成的 id '1000' 的值来自 'rep3' 而 id '1001' 的值来自 'rep1'。

这是为什么?脚本是如何执行的?

4

3 回答 3

9

使用 UNION 时它没有按照您期望的顺序运行的原因是 union 试图强加唯一性,因此它会将所有这些行一起处理并按照引擎最方便的顺序将它们取出。

如果您按照 Parado 的建议切换到 UNION ALL (不尝试强加唯一性),它将不会进行处理,并且它们将按照您放置它们的顺序进入表中,几乎所有时间。然而,这并不是绝对的,并且在其他进程中发生的某些非常不寻常的情况(尤其是那些以某种方式触及您的 tempTable 的情况)可能会影响它。

如果您按照 Kash 的建议使用 order by,那么这将确定 id 的顺序(这很重要),但从技术上讲,插入行的顺序并不重要(这在实践中很少重要)。

在MSDN上有一个很好的总结。

所以,这需要注意为什么。至于如何得到你真正想要的东西,我会使用 Kash 的建议,即添加一个与 order by 子句一起使用的列,但我会使用 UNION ALL 而不是 UNION。使用 UNION 就像添加和隐含的“不同”需求,它会占用处理器周期并使查询计划更加复杂。

于 2012-09-10T21:48:30.147 回答
4

您的外部Select没有订单,因此 INSERT 没有像看起来那样有序。

SQL Server中有一些排序保证,并且带有 ORDER BY 的 SELECT 的 INSERT 保证计算所引用的标识值:

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

更改您的 SQL 以使其有序:

insert into myTable
select idRep,rep FROM
(
    select idRep, ISNULL(rep1,'') as rep, 1 as Grp FROM tempTable
    union
    select idRep, ISNULL(rep2,'') as rep, 2 as Grp FROM tempTable
    union
    select idRep, ISNULL(rep3,'') as rep, 3 as Grp FROM tempTable
    union
    select idRep, ISNULL(rep4,'') as rep, 4 as Grp FROM tempTable
    union
    select idRep, ISNULL(rep5,'') as rep, 5 as Grp FROM tempTable
) as t ORDER BY Grp
于 2012-09-10T21:29:00.193 回答
2

尝试使用union all. 它不对数据进行排序:

insert into myTable
select idRep,rep FROM
(
    select idRep, ISNULL(rep1,'') as rep FROM tempTable
    union all
    select idRep, ISNULL(rep2,'') as rep FROM tempTable
    union all
    select idRep, ISNULL(rep3,'') as rep FROM tempTable
    union all
    select idRep, ISNULL(rep4,'') as rep FROM tempTable
    union all
    select idRep, ISNULL(rep5,'') as rep FROM tempTable
) as t
于 2012-09-10T21:25:22.570 回答