在SELECT INTO中保留ORDER BY

dum*_*dad 19 t-sql sql-server sql-order-by select-into

我有一个tSQL查询,它从一个表中获取数据并将其复制到一个新表中,但只有满足特定条件的行:

SELECT VibeFGEvents.* 
INTO VibeFGEventsAfterStudyStart 
FROM VibeFGEvents
LEFT OUTER JOIN VibeFGEventsStudyStart
ON 
    CHARINDEX(REPLACE(REPLACE(REPLACE(logName, 'MyVibe ', ''), ' new laptop', ''), ' old laptop', ''), excelFilename) > 0
    AND VibeFGEventsStudyStart.MIN_TitleInstID <= VibeFGEvents.TitleInstID
    AND VibeFGEventsStudyStart.MIN_WinInstId <= VibeFGEvents.WndInstID
WHERE VibeFGEventsStudyStart.excelFilename IS NOT NULL
ORDER BY VibeFGEvents.id
Run Code Online (Sandbox Code Playgroud)

使用该表的代码依赖于它的顺序,上面的副本不保留我预期的顺序.也就是说,新表VibeFGEventsAfterStudyStart中的行在VibeFGEventsAfterStudyStart.id复制的列中不会单调增加VibeFGEvents.id.

在TSQL怎么可能我是从维护中行的排序VibeFGEventsVibeFGEventsStudyStart

小智 23

做什么的?

点是 - 表中的数据没有排序.在SQL Server中,表的固有存储顺序是(如果已定义)聚簇索引的存储顺序.

插入数据的顺序基本上是"无关紧要的".忘记数据写入表格的那一刻.

因此,即使你得到这些东西也没有任何收获.如果在处理数据时需要订单,则必须在获取它的选择上放置order by子句.任何其他内容都是随机的 - 即您的数据顺序未确定且可能会发生变化.

因此,当您尝试实现时,在插入上具有特定顺序是没有意义的.

SQL 101:集合没有订单.

  • “为了什么”对任何人都没有帮助。在很多情况下,我需要将数据保存到临时表中,以便我可以在几天后修复数据。它并不是作为永久存储,而是作为数据修复的临时解决方案。无论如何,下一个答案应该是投票。 (10认同)
  • 有时,默认情况下按特定顺序查看数据真是太好了。不需要,您是对的,但是有些人喜欢它。 (4认同)
  • 这不是答案,这是评论。令人失望的是它获得了 25 票。 (3认同)
  • 它是SQL中的核心概念 - 基于SQL设置.在实现一组(在选择中)时强加的顺序.除非在SELECT中定义订单; 结果是任意的,理论上可以在调用之间改变.数据在表中时,数据或插入的顺序将丢失.这不是"隐藏的自然"秩序.这是基于集合的操作的核心. (2认同)
  • 不,不保证。它可能会发生,可能不会。如果表1上的聚簇索引具有其他顺序,则该顺序可能会依次出现。如果由于where子句而存在另一个索引,则它以随机顺序出现,具体取决于sql Server如何决定搜索事物。在更复杂的查询中,您可能会使用不同的线程然后合并结果来发现并行性。不保证意味着您依赖可能会破坏的副作用。称为超级糟糕的编程。 (2认同)
  • 没有聚簇索引的表(如具有UUID主键的表)如何? (2认同)
  • 或者处理在其功能中使用主键序列的代码。 (2认同)
  • 让我困惑的是,当使用列存储时,插入顺序_确实_很重要...它允许行组省略和更快的查询...事实上,MS 为此目的而建议利用插入顺序:https:// docs.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-query-performance?view=sql-server-ver15#1-organize-data-to-eliminate-more-rowgroups-from-全表扫描 (2认同)
  • 我需要自动生成的主键与复制到表中的主键具有相同的顺序,以便我可以选择它们并知道它们映射到什么,以便进一步处理。所以你是有理由的。:-) (2认同)

Mic*_*ael 20

