Inclure les en-têtes lors de l'utilisation de SELECT INTO OUTFILE?

117

Est-il possible d'inclure les en-têtes d'une manière ou d'une autre lors de l'utilisation de MySQL INTO OUTFILE?

Brett
la source

Réponses:

166

Vous devrez coder en dur ces en-têtes vous-même. Quelque chose comme:

SELECT 'ColName1', 'ColName2', 'ColName3'
UNION ALL
SELECT ColName1, ColName2, ColName3
    FROM YourTable
    INTO OUTFILE '/path/outfile'
Joe Stefanelli
la source
14
Mais cela ne fonctionnera pas s'il y a un ORDER BYdans l' SELECTarticle. La ligne d'en-tête peut être n'importe où dans le fichier généré en fonction de la commande.
COil
Voir quelques réponses ci-dessous pour des idées sur l'utilisation de ORDER BY et aussi la réponse de matt pour obtenir rapidement tous les ColName1, ColName2, etc. Compléments très utiles à cette excellente réponse!
Andrew T
1
Cette réponse semble à peu près correcte, je l'ai même utilisée presque aveuglément sur mon serveur de développement ... Sans les en-têtes de colonne, il faut environ 50 secondes pour vider 240 millions de lignes. Avec ce UNION ALL, le serveur a de gros problèmes en essayant de faire une table temporaire avant de tout vider, cela fait plus de 10 minutes maintenant et attend toujours que la table temporaire soit écrite sur le disque! Soyez conscient de cela! Vous préféreriez certainement ajouter les noms de colonne d'une autre manière, même si cela signifie ouvrir le fichier après avec un autre langage de programmation.
Salketer
Cela ne semble fonctionner que si toutes les colonnes de YourTable sont un type de données caractère, ce qui a du sens. Sinon, vous obtenez l'erreur inutile: "Les instructions SELECT utilisées ont un nombre de colonnes différent".
TheBamf
1
C'est l'une des raisons pour lesquelles j'envisage de passer à un autre SGBD.
e18r
85

La solution fournie par Joe Steanelli fonctionne, mais faire une liste de colonnes n'est pas pratique lorsque des dizaines ou des centaines de colonnes sont impliquées. Voici comment obtenir la liste des colonnes de la table my_table dans my_schema .

-- override GROUP_CONCAT limit of 1024 characters to avoid a truncated result
set session group_concat_max_len = 1000000;

select GROUP_CONCAT(CONCAT("'",COLUMN_NAME,"'"))
from INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'my_table'
AND TABLE_SCHEMA = 'my_schema'
order BY ORDINAL_POSITION

Vous pouvez maintenant copier et coller la ligne résultante comme première instruction dans la méthode de Joe.

mat
la source
2
Cela renvoie toutes les colonnes concaténées ensemble dans un seul champ. Je ne parviens pas à unir cela avec une autre instruction select qui renvoie plusieurs champs. C'est vraiment utile pour obtenir une ligne que je peux copier et coller comme en-tête de mon fichier.
tmoore82
1
L'idée est de copier le champ unique résultant et de le coller dans votre instruction UNION au lieu de taper manuellement dans column1, column2, etc. lors de l'utilisation de la méthode de Joe (la réponse acceptée) afin que vous puissiez obtenir la liste des colonnes plus rapidement!
Andrew T
Je cherchais à exporter tout mon schéma de table / champs. Cette réponse combinée à celle acceptée a fait l'affaire!
Rémi Breton
@Chris ORDER BY ORDINAL_POSITIONgère ça
mat
1
ORDER BY ORDINAL_POSITION doit faire partie de l'appel GROUP_CONCAT (), comme dansGROUP_CONCAT(CONCAT('"',COLUMN_NAME,'"') order BY ORDINAL_POSITION)
Apuleius le
15

Pour une sélection complexe avec ORDER BY, j'utilise ce qui suit:

