BULK INSERT із стовпцем ідентифікації (автоматичне збільшення)


74

Я намагаюся додати масивні дані до бази даних із файлу CSV.

У таблиці співробітників є стовпець 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 (ідентифікатор).


Чи можете ви розмістити свої зразки даних, наявні у файлі csv
praveen

1
Я шукав цю KEEPIDENTITYріч ... дякую!
nrod

1
Насправді для цього існує дуже просте рішення. Створіть подання, опустивши лише стовпець ідентифікатора, а потім зробіть групову вставку у подання.
Чарльз Окваугу

Відповіді:


50

Не вводьте групово ВСТУП у свої реальні таблиці безпосередньо.

Я б завжди

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

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

1
ідея хороша, але чи є якась конкретна причина того, чому ви використовуєте інсценізаційну таблицю?
Абхі

7
@Abhi: Я можу (1) видалити стовпець IDENTITY, що викликає горе, та (2) Я можу переглянути дані, можливо, видалити певні рядки, оновити деякі рядки, перш ніж фактично імпортувати їх у реальну таблицю.
marc_s

11
@marc_s Хоча це хороша порада, це не дає відповіді на питання. jwerts дійсно повинні приймати найкращу відповідь.
mawburn

Хороша загальна порада. Але навіть якщо у вас є індексна таблиця, що ви робите, якщо хочете записати номер рядка із вхідного файлу?
Розчарований

> Не вводьте групово ВСТУП у свої реальні таблиці безпосередньо. - Ця порада справедлива лише для БД MSSQL, таких обмежень немає, наприклад, у Postgres
ARA1307

101

Додайте стовпець ідентифікатора у файл csv та залиште його порожнім:

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, вони будуть проігноровані, якщо ви не використовуєте ключове слово KEEPIDENTITY, тоді вони будуть використовуватися замість автоматичного збільшення.


Навіть з індексною таблицею, якщо ви хочете записати номер рядка із вхідного файлу, вам знадобиться щось подібне. Мені це подобається!
Розчарований

Привіт @Josh Werts. Поки що ваше рішення стало для мене благом. Це працює на моїй локальній БД. Тепер, коли я підключаюся до віддаленої БД за допомогою Microsoft SQL Server Management studio і запускаю команду, я отримую повідомлення про помилку "Не вдається завантажити масово, оскільки файл" D: \ data.csv "не вдалося відкрити. Код помилки операційної системи 21 ( Пристрій не готовий). Має бути файл csv на тому самому сервері, де є БД. Файл csv знаходиться на моєму комп’ютері
Фоква Бест

1
@FokwaBest - Я думаю, віддалений сервер не має поняття вашого диска D:. Я думаю, вам потрібно буде створити спільну папку, до якої має доступ віддалений сервер, а потім посилатися на неї таким чином .... щось на зразок \\ myshare \ data.csv. Я тут не фахівець і справді мало працюю на сервері sql, тому, можливо, хтось інший може відповісти, якщо це не спрацює.
Джош Вертс

рішення хороше, але що, якщо ви не можете оновити файли csv. що, якщо є умова, що вам потрібно завантажити файл і завантажити його в db, що нам робити в такому випадку?
Садія

32

У мене була подібна проблема, але мені потрібно було бути впевненим, що порядок ідентифікатора відповідає порядку у вихідному файлі. У моєму рішенні використовується ВИД для БАЛКОВОГО ВСТАВКИ:

Зберігайте таблицю такою, якою вона є, і створіть цей ПЕРЕГЛЯД (виберіть все, крім стовпця ІД)

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');

2
Це, безумовно, найкраще рішення цього питання
DhruvJoshi

Я згоден, що це спосіб зробити це.
Дерек Хаккет,

2
Найпростіший і найпростіший спосіб запустити групову вставку в проміжну таблицю, яка не відповідає вихідному файлу. Однак я щойно сьогодні виявив, що, мабуть, немає гарантії, що дані будуть вставлені в порядку файлу. Що є вбивцею для імпорту файлів заголовків / деталей мейнфрейма
Nick.McDermaid

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


