【问题标题】:Import a file without identity key into table with identity key via bcp通过 bcp 将没有身份密钥的文件导入具有身份密钥的表中
【发布时间】:2020-03-03 16:09:50
【问题描述】:

我有一个包含 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

我得到了这些错误:

我不确定这些错误是否是因为我的表格设计中的身份 id 列而不是我的原始文本文件中的。因为当我从表中删除身份 ID 键时,bcp 工作正常。但我希望 bcp 在将文件导入表的过程中定义身份 ID。

示例文本文件:

任何帮助将不胜感激。

【问题讨论】:

  • 贴出R.txt的插入代码
  • @VigneshKumarA 你是指我的文本文件或 bcp 命令的示例记录吗?
  • @VigneshKumarA 我已经提供了 bcp 导入命令。

标签: sql-server bcp


【解决方案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)

【讨论】:

  • 您无法将数据加载到视图中。视图没有数据页。
  • 你可以insert data进入视图。
  • 它实际上对于让你的表格看起来像一个输入文件(删除列)非常有用,这样你就不需要摆弄 BCP 格式的文件了。这就是我总是在目标中获得身份的方式。
【解决方案2】:

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

第 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 语句,帮助您了解增量加载的 Update-Insert 脚本。

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 代替临时表,最后您可以在将完整数据移入目标表后截断源表。

【讨论】:

  • @vignesh kumar A 也提到了这一点,但我每个月都会收到这个文件,这是一次性解决方案。
  • 这里需要应用增量加载逻辑。在其中您必须使用多个表 table_bcp 和 table_ff(Flat File)
  • 能否详细说明增量加载逻辑?
  • 你好,这里需要创建一个Source和Destination表。每月文件将数据加载到源文件(此表将与文件结构相同)现在您需要编写合并脚本或 upsert(更新插入)脚本将数据从源表加载到目标表。跨度>
【解决方案3】:

问题是您试图不传递最后一列,这是一个 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 插入到您的真实表中。

我会一直

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

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

【讨论】:

  • 问题是我无法访问源文件并且无法编辑具有数百万行的文本文件。
  • @mpy 然后,请删除身份列并进行导入。导入成功后,请务必创建标识列
  • 但是我每个月都会收到这个文件,我想将它们添加到我的表中。如果我在没有身份的情况下将它们导入我的表并随后添加一个身份列 - 这需要几个小时 - 下个月,我必须删除表,再次导入所有文件并开始定义没有意义的身份列。
  • @mpy 按照第 1 步,您应该将向源数据添加一个 INT 列作为第一行,并让它像 IDENTITY 一样递增,并继续传递 -E 选项。这样做将允许将源中的数据用作 IDENTITY 列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2020-09-04
  • 1970-01-01
  • 2022-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多