SQL Server 2008-2017 Travailler avec les CSV - Le blog de Dominique Verrière

 
CONTINUER À LIRE
SQL Server 2008-2017 Travailler avec les CSV - Le blog de Dominique Verrière
SQL Server
              2008-2017
Travailler avec les CSV

              Dominique Verrière
              Dialogue Formation Informatique
              SQL Server 2008-2017
SQL Server 2008-2017 Travailler avec les CSV - Le blog de Dominique Verrière
SQL Server : Le blog de Dominique Verrière   2
SQL Server 2008-2017 Travailler avec les CSV - Le blog de Dominique Verrière
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