Це повинно працювати, читаючи документацію, пропуск стовпців охоплюється, але не пропускаючи стовпці PK спеціально не охоплюється. На практиці я мав змогу зробити це без помилок: Повідомлення 4866, рівень 16, стан 7, рядок 6 Не вдалося виконати основне навантаження. Стовпець задовгий у файлі даних для рядка 1, стовпець 1. Переконайтеся, що термінатор поля та термінатор рядка вказані правильно. Повідомлення 7301, рівень 16, стан 2, рядок 6 Не вдається отримати необхідний інтерфейс ("IID_IColumnsInfo") від постачальника OLE DB "BULK" для пов'язаного сервера "(null)".
sboggs11

2

Моє рішення полягає в тому, щоб додати поле ідентифікатора як ПОСЛІДНЕ поле в таблиці, таким чином групове вставлення ігнорує його, і воно отримує автоматичні значення. Чисто і просто ...

Наприклад, якщо вставляти до тимчасової таблиці:

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

Зверніть увагу, що ROW_IDполе ПОВИННО завжди вказуватися як ПОСЛЕДНЕ!


Це може спрацювати в деяких ситуаціях, але коли я спробував це, це просто дало мені порожню таблицю.
Bryce Wagner,

схоже, не працює в 2008R2. Я отримую таку ж помилку, як OP, виконуючи групову вставку на 4 стовпці, з 4 стовпцями у моєму файлі даних, з 5 стовпцем ідентифікатора в цільовій таблиці. У файлі error.txt я отримую, Row 2 File Offset 528 ErrorFile Offset 0 - HRESULT 0x80020005а в моєму stderr:msgtext = 'Bulk load data conversion error (type mismatch or invalid character for the specified codepage) for row 2, column 5 (QMid).'
mpag

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

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

Запустіть дані імпорту, як у першому підході. Для джерела виберіть Flat Source Source та перегляньте файл CSV. Переконайтеся, що право меню (Загальне, Стовпці, Додатково, Попередній перегляд) справне. Обов’язково встановіть правильний роздільник у меню стовпців (Розділювач стовпців). Так само, як у підході до Excel вище, натисніть редагувати відображення . Для стовпця ідентифікатора в пункті призначення натисніть на нього та виберіть ігнорувати .

Продовжуйте до кінця, і все. Ваші дані будуть імпортовані плавно.


1
  1. Створити таблицю зі стовпцем Identity + іншими стовпцями;
  2. Створіть подання над ним і відкрийте лише ті стовпці, які ви групово вставите;
  3. BCP на виду

2
Ласкаво просимо до Stack Overflow. Найкращі відповіді включають більше пояснень про те, як ваша відповідь корисна, і, можливо, про те, чим ваша відповідь відрізняється від інших.
CGritton,

1

Це дуже стара публікація, на яку потрібно відповісти, але жодна з поданих відповідей не вирішує проблему, не змінюючи поставлених умов, чого я не можу зробити.

Я вирішив це, використовуючи варіант OPENROWSET BULK INSERT. Тут використовується файл одного формату і працює однаково, але він дозволяє читати файл даних за допомогою оператора 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;

0

Іншим варіантом, якщо ви використовуєте тимчасові таблиці замість проміжних таблиць, може бути створення тимчасової таблиці, як очікує імпорт, а потім додавання стовпця ідентифікації після імпорту.

Отже, ваш sql робить щось подібне:

  1. Якщо існує тимчасова таблиця, відпустіть
  2. Створити тимчасову таблицю
  3. Масовий імпорт до тимчасової таблиці
  4. Змінюйте тимчасову таблицю, щоб додати ідентичність
  5. <що б ви не хотіли робити з даними>
  6. Знизьте температурну таблицю

Досі не дуже чистий, але це інший варіант ... можливо, доведеться дістати і замки для безпеки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.