web-dev-qa-db-fra.com

Comment résoudre le problème de qualificateur de texte incorporé lors de l'exportation de données vers un fichier plat CSV?

RFC 4180:

RFC 4180 définit Common Format and MIME Type for Comma-Separated Values (CSV) Files. L'une des exigences de RFC 4180 est indiquée ci-dessous. C'est le point #7 dans le lien RFC.

If double-quotes are used to enclose fields, then a double-quote
appearing inside a field must be escaped by preceding it with
another double quote.  For example:

"aaa","b""bb","ccc"

SQL Server 2000:

DTS Export/Import Wizard in SQL Server 2000 semble conforme aux normes susmentionnées, même si le RFC 4180 lui-même semble avoir été publié uniquement le octobre 2005. J'utilise la version SQL Server 2000 indiquée ci-dessous.

Microsoft SQL Server  2000 - 8.00.2039 (Intel X86) 
May  3 2005 23:18:38 
Copyright (c) 1988-2003 Microsoft Corporation
Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4)

SQL Server 2012:

SQL Server Import and Export Wizard dans SQL Server 2012 n'exporte pas les données d'une table dans un fichier CSV conformément au standard défini dans le document RFC 4180. J'utilise la version indiquée ci-dessous SQL Server 2012.

Microsoft SQL Server 2012 - 11.0.2316.0 (X64) 
Apr  6 2012 03:20:55 
Copyright (c) Microsoft Corporation
Enterprise Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)

Simulation de problème:

Voici un exemple que j'ai exécuté dans les deux SQL Server 2000 et SQL Server 2012. J'ai lancé la requête ci-dessous pour créer une table et insérer quelques enregistrements. La colonne ItemDesc contient des données avec des guillemets doubles. Mon intention est d'exporter les données de ces deux versions de SQL Server à l'aide de l'assistant de données d'exportation intégré et de comparer les fichiers CSV générés.

CREATE TABLE dbo.ItemInformation(
    ItemId nvarchar(20) NOT NULL,
    ItemDesc nvarchar(100) NOT NULL
) 
GO

INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('100338754', 'Crown Bolt 3/8"-16 x 1" Stainless-Steel Hex Bolt');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('202255836', 'Simpson Strong-Tie 5/8" SSTB Anchot Bolt');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('100171631', 'Grip-Rite #11 x 1-1/2" Electro-Galvanized Steel Roofing Nails');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('202210289', 'Crown Bolt 1/2" x 3" "Zinc-Plated" Universal Clevis Pin');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('100136988', 'Tapcon 3/16" x 1-3/4" Climaseal Steel "Flat-Head" Phillips Concrete Anchors (75-Pack)');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('203722101', 'KwikTap 3/16" x 2-1/4" "Flat-Head" Concrete Screws (100-Pack)');
GO

Sur le DTS Export/Import Wizard in SQL Server 2000, j'ai utilisé les paramètres ci-dessous pour exporter les données dans un fichier CSV. J'ai enregistré le fichier sous le nom SQLServer2000_ItemInformation.csv.

DTS Export/Import Wizard

Sur le SQL Server Import and Export Wizard in SQL Server 2012, j'ai utilisé les paramètres ci-dessous pour exporter les données dans un fichier CSV. J'ai enregistré le fichier sous le nom SQLServer2012_ItemInformation.csv.

SQL Server Import and Export Wizard - Choose a destination

SQL Server Import and Export Wizard - Configure Flat File Destination

Voici la comparaison entre les deux fichiers utilisant Beyond Compare. Le côté gauche contient le fichier généré par SQL Server 2000 et le côté droit contient le fichier généré par SQL Server 2012. Vous remarquerez que le fichier de gauche de SQL Server 2000 contient des guillemets doubles supplémentaires pour compenser les guillemets incorporés dans la colonne de données. Ceci est conforme à la norme spécifiée dans RFC 4180 mais il manque clairement dans le fichier généré par SQL Server 2012

File Comparison

Recherches sur le web:

J'ai cherché ce bogue sur le Web et trouvé les liens suivants. Voici les rapports de bogue sur Microsoft Connect. Tous ces problèmes semblent être liés à l'importation d'un fichier, mais rien à l'exportation de données. Tous ces bogues ont été fermés en tant que Fixed.

La publication ci-dessous sur le blog MSDN indique que des modifications ont été apportées à SQL Server 2012 en ce qui concerne Flat file source supports embedded qualifiers and a variable number of columns per row.

Un autre article sur le blog MSDN indique la même chose dans la section Embedded Qualifiers.

Solution que je connais:

