我有一个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
使用该表的代码依赖于它的顺序,上面的副本不保留我预期的顺序。即新表VibeFGEventsAfterStudyStart
中的行在VibeFGEventsAfterStudyStart.id
复制的VibeFGEvents.id
列中不会单调增加。
在tSQL中,如何保留VibeFGEvents
中VibeFGEventsStudyStart
行的排序?
答案 0 :(得分:24)
为什么?
点是 - 表中的数据未订购。在SQL Server中,表的固有存储顺序是(如果已定义)聚簇索引。
插入数据的顺序基本上是“无关紧要的”。忘记数据写入表格的那一刻。
因此,即使你得到这些东西也没有任何好处。如果在处理数据时需要订单,则必须在获取它的选择上放置order by子句。其他任何东西都是随机的 - 即您的数据顺序未确定且可能会发生变化。
因此,在尝试实现插件时,在插件上设置特定顺序是没有意义的。
SQL 101:集合没有订单。
答案 1 :(得分:18)
我知道这有点旧,但我需要做类似的事情。我想将一个表的内容插入到另一个表中,但是以随机顺序插入。我发现我可以使用select top n
和order by newid()
来完成此操作。没有&#39; top n&#39;,订单未被保留,第二个表的行与第一个表的顺序相同。但是,使用&#39; top n&#39;,保留了订单(在我的情况下是随机的)。我使用了&#39; n&#39;这大于行数。所以我的查询是:
insert Table2 (T2Col1, T2Col2)
select top 10000 T1Col1, T1Col2
from Table1
order by newid()
答案 2 :(得分:0)
您不能使用ORDER BY进行此操作,但是如果在SELECT INTO之后在VibeFGEvents.id上创建聚簇索引,则该表将通过VibeFGEvents.id在磁盘上进行排序。
答案 3 :(得分:0)
之所以希望这个(特定的顺序)是因为您不能在子查询中定义顺序,因此,想法是,如果创建一个表变量,然后从该表变量中进行查询,会认为您会保留顺序(例如,连接必须按顺序排列的行(例如,对于XML或json)),但您不能这样做。 所以你会怎么做? 答案是通过选择中使用TOP来强制SQL对其进行排序(只需选择一个足以覆盖所有行的数字)。
答案 4 :(得分:0)
我发现了一种特定的情况,我们希望按列内容中的特定顺序创建新表:
SELECT INTO
而不是CREATE TABLE + INSERT
,因为需要尽快加载(最小记录)。我们已经测试过使用trace flag 610加载具有聚簇索引的已经创建的空表,但是仍然比以下方法花费更长的时间。CLUSTERED INDEX
。我们舍弃了创建非聚集索引的原因,因为它需要再次读取索引中不包含在有序列中的数据,而舍弃了创建完全覆盖的非聚集索引,因为这实际上会使所需的空间量增加一倍住桌子。碰巧的是,如果您设法以某种方式创建具有已“排序”的列的表,则创建聚簇索引(具有相同的顺序)所需的时间要比不包含数据的时间少很多。下令。有时(您必须测试一下情况),对SELECT INTO
中的行进行排序要比不按顺序加载和稍后创建聚簇索引快。
问题在于,SQL Server 2012+在执行ORDER BY
或执行INSERT INTO
时将忽略SELECT INTO
列列表。如果您在ORDER BY
上指定了IDENTITY
列,或者插入的表中有SELECT INTO
列,即 ,它将考虑IDENTITY
列。确定标识值 ,而不是确定基础表中的实际存储顺序。在这种情况下,排序很可能会发生,但不能保证,因为它高度依赖于执行计划。
我们发现的一个技巧是,对SELECT INTO
的结果执行UNION ALL
会使引擎执行SORT
(有时并不总是显式SORT
运算符MERGE 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
到
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
我们已经使用过几次这个技巧,但是我不能保证它总是会排序。我只是将其发布为可能的解决方法,以防有人遇到类似情况。
答案 5 :(得分:0)
我遇到了同样的问题,需要保留订单的原因之一是当我尝试使用ROLLUP来基于原始数据而不是该列中的平均值来获得加权平均值时。例如,假设我想根据四个商店位置所售出的商品数量来查看平均利润?通过创建方程式Profit / #Units = Avg,我可以很容易地做到这一点。现在,我在GROUP BY中加入了ROLLUP,这样我也可以看到所有位置的平均值。现在,我对自己想:“这是个很好的信息,但我希望按最佳平均水平(更差)的顺序查看它,并将“总体”保持在列表的底部(或顶部))。 ROLLUP将使您无法做到这一点,因此您可以采用其他方法。
为什么不根据需要保留的顺序(顺序)创建行号?
SELECT OrderBy = ROW_NUMBER() OVER(PARTITION BY 'field you want to count' ORDER BY 'field(s) you want to use ORDER BY')
, VibeFGEvents.*
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
现在,您可以使用表中的OrderBy字段来设置值的顺序。我从上面的查询中删除了ORDER BY语句,因为它不影响数据如何加载到表中。
答案 6 :(得分:0)
只需将awk ' ##Starting awk program from here.
{
for(i=1;i<=NF;i++){ ##Starting for loop here to loop through each field of currnet line.
if($i~/^\*/){ ##Checking condition if line starts from * then do following.
sub(/^\*/,"",$i) ##Substituting starting * with NULL in current field.
print $i ##Printing current field value here.
}
}
}
' Input_file ##Mentioning Input_file name here.
添加到您的sql中,其数字应大于实际的行数:
top
答案 7 :(得分:-1)
尝试使用INSERT INTO
代替SELECT INTO
INSERT INTO VibeFGEventsAfterStudyStart
SELECT VibeFGEvents.*
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`
答案 8 :(得分:-1)
我在MS SQL 2012上进行了测试,它清楚地向我展示了,将...插入...选择...的顺序是有道理的。这是我所做的:
create table tmp1 (id int not null identity, name sysname);
create table tmp2 (id int not null identity, name sysname);
insert into tmp1 (name) values ('Apple');
insert into tmp1 (name) values ('Carrot');
insert into tmp1 (name) values ('Pineapple');
insert into tmp1 (name) values ('Orange');
insert into tmp1 (name) values ('Kiwi');
insert into tmp1 (name) values ('Ananas');
insert into tmp1 (name) values ('Banana');
insert into tmp1 (name) values ('Blackberry');
select * from tmp1 order by id;
我得到了这个清单:
这里没有惊喜。然后我以这种方式从tmp1复制到tmp2:
insert into tmp2 (name)
select name
from tmp1
order by id;
select * from tmp2 order by id;
我得到了和以前一样的确切答复。苹果到黑莓。 现在按相反的顺序进行测试:
delete from tmp2;
insert into tmp2 (name)
select name
from tmp1
order by id desc;
select * from tmp2 order by id;
因此,tmp2中的顺序也被颠倒了,因此排序依据在目标表中存在标识列时才有意义!