SELECT * FROM (
    SELECT 'Column name #1', 'Column name #2', 'Column name ##'
    UNION ALL
    (
        // complex SELECT statement with WHERE, ORDER BY, GROUP BY etc.
    )
) resulting_set
INTO OUTFILE '/path/to/file';
evilguc
la source
Cette solution fonctionne bien lors de la commande de la deuxième requête (complexe); si vous ne le faites pas de cette façon, vous finirez par commander la première colonne également, ce qui n'est pas souhaitable. Belle suggestion @evilguc!
Aaron
N'a pas fonctionné avec moi, après avoir fait UNION ALL l'ordre de la colonne id est foiré
Mohanad Kaleia
6

Vous pouvez utiliser l'instruction préparée avec la réponse de Lucek et exporter dynamiquement la table avec le nom des colonnes en CSV:

--If your table has too many columns
SET GLOBAL group_concat_max_len = 100000000;
--Prepared statement
SET @SQL = ( select CONCAT('SELECT * INTO OUTFILE \'YOUR_PATH\' FIELDS TERMINATED BY \',\' OPTIONALLY ENCLOSED BY \'"\' ESCAPED BY \'\' LINES TERMINATED BY \'\\n\' FROM (SELECT ', GROUP_CONCAT(CONCAT("'",COLUMN_NAME,"'")),' UNION select * from YOUR_TABLE) as tmp') from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'YOUR_TABLE' AND TABLE_SCHEMA = 'YOUR_SCHEMA' order BY ORDINAL_POSITION );
--Execute it
PREPARE stmt FROM @SQL;
EXECUTE stmt;

Merci Lucek.

Vrag
la source
6

Cela vous permettra d'avoir des colonnes ordonnées et / ou une limite

SELECT 'ColName1', 'ColName2', 'ColName3'
UNION ALL
SELECT * from (SELECT ColName1, ColName2, ColName3
    FROM YourTable order by ColName1 limit 3) a
    INTO OUTFILE '/path/outfile';
Donald Wagner
la source
1
Juste une note que cette disposition de requête a également fonctionné pour moi dans MariaDB 10.1; les autres mises en page suggérées dans ce fil ne l'ont pas fait.
ProgrammerDan
Affiche l'en-tête en bas pour une raison quelconque, mais fonctionne bien pour le remettre en haut dans une application de feuille de calcul, étrange mais applaudit
Dmitri DB
Je suis également coincé avec mariaDB. avec une extraction de seulement 100 pistes, c'était plus de 14 secondes plus rapide que l'exécution de la réponse acceptée. Premier laissez-passer accepté: Query OK, 100 rows affected (14.72 sec) Deuxième laissez-passer avec le vôtreQuery OK, 101 rows affected (0.00 sec)
Casper Wilkes
6

Je fais simplement 2 requêtes, d'abord pour obtenir la sortie de la requête (limite 1) avec les noms de colonnes (pas de code en dur, pas de problèmes avec les jointures, Trier par, les noms de colonnes personnalisés, etc.), et la seconde pour faire la requête elle-même et combiner les fichiers en un seul CSV fichier:

CSVHEAD=`/usr/bin/mysql $CONNECTION_STRING -e "$QUERY limit 1;"|head -n1|xargs|sed -e "s/ /'\;'/g"`
echo "\'$CSVHEAD\'" > $TMP/head.txt
/usr/bin/mysql $CONNECTION_STRING -e "$QUERY into outfile '${TMP}/data.txt' fields terminated by ';' optionally enclosed by '\"' escaped by '' lines terminated by '\r\n';"
cat $TMP/head.txt $TMP/data.txt > $TMP/data.csv
utilisateur3037511
la source
5

