SQL Server 2008-2017 Travailler avec les CSV - Le blog de Dominique Verrière
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
SQL Server 2008-2017 Travailler avec les CSV Dominique Verrière Dialogue Formation Informatique SQL Server 2008-2017
Introduction Ce petit fascicule fait partie d’une liste de notes que je publie gratuitement sur mon site. J’essaie de mettre dans ces notes mon expérience de terrain en toute indépendance de Microsoft. Dominique Verrière
Table des matières Introduction ................................................................................................................. 6 Pourquoi utiliser encore des CSV ?........................................................................................................................ 6 Produire des CSV.......................................................................................................... 6 Produire une variable contenant une liste ............................................................................................................ 6 Produire une CSV en SQL Server 2017 .................................................................................................................. 7 Produire une CSV en colonne de requête ............................................................................................................. 7 Importer des CSV ....................................................................................................... 11 Transformer une CSV en liste .............................................................................................................................. 11 Transformer une CSV à partir de SQL Server 2016.............................................................................................. 13 Contacter l’auteur ...................................................................................................... 14
Sommaire SQL Server : Le blog de Dominique Verrière 5
Exporter et importer des CSV Introduction Pourquoi utiliser encore des CSV ? Les Comma Separated Values peuvent encore être utiles face aux formats XML et JSON car ils sont plus Que compacts : seules les données utiles y sont stockées indépendamment de toute méta donnée. Je les utilise dans deux cas le plus souvent : Générer une CSV contenant une liste de ‘choses’ pour affichage ou preuve Dé normalisation pour transformer un tableau de données en liste Nous allons voir ces deux cas dans ce billet. Produire des CSV Produire une variable contenant une liste Cette méthode servira quand on veut avoir une trace de ce que l’on est en train de traiter ; je me sers souvent de ce cas dans mes scripts d’administration de bases de données. Un développeur de rapport (Exemple SSRS) pourra aussi afficher des paramètres venant de l’extérieur. Enfin, c’est une des façons de passer des paramètres multi valués aux procédures stockées Transact SQL (l’autre façon étant de passer des objets table en lecture seule). Voici un exemple trivial : je travaille sur n bases de données et j’en veux une liste CSV : declare @Liste nvarchar(max)='',@Separateur nvarchar(1)='' select @Liste = @Liste + @Separateur + name ,@Separateur=',' from ( select top 8 t1.name as name from sys.databases t1 order by t1.name )t2 print @Liste SQL Server Le blog de Dominique Verrière
Exporter et importer des CSV Ici on utilise le caractère récursif du remplissage du buffer de sortie des données ; c’est pourquoi les deux variables sont initialisées à chaine vide, le remplissage ne faisant que de concaténer jusqu’à la fin des données. Vous noterez aussi que le séparateur vaut vide au début pour se transformer en virgule ensuite. Produire une CSV en SQL Server 2017 Eh oui ! Cette version est déjà dans les tuyaux et va enfin combler des manques cruels dans le langage Transact SQL. Ainsi, une fonction intégrée va permettre de générer directement une CSV depuis les données d’une requête : En voici la syntaxe : STRING_AGG STRING_AGG (ExpressionDeChaine , Separateur ) [ ] ::= WITHIN GROUP ( ORDER BY [ ASC | DESC ] ) Et notre exemple modifié pour SQL 2017 : -- SQL 2017 select STRING_AGG(t2.name,',') as ListeBases from ( select top 8 t1.name as name from sys.databases t1 order by t1.name ) t2 Produire une CSV en colonne de requête L’exercice est un peu plus compliqué car on va risquer des problèmes de performances. Pour illustrer mon propos, je vais utiliser deux tables : Une contient les ‘données’ NoCoureur int, Nom varchar, Prenom varchar avec une volumétrie de (608669 ligne(s) affectée(s)) L’autre contient les ‘méta données’ NoCoureur int, Meta varchar avec une volumétrie initiale de SQL Server : Le blog de Dominique Verrière 7
Exporter et importer des CSV (39182 ligne(s) affectée(s)) L’objectif de la démonstration est de dé normaliser la table des méta données pour la ‘coller’ en CSV à la suite des données. Voici des extraits de ces deux tables : select top 10 * from #Donnees select top 10 * from #MetaDonnees On remarque tout de suite qu’il y a plusieurs méta données pour une donnée, par ailleurs certaines données n’ont pas de méta données associées. Voici une première requête : -- Sous requete liste CSV des méta select t1.NoCoureur,t1.Nom,t1.Prenom, (select ',' + Meta from #MetaDonnees where NoCoureur = t1.NoCoureur for XML path('') ) as DCourses from #Donnees t1 where t1.NoCoureur in (194728,194731) J’ai limité à deux coureurs ‘intéressants’ car possédant des méta données… SQL Server Le blog de Dominique Verrière
Exporter et importer des CSV Pourquoi utiliser XML PATH ? Car cette instruction génère une variable contenant du XML, ce qui nous va parfaitement car une expression de type colonne de requête ne peut retourner n lignes. Mais il reste un petit problème : la concaténation des valeurs dans le type XML a ajouté une virgule en début de l’expression. Il reste donc à nettoyer ce résultat. La fonction STUFF va y pourvoir : elle permet de remplacer une portion de chaine par une autre chaine. select t1.NoCoureur,t1.Nom,t1.Prenom, stuff( (select ',' + Meta from #MetaDonnees where NoCoureur = t1.NoCoureur for XML path('') ) ,1,1,'') as DCourses from #Donnees t1 where t1.NoCoureur in (194728,194731) SQL Server : Le blog de Dominique Verrière 9
Exporter et importer des CSV Qu’en est-il des performances ? Attention, ce genre de requête corrélée va potentiellement manipuler D x M données… Pour forcer le trait je vais ajouter beaucoup de méta données. if OBJECT_ID('tempdb..#DonneesMetaDonnees') is not null drop table #DonneesMetaDonnees select t1.NoCoureur,t1.Nom,t1.Prenom, stuff ( (select ',' + Meta from #MetaDonnees where NoCoureur = t1.NoCoureur for XML path('') ),1,1,'') as DCourses into #DonneesMetaDonnees from #Donnees t1 Pour ne pas mesurer le remplissage du buffer de Management Studio, je stocke le tout dans une nouvelle table temporaire. SQL Server \endash Temps d'exécution : , Temps UC = 4281 ms, temps écoulé = 4290 ms. (608669 ligne(s) affectée(s)) Effectivement cette requête consomme beaucoup de CPU, une chance pour moi, la machine est dédiée et tout le CPU est pour moi ! L’avantage de stocker les entrées dans des tables temporaires est ici : 1. Réduire la surface des données 2. Pouvoir indexer à la demande create unique clustered index x1 on #Donnees(NoCoureur) create clustered index x2 on #MetaDonnees(NoCoureur) Notre nouvelle exécution devenant : SQL Server \endash Temps d'exécution : , Temps UC = 2391 ms, temps écoulé = 2394 ms. (608669 ligne(s) affectée(s)) Pas si mal, presque une division par deux. SQL Server Le blog de Dominique Verrière
Exporter et importer des CSV Importer des CSV Transformer une CSV en liste Il s’agit cette fois de générer une table à partir d’une CSV. Nous rentrons ici dans le domaine des fonctions de type table ; en voici un exemple : -- Splitter une CSV if object_id (N'dbo.Split') IS NOT NULL drop function dbo.Split go create function dbo.Split(@Valeurs varchar(max)) returns @tRetour table ( Valeur varchar(max) ) as begin set @Valeurs = @Valeurs + ',' declare @i int, @Valeur varchar(max) set @i = 1 while 1=1 begin set @i = CHARINDEX(',',@Valeurs) if @i < 1 break set @Valeur = SUBSTRING (@Valeurs,1,@i - 1) if LEN(@Valeur) > 0 insert into @tRetour values (@Valeur) set @Valeurs = SUBSTRING (@Valeurs,@i +1, LEN(@Valeurs) - @i) end return end go Bien sûr, dans une programmation professionnelle on pourra rendre le séparateur paramétrable en ajoutant un paramètre à la fonction. Un cas d’usage étant : select * from dbo.Split ('Pierre,Paul,Jacques') SQL Server : Le blog de Dominique Verrière 11
Exporter et importer des CSV De nouveau, gare aux performances ! Transact SQL étant un langage interprété, n’aime guère toutes ces allocations de chaines de caractères. Par ailleurs, si vous lancez cette fonction de type table en jointure de tables, vous risquez fort de tomber sur le parameter sniffing (Voir mon article à ce sujet). select NoCoureur,Nom,Prenom,Valeur from #DonneesMetaDonnees cross apply dbo.Split(DCourses) SQL Server \endash Temps d'exécution : , Temps UC = 3172 ms, temps écoulé = 5079 ms. SQL Server Le blog de Dominique Verrière
Exporter et importer des CSV Transformer une CSV à partir de SQL Server 2016 A partir de SQL Server 2016, on pourra utiliser la nouvelle fonction STRING_SPLIT. Cette fonction, comme celle écrite précédemment, rend une table à partir d’une CSV. En voici la syntaxe : STRING_SPLIT ( Chaine , Separateur) select value from STRING_SPLIT('Pierre,Paul,Jacques', ','); Il est bien sûr tentant pour moi de comparer les performances des deux fonctions. -- comparer les deux fonctions if OBJECT_ID('tempdb..#ResultatSplit') is not null drop table #ResultatSplit select NoCoureur,Nom,Prenom,Valeur into #ResultatSplit from #DonneesMetaDonnees cross apply dbo.Split(DCourses) if OBJECT_ID('tempdb..#ResultatSplit') is not null drop table #ResultatSplit select NoCoureur,Nom,Prenom,value into #ResultatSplit from #DonneesMetaDonnees cross apply STRING_SPLIT(DCourses,',') Bilan : Cpu msec Elapsed msec Nbe lignes Dbo.Split 3 563 3 629 647851 STRING_SPLIT 12 453 5 087 647851 Oups ! Microsoft si tu me lis, il doit y avoir un loupé… (Mode debug, traces en trop ???) SQL Server : Le blog de Dominique Verrière 13
Contact Contacter l’auteur Dominique Verrière est un consultant spécialisé sur les technologies SQL Server : moteur relationnel, SSIS, SSRS et SSAS. Il intervient dans les entreprises pour des missions d'audit, de suivi de performances, d'administration de bases de données. Les bases de données dont il s'occupe peuvent contenir plusieurs milliards de lignes et atteindre des Téra octets; son expérience du terrain est donc significative. Afin de compléter cet article, un blog www.dominiqueverriere.fr est régulièrement mis à jour avec des articles sur les nouveautés ou expériences nouvelles de l'auteur SQL Server Le blog de Dominique Verrière
Vous pouvez aussi lire