78

我正在尝试从 CSV 文件在数据库中添加批量数据。

Employee 表有一个ID自动递增的列 (PK)。

CREATE TABLE [dbo].[Employee](
 [id] [int] IDENTITY(1,1) NOT NULL,
 [Name] [varchar](50) NULL,
 [Address] [varchar](50) NULL
) ON [PRIMARY]

我正在使用这个查询:

BULK INSERT Employee  FROM 'path\tempFile.csv ' 
WITH (FIRSTROW = 2,KEEPIDENTITY,FIELDTERMINATOR = ',' , ROWTERMINATOR = '\n');

.CSV 文件 -

Name,Address
name1,addr test 1
name2,addr test 2

但它会导致此错误消息:

第 2 行第 1 列 (id) 的批量加载数据转换错误(指定代码页的类型不匹配或无效字符)。

4

9 回答 9

106

在 csv 文件中添加一个 id 列并将其留空:

id,Name,Address
,name1,addr test 1
,name2,addr test 2

从查询中删除 KEEPIDENTITY 关键字:

BULK INSERT Employee  FROM 'path\tempFile.csv ' 
WITH (FIRSTROW = 2,FIELDTERMINATOR = ',' , ROWTERMINATOR = '\n');

id 身份字段将自动递增。

如果您将值分配给 csv 中的 id 字段,除非您使用 KEEPIDENTITY 关键字,否则它们将被忽略,然后将使用它们而不是自动增量。

于 2012-09-12T20:22:15.820 回答
55

不要直接将 BULK INSERT 插入到您的真实表中。

我会永远

  1. 从 CSV 文件插入临时dbo.Employee_Staging(不带列)IDENTITY
  2. 可能编辑/清理/操作您导入的数据
  3. 然后使用以下 T-SQL 语句将数据复制到真实表中:

    INSERT INTO dbo.Employee(Name, Address) 
       SELECT Name, Address
       FROM dbo.Employee_Staging
    
于 2012-06-01T13:24:02.357 回答
38

我遇到了类似的问题,但我需要确保 ID 的顺序与源文件中的顺序一致。我的解决方案是为 BULK INSERT 使用 VIEW:

保持表原样并创建此视图(选择除 ID 列之外的所有内容)

CREATE VIEW [dbo].[VW_Employee]
AS
SELECT [Name], [Address]
FROM [dbo].[Employee];

您的 BULK INSERT 应如下所示:

BULK INSERT [dbo].[VW_Employee] FROM 'path\tempFile.csv ' 
WITH (FIRSTROW = 2,FIELDTERMINATOR = ',' , ROWTERMINATOR = '\n');
于 2014-04-25T13:51:06.503 回答
9

您必须使用格式文件进行批量插入:

   BULK INSERT Employee FROM 'path\tempFile.csv ' 
   WITH (FORMATFILE = 'path\tempFile.fmt');

其中格式文件 (tempFile.fmt) 如下所示:

11.0
2
1 SQLCHAR 0 50 "\t" 2 名称 SQL_Latin1_General_CP1_CI_AS
2 SQLCHAR 0 50 "\r\n" 3 地址 SQL_Latin1_General_CP1_CI_AS

更多细节在这里 - http://msdn.microsoft.com/en-us/library/ms179250.aspx

于 2014-07-27T07:32:10.977 回答
2

我的解决方案是将 ID 字段添加为表中的 LAST 字段,因此批量插入会忽略它并获取自动值。干净简单...

例如,如果插入临时表:

CREATE TABLE #TempTable 
(field1 varchar(max), field2 varchar(max), ... 
ROW_ID int IDENTITY(1,1) NOT NULL)

请注意,该ROW_ID字段必须始终指定为 LAST 字段!

于 2016-04-04T10:16:02.807 回答
2
  1. 创建一个包含标识列 + 其他列的表;
  2. 在其上创建一个视图并仅公开您将批量插入的列;
  3. 视图中的 BCP
于 2018-10-16T15:37:01.090 回答
1

我遇到了同样的问题,导致损失数小时,所以我很受鼓舞地分享我的发现和对我有用的解决方案。

1.使用excel文件

这是我采用的方法。我没有使用 csv 文件,而是使用了一个包含如下内容的 excel 文件 (.xlsx)。

id  username   email                token website

    johndoe   johndoe@divostar.com        divostar.com
    bobstone  bobstone@divosays.com        divosays.com

请注意,id 列没有值。

