axd*_*dna 1 sql-server csv bulk-insert
我有一个csv包含 350,000 行的文件。想要按照与csv文件中相同的顺序将数据插入到临时表中。我正在尝试BULK INSERT使用:
BULK INSERT ##AllRows
FROM @FilePath
WITH
(
FIELDTERMINATOR = '\n'
)
Run Code Online (Sandbox Code Playgroud)
不幸的是,BULK INSERT按随机顺序插入数据。我每次执行的标题都在不同的行中。我在 SQL Server 2016 上运行它。是否有可能在旧版本的 SQL Server 中顺序方式有所不同?
使用该FIRSTROW选项不会将标题识别为文件的第一行。文件没有任何我们可以订购的列。在文件中,标题始终位于第一行。
这可能是巧合,但即使如此FIRSTROW=2,我的标题也有可能出现在表格中。我查了一下。看起来csv文件包含的行数越多,插入到表中的机会就越随机。
按顺序读取文件中的行,并按相同顺序添加到表中。
当您从表中读取行时会出现此问题。ORDER BY如果上没有子句SELECT,SQL Server 可以按照任何方便的顺序从表中返回行。
该问题没有提供 table 的定义##AllRows,但似乎可以肯定该表是一个堆(没有聚集索引的表)。SQL Server 使用索引分配映射 (IAM) 结构从堆中读取页面。这意味着数据往往以每个 IAM 链内的文件和页面 ID 顺序返回,这通常不会反映数据插入的顺序。这是您所看到的行为的根本原因。
您需要一列来指示文件中行的顺序,然后在编写查询时按该列进行排序。不幸的是,SQL Server 不提供在导入期间添加此“序列”列的内置方法。
有几种常见的解决方法:
第二种方法存在一定风险,因为没有书面保证该方法在所有情况下都能可靠地工作。尽管如此,人们长期以来一直成功地使用这个想法。总体思路是:
IDENTITY向导入表添加一列。IDENTITY列。BULK INSERT进入视图。这不适用于全局临时表,因为视图无法引用该类型的表。您需要使用常规表(可能在tempdb中)。
我使用以下脚本成功导入包含莎士比亚全集的csv 文件:
第一步是在tempdb中创建一个带有额外IDENTITY列的表:
USE tempdb;
GO
CREATE TABLE dbo.Test
(
id integer IDENTITY PRIMARY KEY,
line nvarchar(4000) NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
现在我们在该表上创建一个视图,省略该IDENTITY列:
CREATE VIEW dbo.ImportTest
WITH SCHEMABINDING
AS
SELECT
T.line
FROM dbo.Test AS T;
Run Code Online (Sandbox Code Playgroud)
最后,我们批量插入到视图中:
BULK INSERT dbo.ImportTest
FROM 'C:\Temp\shakespeare.txt'
WITH
(
CODEPAGE = '65001',
DATAFILETYPE = 'char',
ROWTERMINATOR = '\n'
);
Run Code Online (Sandbox Code Playgroud)
SELECT我们现在可以使用with查看文件顺序的前几行ORDER BY:
SELECT TOP (20)
T.id,
T.line
FROM dbo.Test AS T
ORDER BY
T.id ASC;
Run Code Online (Sandbox Code Playgroud)
结果以正确的顺序显示文本:
也可以OPENROWSET与格式文件一起使用。使用相同的示例 csv 文件,我能够使用以下格式文件(另存为shakespeare.xml)导入数据:
USE tempdb;
GO
CREATE TABLE dbo.Test
(
id integer IDENTITY PRIMARY KEY,
line nvarchar(4000) NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
和:
INSERT dbo.Test
WITH (TABLOCK)
(
line
)
SELECT
ORO.line
FROM OPENROWSET
(
BULK 'C:\Temp\shakespeare.txt',
FORMATFILE = 'C:\Temp\shakespeare.xml',
CODEPAGE = '65001'
) AS ORO;
Run Code Online (Sandbox Code Playgroud)
请注意,此方法不需要视图,因此您可以定位全局临时表。目标表仍然需要额外的IDENTITY列。