通过bcp将没有身份密钥的文件导入具有身份密钥的表

时间:2019-11-07 05:44:43

标签: sql-server bcp

我有一个6列2亿行的文本文件,它们都不是唯一的。我想将它们导入SQL Server中的表中,并希望将Identity列定义为主键。

因此,我首先创建了下表:

CREATE TABLE dbo.Inventory 
(
    ProductID NUMERIC(18,3) NOT NULL,
    RegionID NUMERIC(18,3) NULL,
    ShopCode INT NULL,
    QTY FLOAT NULL,
    OLAPDate VARCHAR(6) NULL,
    R Float NULL,

    ID BIGINT NOT NULL PRIMARY KEY IDENTITY(1,1)
)

然后我使用以下命令将文本文件导入到表中:

bcp ETLDB.dbo.Inventory in D:\SCM\R.txt -T -b 10000 -t "," -c -e D:\SCM\Errors.txt

我得到了这些错误:

errors

我不确定错误是否是由于我的表设计中而不是原始文本文件中的标识id列引起的。因为当我从表中删除身份ID密钥时,bcp可以正常工作。但是我希望bcp在将文件导入表的过程中定义身份ID。

示例文本文件:

text file

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

对于类似情况,我尝试了一种解决方法。

步骤1: 用您的CSV / TXT文件可用的列创建一个表。

步骤2: 使用BCP脚本推送数据。

bcp dbo.<tablename> in <file location in local folder> -S <server_name> -d <database_name> -U <username> -P <password> -b 20000 -q -c -t"<column delimiter>"

第3步: 一旦数据在目标表上可用,您现在可以使用以下SQL命令更改表:

ALTER TABLE <Table Name>
ADD <Identity Column> BIGINT IDENTITY(1,1)

添加少量SQL语句以帮助您了解增量负载的更新插入脚本。

CREATE TABLE Employees
(
    ID INT IDENTITY(1,1),
    Name VARCHAR(100),
    Salary INT,
    InsertDate DATETIME,
    UpdateDate DATETIME
)

INSERT INTO Employees
VALUES
('Kristeen',1420,NULL,NULL)
,('Ashley',2006,NULL,NULL)
,('Julia',2210,NULL,NULL)
,('Maria',3000,NULL,NULL)

CREATE PROCEDURE dbo.InsertOrUpdateEmployee
    @Name VARCHAR(100),
    @Salary INT
AS BEGIN

    CREATE TABLE #tmpData
    (
        Name VARCHAR(50),
        Salary INT
    )   

    INSERT INTO #tmpData(Name,Salary)

    VALUES(
        @Name,
        @Salary 
    )


    UPDATE A
    SET A.Name = B.Name,
        A.Salary = B.Salary,
        A.updatedate = GETDATE(),
        A.IsNewRecord = 0
    FROM Employees A
    JOIN #tmpData B
    ON A.Name = B.Name
    AND A.Salary = B.Salary

    INSERT INTO Employees
    (
        Name,
        Salary,
        InsertDate,
        IsNewRecord
    )
    SELECT 
        S.Name,
        S.Salary,
        GETDATE(),
        1
    FROM #tmpData S
    LEFT JOIN Employees D
    ON S.Name = D.Name
    AND S.Salary = D.Salary
    WHERE D.Name IS NULL
    AND D.Salary IS NULL

    DROP TABLE #tmpData

END

EXEC InsertOrUpdateEmployee 'Gaurav',4500000

您需要对上面的代码进行一些修改,因为上面的代码是通过SP参数插入数据,但是在这种情况下,您可能需要使用Source Table代替临时表,最后您需要将完整的数据移到目标表后,可以截断源表。

答案 1 :(得分:1)

创建一个看起来像要加载到其中的视图,并加载到该视图中

CREATE VIEW dbo.Inventory_Stage
AS SELECT 
    ProductID,
    RegionID,
    ShopCode,
    QTY,
    OLAPDate,
    R Float
FROM Inventory

现在加载到Inventory_Stage而不是Inventory

还要使用-F从第二行开始加载,因为第一行具有列名

bcp ETLDB.dbo.Inventory_Stage in -F 1 D:\SCM\R.txt -T -b 10000 -t "," -c -e D:\SCM\Errors.txt

此外,请认真考虑是否要使用float。对于您的示例数据,我推荐NUMERIC(19,6)

答案 2 :(得分:0)

问题是您尝试不传递最后一列,即INT列。

  

“-E指定导入的数据文件中的一个或多个标识值   用于标识列。如果未给出-E,则   导入的数据文件中此列的标识值是   被忽略。”

您有三个选择...

  1. 将INT列作为第一行添加到源数据,并使其增加,就像IDENTITY将增加一样,并继续传递-E选项。这样做可以将源中的数据用作IDENTITY列。

  2. 向源数据的最后一列添加一个随机INT,每行说1,然后请勿传递-E。根据文档,如果未提供-E,它将忽略身份列的值,并从当前的种子值开始并自动递增。

  3. 利用格式文件来指定数据文件中的哪些列进入SQL表中的哪些列。

How to specify the format file

How to construct a format file

更新后的答案

当您没有选择修改源数据的选项时,请删除标识列并执行以下操作:   -从表格中删除身份列   -导入   -导入成功后,请添加以下身份列:

Alter Table Names
Add Id_new BigInt Identity(1, 1)
Go

正如Marc_s提到的here

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

我会一直

    从CSV文件
  1. 插入登台dbo.Employee_Staging(无IDENTITY列)
  2. 可能会编辑/清理/处理您导入的数据
  3. ,然后使用如下T-SQL语句将数据复制到真实表中:

    INSERT INTO dbo.Employee(Name, Address) 
       SELECT Name, Address
       FROM dbo.Employee_Staging