Je connais une solution pour résoudre le problème en écrivant une requête qui remplacerait toutes les doubles guillemets (") dans les données de ma colonne par deux doubles guillemets (""), de sorte que le fichier exporté finisse par se retrouver. avec les données qualificatives intégrées correctes. Cela éviterait d'extraire les données directement de la table telles quelles.

Mes questions:

  • Je ne sais pas si ce problème a vraiment été résolu dans SQL Server 2012. Ce problème a-t-il été résolu uniquement pour les fichiers importing avec des qualificateurs de texte incorporés et not pour les données exporting vers CSV?

  • Probablement, je fais clairement quelque chose de mal et manque l'évidence. Quelqu'un pourrait-il m'expliquer ce que je fais mal ici?

Microsoft Connect:

J'ai soumis un rapport de bogue sur le site Web Microsoft Connect pour obtenir leurs commentaires. Voici le lien vers le rapport de bogue. Si vous acceptez le fait qu'il s'agisse d'un bogue, veuillez visiter le lien ci-dessous pour voter sur le site Web Microsoft Connect.

Le qualificateur de texte incorporé lors de l'exportation au format CSV n'est pas conforme à la norme RFC 4180

61
user756519

Je ne proposerais pas cette réponse, sauf que vous avez travaillé si dur pour la documenter et qu'elle a été votée sans réponse après un mois. Alors, voici. Votre seul choix semble être de changer les données ou de changer l'outil. 

Probablement, je fais clairement quelque chose de mal et manque l'évidence. Quelqu'un pourrait-il m'expliquer ce que je fais mal ici?

Lorsque l'outil est cassé et que le fournisseur s'en fiche, c'est une erreur de continuer à essayer. Il est temps de passer. Vous vous êtes efforcé de rechercher exactement le type de problème et de démontrer qu'il enfreint non seulement le RFC, mais également la version précédente de l'outil. De combien d'autres preuves avez-vous besoin? 

CSV est aussi une ancre de bateau. Si vous avez l'option, vous feriez mieux d'utiliser un format de fichier délimité ordinaire. Pour de nombreuses applications, délimité par des tabulations est bon. Le meilleur délimiteur IMO est '\' car ce caractère n'a pas sa place dans le texte anglais. (Par contre, cela ne fonctionnera pas pour les données contenant des noms de chemins Windows.)

CSV a deux problèmes en tant que format d'échange. Premièrement, ce n'est pas tout ce que la norme; différentes applications reconnaissent différentes versions, quoi que dise le RFC. Deuxièmement (et liée), cela ne constitue pas un langage régulier en termes CS, raison pour laquelle il ne peut pas être analysé comme une expression régulière. Comparez avec ^([^\t]*\t)*[\t]*$ pour une ligne délimitée par des tabulations. L'implication pratique de la complexité de la définition du CSV est (voir ci-dessus) le manque relatif d'outils pour les manipuler et leur tendance à être incompatibles, en particulier aux petites heures du matin. 

Si vous lancez CSV et DTS, vous disposez de bonnes options, dont l'une est bcp.exe. C'est très rapide et sûr, car Microsoft n'a pas été tenté de le mettre à jour depuis des années. Je ne connais pas grand chose à DTS, mais au cas où vous deviez l'utiliser pour l'automatisation, IIRC existe un moyen d'appeler des utilitaires externes. Attention cependant, bcp.exe ne renvoie pas le statut d'erreur au shell de manière fiable. 

Si vous êtes déterminé à utiliser DTS et à vous en tenir au format CSV, votre meilleure option consiste à écrire une vue qui prépare les données de manière appropriée. Si je restais dans ce coin, je créerais un schéma appelé, par exemple, "DTS2012CSV", afin de pouvoir écrire select * from DTS2012CSV.tablename, donnant ainsi à toute personne intéressée une chance de le comprendre (parce que vous le documenterez, n'est-ce pas, dans les commentaires dans le texte de vue?). Au besoin, d’autres peuvent copier sa technique pour d’autres extraits brisés. 

HTH. 

7
James K. Lowden

Je sais que cela remonte à deux ans, mais je rencontre également ce problème, car nous devons utiliser SQL Server 2008 pour un contrat que nous avons (ne le demandez pas). Après avoir lu cette question, je me suis rendu compte que je devais faire la suggestion de remplacement, mais lorsque je suis allé le faire dans la requête, je me suis heurté à des problèmes de troncature, car utiliser la fonction replace () dans la requête convertissait le texte en varchar (8000) par défaut.

Cependant, j'ai découvert que je pouvais faire la même chose en utilisant une étape de colonne dérivée entre les objets DB Source et Flat File. Par exemple, j'ai une colonne nommée "short_description", qui pourrait contenir des guillemets. Je viens d'utiliser la fonction suivante comme expression et de sélectionner "Remplacer short_description" dans la colonne dérivée:

REPLACE(short_description,"\"","\"\"")

Cela semble avoir résolu le problème pour moi.

1
skywarpgold

Souvent, le prénom et le nom de famille sont dans le même champ et mis en forme (Nom, Prénom). Cela doit être qualifié en texte si vous utilisez Tâches-> Exporter des données de la base de données (pas via SSIS où vous avez plus d'options) et vous devez exporter au format CSV sous forme de fichier délimité par des virgules.

Cela vous aidera dans vos champs sélectionnés non nuls qui nécessitent une double cotation ...

CASE WHEN NOT PersonName IS NULL AND LEN(PersonName) > 0 THEN QUOTENAME(PersonName, '"') ELSE NULL END as 'PersonName'

Résultat:

Nom d'une personne

"COLLINS, ZACKERY E"

0
Greg Bologna