Импортировать файл без идентификационного ключа в таблицу с идентификационным ключом через bcp - PullRequest
1 голос
/ 07 ноября 2019

У меня есть текстовый файл с 6 столбцами и 200 миллионами строк, и ни одна из них не является уникальной. Я хотел бы импортировать их в таблицу в 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

Яне уверен, что ошибки из-за столбца идентификатора, который находится в моем дизайне таблицы, а не в исходном текстовом файле или нетПотому что, когда я удаляю ключ идентификатора из таблицы, BCP работает нормально. Но я хочу, чтобы bcp определял идентификатор в процессе импорта моего файла в таблицу.

Пример текстового файла:

text file

Любая помощь будет оценена.

Ответы [ 3 ]

1 голос
/ 07 ноября 2019

Существует обходной путь, который я пробовал для аналогичного случая.

Шаг 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, но в вашем случае вам может понадобиться использовать исходную таблицу вместо временной таблицы, и в конце вы можете обрезать исходную таблицу после перемещениязаполните данные в таблице назначения.

1 голос
/ 07 ноября 2019

Создайте представление, похожее на то, что вы хотите загрузить, и загрузите в него

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)

0 голосов
/ 07 ноября 2019

Проблема в том, что вы пытаетесь не передавать последний столбец, который является столбцом INT.

"- E Указывает, что значение или значения идентификатора в импортированном файле данных должны использоваться длястолбец идентификаторов. Если -E не задано, значения идентификаторов для этого столбца в импортируемом файле данных игнорируются. "

У вас есть три варианта ...

  1. Добавьте столбец INT к исходным данным в качестве первой строки и увеличьте его, как IDENTITY, будет увеличиваться и продолжать передавать параметр -E. Это позволит использовать данные из источника в качестве столбца IDENTITY.

  2. Добавьте случайный INT к последнему столбцу ваших исходных данных, скажем 1 для каждой строки, затем не передавать в -E. Согласно документации, когда -E не указан, он будет игнорировать значения для столбца идентификаторов и начинаться с текущего значения и автоматического увеличения.

  3. Использование файла формата для указаниякакие столбцы из вашего файла данных идут в какие столбцы в нашей таблице SQL.

Как указать формат файла

Каксоздать файл формата

Обновленный ответ

Если у вас нет возможности изменить исходные данные, удалите столбцы идентификаторов и выполните следующие действия. : - Удалить столбец идентификаторов из таблицы - Выполните импорт - После успешного импорта добавьте столбец идентификаторов, как показано ниже:

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

Как отметил Marc_ здесь

НЕ ДОПУСКАЙТЕ ВСТАВКИ в ваши настоящие таблицы напрямую.

Я бы всегда

  1. вставлял в постановочную таблицу dbo.Employee_Staging(без столбца IDENTITY) из файла CSV
  2. poРедактировать / очищать / манипулировать импортированными данными
  3. , а затем копировать данные в реальную таблицу с помощью оператора T-SQL, например:

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