Ответ 1
Вы не можете. Сначала вы должны использовать поле данных типа N, преобразовать свой файл в UTF-16 и затем импортировать его. База данных не поддерживает UTF-8.
Я делаю BULK INSERT в sqlserver и не вставляю символы UTF-8 в базу данных правильно. Файл данных содержит эти символы, но строки базы данных содержат символы мусора после выполнения массовой вставки.
Мой первый подозреваемый был последней строкой файла формата:
10.0
3
1 SQLCHAR 0 0 "{|}" 1 INSTANCEID ""
2 SQLCHAR 0 0 "{|}" 2 PROPERTYID ""
3 SQLCHAR 0 0 "[|]" 3 CONTENTTEXT "SQL_Latin1_General_CP1_CI_AS"
Но после чтения этой официальной страницы мне кажется, что на самом деле это ошибка при чтении файла данных с помощью операции вставки в SQL Server версии 2008. Мы используют версию 2008 R2.
Каково решение этой проблемы или, по крайней мере, обходной путь?
Вы не можете. Сначала вы должны использовать поле данных типа N, преобразовать свой файл в UTF-16 и затем импортировать его. База данных не поддерживает UTF-8.
Я пришел сюда, прежде чем искать решение для массовой вставки специальных символов. Не понравился обходной путь с UTF-16 (это удвоило бы размер CSV файла). Я обнаружил, что вы определенно МОЖЕТЕ, и это очень просто, вам не нужен формат файла. Этот ответ предназначен для других людей, которые ищут то же самое, так как, кажется, это нигде не задокументировано, и я считаю, что это очень распространенная проблема для не говорящих по-английски людей. Решение: просто добавьте CODEPAGE = '65001' внутри оператора with массовой вставки. (65001 = номер кодовой страницы для UTF-8). Может работать не для всех символов Юникода, как это было предложено Майклом О, но, по крайней мере, он отлично работает для латинского, греческого и кириллического алфавита, возможно, для многих других.
Примечание: документация MSDN гласит, что utf-8 не поддерживается, не верьте этому, для меня это прекрасно работает в SQL Server 2008, однако другие версии не пробовали.
например:
BULK INSERT #myTempTable
FROM 'D:\somefolder\myCSV.txt'+
WITH
(
CODEPAGE = '65001',
FIELDTERMINATOR = '|',
ROWTERMINATOR ='\n'
);
Если все ваши специальные символы указаны в 160-255 (iso-8859-1 или windows-1252), вы также можете использовать:
BULK INSERT #myTempTable
FROM 'D:\somefolder\myCSV.txt'+
WITH
(
CODEPAGE = 'ACP',
FIELDTERMINATOR = '|',
ROWTERMINATOR ='\n'
);
BULK INSERT #tmpDatap >
FROM 'C:\Book2.csv' WITH ( FIRSTROW = 2, FIELDTERMINATOR = ';', --CSV field delimiter ROWTERMINATOR = '\n', --Use to shift the control to next row TABLOCK )
Готово.
Вы можете перекодировать файл данных с помощью UTF-16. Это все, что я сделал.
Microsoft просто добавила поддержку UTF-8 для SQL Server 2014 SP2:
Используйте эти параметры -
DATAFILETYPE='char'
и CODEPAGE = '1252'
Обратите внимание, что с Microsoft SQL Server 2016 UTF-8 поддерживается bcp
, BULK_INSERT
(как было в исходном вопросе) и OPENROWSET
.
Разве вы не используете SQLNCHAR
вместо SQLCHAR
для данных Unicode?
Мне удалось сделать это с помощью SSIS и назначения ADO NET вместо OLEDB.
Мои экспортированные данные находятся в формате TSV из базы данных с кодировкой Latin-1.
Это легко проверить:
SELECT DATABASEPROPERTYEX('DB', 'Collation') SQLCollation;
Экстрактивный файл находится в формате UTF-8.
BULK INSERT не работает с UTF-8, поэтому я конвертирую UTF-8 в ISO-8859-1 (aka Latin-1) с простым Clojure script:
(spit ".\\dump\\file1.txt"
(slurp ".\\dump\\file1_utf8.txt" :encoding "UTF-8")
:encoding "ISO-8859-1")
Выполнять - правильные пути и
java.exe -cp clojure-1.6.0.jar clojure.main utf8_to_Latin1.clj
Я проверил объемную вставку с UTF -8
Format. Он отлично работает на Sql Server 2012.
string bulkInsertQuery = @"DECLARE @BulkInsertQuery NVARCHAR(max) = 'bulk insert [dbo].[temp_Lz_Post_Obj_Lvl_0]
FROM ''C:\\Users\\suryan\\Desktop\\SIFT JOB\\New folder\\POSTdata_OBJ5.dat''
WITH ( FIELDTERMINATOR = '''+ CHAR(28) + ''', ROWTERMINATOR = ''' +CHAR(10) + ''')'
EXEC SP_EXECUTESQL @BulkInsertQuery";
Я использовал файл *.DAT
с FS в качестве разделителя столбцов.
Преобразование файла utf-8 в utf-16 используя iconv:
iconv -f utf-8 -t utf-16le < in.txt > out.txt
Думаю, я бы добавил к этому свои мысли. Мы пытались загрузить данные в SqlServer с помощью bcp и имели массу проблем.
bcp не поддерживает большинство файлов UTF-8 в большинстве версий. Мы обнаружили, что UTF-16 будет работать, но он более сложный, чем показано в этих сообщениях.
Используя Java, мы написали файл, используя этот код:
PrintStream fileStream = new PrintStream(NEW_TABLE_DATA_FOLDER + fileName, "x-UTF-16LE-BOM");
Это дало нам правильные данные для вставки.
Мы попытались использовать только UTF16 и продолжали получать ошибки EOF. Это связано с тем, что нам не хватает части спецификации этого файла. Материал из Википедии:
UTF-16, спецификация (U + FEFF) может быть помещена в качестве первого символа файла или символьного потока для указания конечности (порядка байтов) всех 16-разрядных блоков кода файла или потока.
Если эти байты отсутствуют, файл не будет работать. Итак, у нас есть файл, но есть еще один секрет, который нужно решить. При построении командной строки вы должны указать -w, чтобы сообщить bcp, какой тип данных он имеет. При использовании только английских данных вы можете использовать -c (символ). Итак, это будет выглядеть примерно так:
bcp dbo.blah в C:\Users\blah\Desktop\events\blah.txt -S tcp: databaseurl, someport -d thedatabase -U username -P password -w
Когда все это будет сделано, вы получите несколько приятных данных!