J'ai rencontré un problème similaire lors de l'exécution d'une requête mysql sur de grandes tables dans NodeJS. L'approche que j'ai suivie pour inclure les en-têtes dans mon fichier CSV est la suivante

  1. Utilisez la requête OUTFILE pour préparer le fichier sans en-têtes

        SELECT * INTO OUTFILE [FILE_NAME] FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED 
        BY '\"' LINES TERMINATED BY '\n' FROM [TABLE_NAME]
  2. Récupérer les en-têtes de colonne pour le tableau utilisé au point 1

        select GROUP_CONCAT(CONCAT(\"\",COLUMN_NAME,\"\")) as col_names from 
        INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = [TABLE_NAME] AND TABLE_SCHEMA 
        = [DATABASE_NAME] ORDER BY ORDINAL_POSITION
  3. Ajoutez les en-têtes de colonne au fichier créé à l'étape 1 à l'aide du package npm prepend-file

L'exécution de chaque étape a été contrôlée à l'aide de promesses dans NodeJS.

rahul shukla
la source
3

C'est une triche alternative si vous êtes familier avec Python ou R, et votre table peut tenir dans la mémoire.

Importez la table SQL dans Python ou R, puis exportez-la au format CSV et vous obtiendrez les noms de colonnes ainsi que les données.

Voici comment je le fais en utilisant R, nécessite la bibliothèque RMySQL:

db <- dbConnect(MySQL(), user='user', password='password', dbname='myschema', host='localhost')

query <- dbSendQuery(db, "select * from mytable")
dataset <- fetch(query, n=-1)

write.csv(dataset, 'mytable_backup.csv')

C'est un peu une triche, mais j'ai trouvé que c'était une solution de contournement rapide lorsque mon nombre de colonnes était trop long pour utiliser la méthode concat ci-dessus. Remarque: R ajoutera une colonne 'row.names' au début du CSV, vous voudrez donc la supprimer si vous avez besoin de vous fier au CSV pour recréer la table.

Joindre des points
la source
2

Donc, si toutes les colonnes de my_tablesont un type de données caractère , nous pouvons combiner les réponses principales (de Joe, matt et evilguc) ensemble, pour obtenir l'en-tête ajouté automatiquement dans une requête SQL `` simple '', par exemple

select * from (
  (select column_name
    from information_schema.columns
    where table_name = 'my_table'
    and table_schema = 'my_schema'
    order by ordinal_position)
  union all
  (select *  // potentially complex SELECT statement with WHERE, ORDER BY, GROUP BY etc.
  from my_table)) as tbl
into outfile '/path/outfile'
fields terminated by ',' optionally enclosed by '"' escaped by '\\'
lines terminated by '\n';

où les deux dernières lignes font la sortie csv.

Notez que cela peut être lent s'il my_tableest très volumineux.

TheBamf
la source
il a l'erreur "Les instructions SELECT utilisées ont un nombre de colonnes différent". Sir
Bowei Liu
1

Je pense que si vous utilisez un UNION, cela fonctionnera:

select 'header 1', 'header 2', ...
union
select col1, col2, ... from ...

Je ne connais pas de moyen de spécifier directement les en-têtes avec la syntaxe INTO OUTFILE.

Paul W
la source
1
UNION ALL serait plus sûr et plus rapide.
toxalot
1

En fait, vous pouvez le faire fonctionner même avec un ORDER BY.

Il faut juste quelques astuces dans l'ordre par instruction - nous utilisons une instruction case et remplaçons la valeur d'en-tête par une autre valeur dont le tri est garanti en premier dans la liste (cela dépend évidemment du type de champ et si vous triez ASC ou DESC)

Supposons que vous ayez trois champs, name (varchar), is_active (bool), date_something_happens (date), et que vous souhaitiez trier les deux seconds par ordre décroissant:

select 
        'name'
      , 'is_active' as is_active
      , date_something_happens as 'date_something_happens'

 union all

 select name, is_active, date_something_happens

 from
    my_table

 order by
     (case is_active when 'is_active' then 0 else is_active end) desc
   , (case date when 'date' then '9999-12-30' else date end) desc
Simon Woolf
la source
1

Étant donné que la fonctionnalité 'include-headers' ne semble pas encore intégrée et que la plupart des "solutions" ici doivent taper les noms des colonnes manuellement, et / ou ne même pas prendre en compte les jointures, je vous recommande de contourner le problème .

  • La meilleure alternative que j'ai trouvée jusqu'à présent est d'utiliser un outil décent (j'utilise HeidiSQL ).
    Mettez votre demande, sélectionnez la grille, faites un simple clic droit et exportez vers un fichier. Il a toutes les options nécessaires pour une exportation propre et devrait gérer la plupart des besoins.

  • Dans la même idée, l'approche de user3037511 fonctionne bien et peut être automatisée facilement .
    Lancez simplement votre requête avec une ligne de commande pour obtenir vos en-têtes. Vous pouvez obtenir les données avec un SELECT INTO OUTFILE ... ou en exécutant votre requête sans la limite, à vous de choisir.

    Notez que la redirection de sortie vers un fichier fonctionne comme un charme à la fois sous Linux ET Windows.


Cela me donne envie de souligner que 80% du temps, lorsque je veux utiliser SELECT FROM INFILE ou SELECT INTO OUTFILE, je finis par utiliser autre chose en raison de certaines limitations (ici, l'absence de 'headers options', on un AWS-RDS, les droits manquants, etc.)

Par conséquent, je ne réponds pas exactement à l'op question ... mais il devrait répondre à ses besoins :)
EDIT: et de répondre effectivement à sa question: pas
tant de 07/09/2017, vous ne pouvez pas inclure des en- têtes si vous coller avec la commande SELECT INTO OUTFILE
: |

Baume
la source
1

un exemple de mon capteur de nom de table de base de données avec des colonnes (id, heure, unité)

select ('id') as id, ('time') as time, ('unit') as unit
UNION ALL
SELECT * INTO OUTFILE 'C:/Users/User/Downloads/data.csv'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM sensor
Dayanand SK
la source
0

J'écrivais mon code en PHP, et j'avais un peu de mal à utiliser les fonctions concat et union, et je n'utilisais pas non plus de variables SQL, de quelque manière que ce soit, je l'ai fait fonctionner, voici mon code:

//first I connected to the information_scheme DB

$headercon=mysqli_connect("localhost", "USERNAME", "PASSWORD", "information_schema");

//took the healders out in a string (I could not get the concat function to work, so I wrote a loop for it)

    $headers = '';
    $sql = "SELECT column_name AS columns FROM `COLUMNS` WHERE table_schema = 'YOUR_DB_NAME' AND table_name = 'YOUR_TABLE_NAME'";
    $result = $headercon->query($sql);
    while($row = $result->fetch_row())
    {
        $headers = $headers . "'" . $row[0] . "', ";
    }
$headers = substr("$headers", 0, -2);

// connect to the DB of interest

$con=mysqli_connect("localhost", "USERNAME", "PASSWORD", "YOUR_DB_NAME");

// export the results to csv
$sql4 = "SELECT $headers UNION SELECT * FROM YOUR_TABLE_NAME WHERE ... INTO OUTFILE '/output.csv' FIELDS TERMINATED BY ','";
$result4 = $con->query($sql4);
user5671922
la source
0

Voici un moyen d'obtenir les titres d'en-tête à partir des noms de colonnes de manière dynamique.

/* Change table_name and database_name */
SET @table_name = 'table_name';
SET @table_schema = 'database_name';
SET @default_group_concat_max_len = (SELECT @@group_concat_max_len);

/* Sets Group Concat Max Limit larger for tables with a lot of columns */
SET SESSION group_concat_max_len = 1000000;

SET @col_names = (
  SELECT GROUP_CONCAT(QUOTE(`column_name`)) AS columns
  FROM information_schema.columns
  WHERE table_schema = @table_schema
  AND table_name = @table_name);

SET @cols = CONCAT('(SELECT ', @col_names, ')');

SET @query = CONCAT('(SELECT * FROM ', @table_schema, '.', @table_name,
  ' INTO OUTFILE \'/tmp/your_csv_file.csv\'
  FIELDS ENCLOSED BY \'\\\'\' TERMINATED BY \'\t\' ESCAPED BY \'\'
  LINES TERMINATED BY \'\n\')');

/* Concatenates column names to query */
SET @sql = CONCAT(@cols, ' UNION ALL ', @query);

/* Resets Group Contact Max Limit back to original value */
SET SESSION group_concat_max_len = @default_group_concat_max_len;

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
RNickMcCandless
la source
1
Une bonne solution devrais-je dire. Je l'ai adopté pour mes besoins. Merci!
Denis Kulagin
0

Je voudrais ajouter à la réponse fournie par Sangam Belose. Voici son code:

select ('id') as id, ('time') as time, ('unit') as unit
UNION ALL
SELECT * INTO OUTFILE 'C:/Users/User/Downloads/data.csv'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM sensor

Cependant, si vous n'avez pas configuré votre "secure_file_priv"dans les variables, cela peut ne pas fonctionner. Pour cela, vérifiez le dossier défini sur cette variable en:

SHOW VARIABLES LIKE "secure_file_priv"

La sortie devrait ressembler à ceci:

mysql> show variables like "%secure_file_priv%";
+------------------+------------------------------------------------+
| Variable_name    | Value                                          |
+------------------+------------------------------------------------+
| secure_file_priv | C:\ProgramData\MySQL\MySQL Server 8.0\Uploads\ |
+------------------+------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

Vous pouvez modifier cette variable ou modifier la requête pour afficher le fichier dans le chemin par défaut affiché.

RGregg
la source
0

MySQL seul ne suffit pas pour faire cela simplement. Vous trouverez ci-dessous un script PHP qui produira des colonnes et des données au format CSV.

Entrez le nom de votre base de données et les tables en haut.

<?php

set_time_limit( 24192000 );
ini_set( 'memory_limit', '-1' );
setlocale( LC_CTYPE, 'en_US.UTF-8' );
mb_regex_encoding( 'UTF-8' );

$dbn = 'DB_NAME';
$tbls = array(
'TABLE1',
'TABLE2',
'TABLE3'
);

$db = new PDO( 'mysql:host=localhost;dbname=' . $dbn . ';charset=UTF8', 'root', 'pass' );

foreach( $tbls as $tbl )
{
    echo $tbl . "\n";
    $path = '/var/lib/mysql/' . $tbl . '.csv';

    $colStr = '';
    $cols = $db->query( 'SELECT COLUMN_NAME AS `column` FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = "' . $tbl . '" AND TABLE_SCHEMA = "' . $dbn . '"' )->fetchAll( PDO::FETCH_COLUMN );
    foreach( $cols as $col )
    {
        if( $colStr ) $colStr .= ', ';
        $colStr .= '"' . $col . '"';
    }

    $db->query(
    'SELECT *
    FROM
    (
        SELECT ' . $colStr . '
        UNION ALL
        SELECT * FROM ' . $tbl . '
    ) AS sub
    INTO OUTFILE "' . $path . '"
    FIELDS TERMINATED BY ","
    ENCLOSED BY "\""
    LINES TERMINATED BY "\n"'
    );

    exec( 'gzip ' . $path );

    print_r( $db->errorInfo() );
}

?>

Vous aurez besoin de ce répertoire dans lequel vous souhaitez générer la sortie. MySQL doit avoir la capacité d'écrire dans le répertoire.

$path = '/var/lib/mysql/' . $tbl . '.csv';

Vous pouvez modifier les options d'exportation CSV dans la requête:

INTO OUTFILE "' . $path . '"
FIELDS TERMINATED BY ","
ENCLOSED BY "\""
LINES TERMINATED BY "\n"'

À la fin, il y a un appel exécutable à GZip le CSV.

Kohjah Breese
la source
-1
SÉLECTIONNEZ 'ColName1', 'ColName2', 'ColName3'
UNION TOUT
SELECT ColName1, ColName2, ColName3
    DE YourTable
    INTO OUTFILE 'c: \\ fiche.csv' CHAMPS TERMINÉS PAR ',' FACULTATIVEMENT CLOS PAR '"' LIGNES TERMINÉES PAR '\ n' 
manoj singh
la source