接下来,使用 Microsoft SQL Server Management Studio 连接到您的数据库并右键单击您的数据库并选择导入数据(任务下的子菜单)。选择 Microsoft Excel 作为源。当您到达名为“选择源表和视图”的阶段时,单击编辑映射。对于id目标下的列,单击它并选择忽略Enable Identity insert除非您想在从另一个数据库导入数据并希望维护源数据库的自动增量 id 的情况下保留 id,否则不要检查。继续完成,就是这样。您的数据将顺利导入。

2. 使用 CSV 文件

在您的 csv 文件中,确保您的数据如下所示。

id,username,email,token,website
,johndoe,johndoe@divostar.com,,divostar.com
,bobstone,bobstone@divosays.com,,divosays.com

运行以下查询:

BULK INSERT Metrics FROM 'D:\Data Management\Data\CSV2\Production Data 2004 - 2016.csv '
WITH (FIRSTROW = 2, FIELDTERMINATOR = ',', ROWTERMINATOR = '\n');

这种方法的问题是 CSV 应该在数据库服务器或数据库可以访问的某个共享文件夹中,否则您可能会收到类似“无法打开文件。操作系统返回错误代码 21(设备未准备好)”。

如果您要连接到远程数据库,则可以将 CSV 上传到该服务器上的目录并引用批量插入的路径。

3. 使用 CSV 文件和 Microsoft SQL Server Management Studio 导入选项

像第一种方法一样启动您的导入数据。对于源,选择平面文件源并浏览您的 CSV 文件。确保正确的菜单(常规、列、高级、预览)正常。确保在列菜单(列分隔符)下设置正确的分隔符。就像上面的 excel 方法一样,单击edit mappings。对于目标下的 id 列,单击它并选择忽略

继续完成,就是这样。您的数据将顺利导入。

于 2016-11-18T13:35:01.863 回答
1

这是一个非常古老的帖子,但是给出的答案都没有在不改变提出条件的情况下解决问题,这是我做不到的。

我通过使用 BULK INSERT 的 OPENROWSET 变体解决了这个问题。这使用相同的格式文件并以相同的方式工作,但它允许使用 SELECT 语句读取数据文件。

创建你的表:

CREATE TABLE target_table(
id bigint IDENTITY(1,1),
col1 varchar(256) NULL,
col2 varchar(256) NULL,
col3 varchar(256) NULL)

打开命令窗口运行:

bcp dbname.dbo.target_table format nul -c -x -f C:\format_file.xml -t; -T

这会根据表格的外观创建格式文件。

现在编辑格式文件并删除 FIELD ID="1" 和 COLUMN SOURCE="1" 的整个行,因为这在我们的数据文件中不存在。
还可以根据数据文件的需要调整终止符:

<?xml version="1.0"?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <RECORD>
  <FIELD ID="2" xsi:type="CharTerm" TERMINATOR=";" MAX_LENGTH="256" COLLATION="Finnish_Swedish_CI_AS"/>
  <FIELD ID="3" xsi:type="CharTerm" TERMINATOR=";" MAX_LENGTH="256" COLLATION="Finnish_Swedish_CI_AS"/>
  <FIELD ID="4" xsi:type="CharTerm" TERMINATOR="\r\n" MAX_LENGTH="256" COLLATION="Finnish_Swedish_CI_AS"/>
 </RECORD>
 <ROW>
  <COLUMN SOURCE="2" NAME="col1" xsi:type="SQLVARYCHAR"/>
  <COLUMN SOURCE="3" NAME="col2" xsi:type="SQLVARYCHAR"/>
  <COLUMN SOURCE="4" NAME="col3" xsi:type="SQLVARYCHAR"/>
 </ROW>
</BCPFORMAT>

现在我们可以使用 select 将数据文件批量加载到我们的表中,从而完全控制列,在这种情况下,通过不将数据插入标识列:

INSERT INTO target_table (col1,col2, col3)
SELECT * FROM  openrowset(
bulk 'C:\data_file.txt',
formatfile='C:\format_file.xml') as t;
于 2019-02-05T17:45:23.293 回答
0

另一种选择是,如果您使用临时表而不是临时表,则可以按照导入的预期创建临时表,然后在导入后添加标识列。

所以你的 sql 做这样的事情:

  1. 如果临时表存在,则删除
  2. 创建临时表
  3. 批量导入临时表
  4. 更改临时表添加身份
  5. <你想对数据做什么>
  6. 删除临时表

仍然不是很干净,但它是另一种选择......可能也必须获得锁以确保安全。

于 2015-11-17T11:54:51.167 回答