web-dev-qa-db-fra.com

Comment écrire des caractères UTF-8 en utilisant une insertion en bloc dans SQL Server?

Je fais un INSERTION EN VRAC dans sqlserver et il n'insère pas correctement les caractères UTF-8 dans la base de données. Le fichier de données contient ces caractères, mais les lignes de la base de données contiennent des caractères parasites après l'exécution d'une insertion en bloc.

Mon premier suspect était la dernière ligne du fichier de format:

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"

Mais, après avoir lu cette page officielle il me semble qu’il s’agit en fait d’un bogue dans la lecture du fichier de données lors de l’insertion dans SQL Server version 2008. Nous utilisons la version 2008 R2.

Quelle est la solution à ce problème ou au moins une solution de contournement? 

16
Goran Jovic

Tu ne peux pas. Vous devez d’abord utiliser un champ de données de type N, convertir votre fichier au format UTF-16 puis l’importer. La base de données ne supporte pas UTF-8.

27
Michael-O

Je suis venu ici avant de chercher une solution permettant d'insérer en masse des caractères spéciaux .. Je n'ai pas aimé la solution de contournement avec UTF-16 (qui doublerait la taille d'un fichier csv) ... J'ai découvert que vous pouviez définitivement et que c'est CAN très facile, vous n'avez pas besoin d'un fichier de format . J'ajoute donc ce commentaire à d'autres personnes qui recherchent le même, car il ne semble pas être bien documenté nulle part, et je pense que c'est un problème très courant pour les personnes ne parlant pas anglais. La solution est la suivante: Il suffit d’ajouter CODEPAGE = '65001' dans l’énoncé with de l’insert en bloc. (65001 = numéro de page codée pour UTF-8) . Peut ne pas fonctionner pour tous les caractères unicode comme suggéré par Michael O, mais au moins, il convient parfaitement aux caractères latins étendus, grecs et cyrilliques, probablement beaucoup d'autres.

Remarque: la documentation MSDN indique que utf-8 n'est pas pris en charge. Ne le croyez pas. Cela fonctionne parfaitement pour SQL Server 2008, mais n'a pas essayé d'autres versions.

par exemple.:

BULK INSERT #myTempTable 
FROM  'D:\somefolder\myCSV.txt'+
WITH 
    ( 
        CODEPAGE = '65001',
        FIELDTERMINATOR = '|',
        ROWTERMINATOR ='\n'
    );

Si tous vos caractères spéciaux sont en 160-255 (iso-8859-1 ou windows-1252), vous pouvez également utiliser:

BULK INSERT #myTempTable 
FROM  'D:\somefolder\myCSV.txt'+
WITH 
    ( 
        CODEPAGE = 'ACP',
        FIELDTERMINATOR = '|',
        ROWTERMINATOR ='\n'
    );
27
Tom-K
  1. Dans Excel, enregistrer le fichier au format CSV (délimité par des virgules)
  2. Ouvrir le fichier CSV enregistré dans Notepad ++
  3. Encodage -> Convertir en UCS-2 Big Endian 
  4. Sauvegarder

BULK INSERT #tmpData

    FROM 'C:\Book2.csv'
    WITH
    (
        FIRSTROW = 2,
        FIELDTERMINATOR = ';',  --CSV field delimiter
        ROWTERMINATOR = '\n',   --Use to shift the control to next row
        TABLOCK
    )

Terminé.

7
Janis Rudovskis

Vous pouvez ré-encoder le fichier de données avec UTF-16. C'est ce que j'ai fait quand même.

4
sayap

Microsoft vient d'ajouter le support UTF-8 à SQL Server 2014 SP2:

https://support.Microsoft.com/en-us/kb/3136780

4
Jon Morisi

Notez qu'à partir de Microsoft SQL Server 2016, UTF-8 est pris en charge par bcp , BULK_INSERT (comme faisait partie de la question d'origine) , et OPENROWSET .

2
Charles Burns

Utilisez ces options - DATAFILETYPE='char' et CODEPAGE = '1252'

2
Heber

Ne devriez-vous pas utiliser SQLNCHAR au lieu de SQLCHAR pour les données unicode?

1
AdaTheDev

Je pensais ajouter mes pensées à cela. Nous essayions de charger des données dans SqlServer à l'aide de bcp et nous avons eu beaucoup de problèmes.

dans la plupart des versions, bcp ne prend en charge aucun type de fichier UTF-8. Nous avons découvert qu’UTF-16 fonctionnerait, mais c’est plus complexe que ce qui est montré dans ces messages.

En utilisant Java nous avons écrit le fichier en utilisant ce code: 

PrintStream fileStream = new PrintStream(NEW_TABLE_DATA_FOLDER + fileName, "x-UTF-16LE-BOM");

Cela nous a donné les données correctes à insérer.

 utf-16 little-endian

Nous avons essayé d’utiliser uniquement UTF16 et nous avons continué à obtenir des erreurs EOF. En effet, il nous manquait la partie BOM du fichier. De Wikipedia:

UTF-16, une nomenclature (U + FEFF) peut être placée en tant que premier caractère d'un fichier ou d'un flux de caractères pour indiquer la finalité (ordre des octets) de toutes les unités de code à 16 bits du fichier ou du flux. 

Si ces octets ne sont pas présents, le fichier ne fonctionnera pas. Nous avons donc le dossier, mais il reste un secret à résoudre. Lors de la construction de votre ligne de commande, vous devez inclure -w pour indiquer à bcp de quel type de données il s’agit. Lorsque vous utilisez uniquement des données en anglais, vous pouvez utiliser -c (caractère). Cela ressemblera à quelque chose comme ça:

bcp dbo.blah dans C:\Utilisateurs\blah\Bureau\événements\blah.txt -S tcp: databaseurl, someport -d thedatabase -U nom d'utilisateur -P mot de passe -w

Lorsque tout cela est fait, vous obtenez des données attrayantes!

 Good little endian!

0
markthegrea

Les données exportées sont au format TSV à partir du DB avec codage Latin-1.

C'est facile à vérifier: SELECT DATABASEPROPERTYEX('DB', 'Collation') SQLCollation;

Le fichier d'extraction est au format UTF-8.

BULK INSERT ne fonctionne pas avec UTF-8, je convertis donc UTF-8 en ISO-8859-1 (ou Latin-1) avec un simple script Clojure:

(spit ".\\dump\\file1.txt" (Slurp ".\\dump\\file1_utf8.txt" :encoding "UTF-8") :encoding "ISO-8859-1")

Pour exécuter - corriger les chemins et Java.exe -cp clojure-1.6.0.jar clojure.main utf8_to_Latin1.clj

0
beloblotskiy

J'ai testé l'insertion en bloc avec le format UTF -8. Cela fonctionne bien dans 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";

J'utilisais le fichier *.DAT avec FS comme séparateur de colonne.

0

J'ai réussi à le faire en utilisant SSIS et une destination ADO NET au lieu d'OLEDB.

0
JYatesDBA