【问题标题】:How can I keep the order of column values in a union select?如何在联合选择中保持列值的顺序?
【发布时间】:2018-12-11 20:02:55
【问题描述】:

我正在使用SELECTUNION 对表进行批量插入。我需要在调用INSERT 时保持SELECT 值的顺序不变,但似乎这些值是按升序插入的,而不是我指定的顺序。

例如下面的插入语句

declare @QuestionOptionMapping table
(
    [ID] [int] IDENTITY(1,1)
  , [QuestionOptionID] int
  , [RateCode] varchar(50)
)

insert into @QuestionOptionMapping (
    RateCode
)
select
   'PD0116'
union
select
  'PL0090'
union
select
  'PL0091'
union
select
  'DD0026'
union
select
  'DD0025'

SELECT * FROM @QuestionOptionMapping

将数据呈现为

(5 row(s) affected)
ID          QuestionOptionID RateCode
----------- ---------------- --------------------------------------------------
1           NULL             DD0025
2           NULL             DD0026
3           NULL             PD0116
4           NULL             PL0090
5           NULL             PL0091

(5 row(s) affected)

插入数据的select如何返回和插入时一样的顺序?

【问题讨论】:

  • 回答为什么它最终被排序:UNION 删除重复项,因此通常会沿途对数据进行排序。您可以使用UNION ALL 来避免这种情况。

标签: sql-server tsql


【解决方案1】:

SQL Server 将您的行存储为无序集。数据点可能是连续的,也可能不是连续的,它们可能与插入语句中指定的数据“顺序”一致,也可能不同。

当您查询数据时,引擎将按照优化器确定的最有效顺序检索行。不能保证每次查询数据时顺序都相同。

保证结果集顺序的唯一方法是在 SELECT 语句中包含显式 ORDER BY 子句。

请参阅此答案以更深入地讨论为什么会这样。 Default row order in SELECT query - SQL Server 2008 vs SQL 2012

通过在 INSERT 语句中使用 SELECT/UNION 选项,您正在创建一个无序集,SQL Server 将其作为一个集合而不是一系列输入来获取。如果需要按顺序应用 IDENTITY 值,请将插入内容分隔到离散语句中。更好的是,如果行号很重要,请不要碰运气。对插入的行显式编号。

【讨论】:

  • 好吧,至少现在我明白为什么 UNION 会导致这个问题。好书,谢谢
【解决方案2】:

如果您不是从表格中选择?
然后您可以插入 VALUES,而不是使用联合进行选择。

insert into @QuestionOptionMapping (RateCode) values
 ('PD0116')
,('PL0090')
,('PL0091')
,('DD0026')
,('DD0025')

或者在您的查询中,将所有 UNION 更改为 UNION ALL。

UNION 和 UNION ALL 之间的区别在于 UNION 将删除重复的行。 而 UNION ALL 只是将选择的结果集拼接在一起。
UNION 要找到这些重复项,首先必须在内部对它们进行排序。
但是 UNION ALL 并不关心唯一性,所以它不需要排序。

第三种选择是简单地从 1 个插入语句更改为多个插入语句。 每个值插入一个。从而完全避免 UNION。
但是那个反高尔夫编码的方法也是最罗嗦的。

【讨论】:

  • 将 UNION 更改为 UNION ALL 是一个足够快的修复。谢谢
【解决方案3】:

您的问题是您没有按照您认为的顺序放置它们。 UNION 只是不同的值,它通常会对值进行排序以促进不同的值。单独运行select语句就可以看到了。

如果您使用values 插入,则保留顺序:

insert into @QuestionOptionMapping (RateCode) values
('PD0116'), ('PL0090'), ('PL0091'), ('DD0026'), ('DD0025')

select * from @QuestionOptionMapping order by ID

【讨论】:

    【解决方案4】:

    SQL 表确实代表无序集。但是,insert 上的 identity 列将遵循 order by 的顺序。

    由于union 中的重复消除,您的数据出现故障。但是,我建议编写查询以明确对数据进行排序:

    insert into @QuestionOptionMapping (RateCode)
        select ratecode
        from (values (1, 'PD0116'), 
                     (2, 'PL0090'),
                     (3, 'PL0091'),
                     (4, 'DD0026'),
                     (5, 'DD0025')
             ) v(ord, ratecode)
        order by ord;
    

    那么请务必使用order by 进行选择:

    select qom.*
    from @QuestionOptionMapping qom
    order by id;
    

    请注意,这也使用了values() 表构造函数,这是一种非常方便的语法。

    【讨论】:

    • 您可能想要解决SET IDENTITY_INSERT 问题。
    猜你喜欢
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-23
    • 2015-05-23
    • 2022-12-24
    相关资源
    最近更新 更多