我知道这有点旧,但我需要做类似的事情.我想将一个表的内容插入到另一个表中,但是以随机顺序插入.我发现我可以通过使用select top n和来做到这一点order by newid().没有'top n',订单没有保留,第二个表的行与第一个表的顺序相同.然而,对于'top n',保留了顺序(在我的情况下是随机的).我使用的值'n'大于行数.所以我的查询是这样的:

insert Table2 (T2Col1, T2Col2)
  select top 10000 T1Col1, T1Col2
  from Table1
  order by newid()
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的实际回答 (13认同)

Gre*_*Gum 11

只需top在 sql 中添加一个大于实际行数的数字即可:

SELECT top 25000 * 
into spx_copy
  from SPX
  order by date
Run Code Online (Sandbox Code Playgroud)

  • 通过添加 TOP,我可以运行 SQL。但是,它们仍然被加载到目标表中,就好像“ORDER BY”不存在一样......我单独测试了该命令,并且作为选择它仍然可以正常工作,并对其进行排序。有任何想法吗? (2认同)
  • 我可以发誓它对我有用,但现在却不起作用了。添加身份列(“SELECT ..., _dummy = Identity(int) INTO ...”)为我解决了这个问题。 (2认同)

EzL*_*zLo 6

我发现了一个特定的场景,我们希望按照列内容中的特定顺序创建新表:

  • 行数非常大(从 200 到 2000 百万行),因此我们使用SELECT INTO而不是CREATE TABLE + INSERT因为需要尽可能快地加载(最少的日志记录)。我们已经测试使用跟踪标志 610加载已创建的具有聚集索引的空表,但仍然比以下方法花费更长的时间。
  • 我们需要按特定列对数据进行排序以提高查询性能,因此我们CLUSTERED INDEX在表加载后立即创建一个。我们放弃创建非聚集索引,因为它需要再次读取索引中未包含在有序列中的数据,并且我们放弃创建完全覆盖的非聚集索引,因为它实际上会使所需的空间量增加一倍保持桌子。

如果您设法以某种方式创建包含已“排序”的列的表,则创建聚集索引(具有相同的顺序)所需的时间比数据未排序时要少得多。有时(您必须测试您的情况),对 中的行进行排序SELECT INTO比不按顺序加载并稍后创建聚集索引要快。

问题是 SQL Server 2012+ORDER BY在执行INSERT INTO或 时会忽略列列表SELECT INTOORDER BY如果您在插入的表上指定IDENTITYSELECT INTO或插入的表具有列,它将考虑这些IDENTITY列,但只是为了确定标识值而不是基础表中的实际存储顺序。在这种情况下,排序可能会发生,但不能保证,因为它高度依赖于执行计划。

我们发现的一个技巧是,如果您有一个列表,则SELECT INTO对 a 的结果执行UNION ALLa 会使引擎执行 a SORT(并不总是显式SORT运算符,有时是 aMERGE JOIN CONCATENATION等)ORDER BY。这样,select into 就已经按照我们稍后创建聚集索引的顺序创建了新表,因此创建索引所需的时间更少。

所以你可以重写这个查询:

SELECT
    FirstColumn = T.FirstColumn,
    SecondColumn = T.SecondColumn
INTO
    #NewTable
FROM
    VeryBigTable AS T
ORDER BY            -- ORDER BY is ignored!
    FirstColumn,
    SecondColumn
Run Code Online (Sandbox Code Playgroud)

SELECT
    FirstColumn = T.FirstColumn,
    SecondColumn = T.SecondColumn
INTO
    #NewTable
FROM
    VeryBigTable AS T

UNION ALL

-- A "fake" row to be deleted
SELECT
    FirstColumn = 0,
    SecondColumn = 0

ORDER BY
    FirstColumn,
    SecondColumn
Run Code Online (Sandbox Code Playgroud)

我们已经使用过这个技巧几次了,但我不能保证它总是能排序。我只是将其发布为一种可能的解决方法,以防有人遇到类似的情况。