web-dev-qa-db-fra.com

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

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

96
Brett

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

SELECT 'ColName1', 'ColName2', 'ColName3'
UNION ALL
SELECT ColName1, ColName2, ColName3
    FROM YourTable
    INTO OUTFILE '/path/outfile'
135
Joe Stefanelli

La solution fournie par Joe Steanelli fonctionne, mais dresser 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 in 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

Maintenant, vous pouvez copier-coller la ligne résultante en tant que première instruction de la méthode de Joe.

72
matt

Pour les complexes sélectionnez 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';
12
evilguc

Cela vous permettra d'avoir des colonnes commandé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';
5
Donald Wagner

Vous pouvez utiliser une instruction préparée avec la réponse de lucek et exporter dynamiquement une table avec un nom de colonne 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.

5
Vrag

Je fais simplement 2 requêtes, premièrement pour obtenir le résultat de la requête (limite 1) avec des noms de colonnes (pas de hardcode, pas de problèmes de jointures, de commande par, noms de colonnes personnalisés, etc.) et ensuite pour faire une requête elle-même et combiner des 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
5
user3037511

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 des en-têtes dans mon fichier CSV est la suivante:

  1. Utiliser la requête OUTFILE pour préparer un fichier sans en-tête

        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 la table utilisée 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 paquet prepend-file npm

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

3
rahul shukla

Ceci est une alternative si vous êtes familier avec Python ou R et que votre table peut tenir dans la mémoire. 

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

Voici comment je 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 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 fichier CSV. Vous voudrez donc supprimer cette colonne si vous devez vous fier au fichier CSV pour recréer la table.

3
Joining Dots

Puisque la fonctionnalité "include-headers" ne semble pas encore être intégrée, et que la plupart des "solutions" ici nécessitent de taper les noms des colonnes manuellement et/ou ne prennent même pas les jointures en compte, 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 clic droit et exportez-le dans un fichier. Il dispose de toutes les options nécessaires pour une exportation propre et répond à la plupart des besoins.

  • Dans la même idée, l'approche de user3037511 fonctionne bien et peut être automatisé 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 limite, à vous de choisir.

    Notez que la redirection de sortie vers un fichier fonctionne comme un charme 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 ( absence d'une "option d'en-tête", sur un AWS-RDS, des droits manquants, etc.)

Par conséquent, je ne réponds pas exactement à la question question ... mais elle devrait répondre à ses besoins:)
EDIT: et pour réellement répondre à sa question: non
À compter du 07/09/2017, vous ne pouvez tout simplement pas inclure les en-têtes si vous vous en tenez à la commande SELECT INTO OUTFILE
: |

1
Balmipour

Ainsi, si toutes les colonnes dans my_table sont un type de données de caractère , nous pouvons combiner les principales réponses (par Joe, matt et evilguc) pour obtenir l'en-tête ajouté automatiquement dans une "simple" requête SQL, 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 constituent le csv de sortie.

Notez que cela peut être lent si my_table est très gros.

1
TheBamf

un exemple tiré de ma base de données nom de table sensor with colums (id, time, 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
1
Dayanand SK

J'écrivais mon code en PHP, et j'ai eu un peu de difficulté à utiliser les fonctions concat et union, et je n'ai pas non plus utilisé de variables SQL.

//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);
0
user5671922

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

Toutefois, si vous n'avez pas configuré votre "secure_file_priv" dans les variables, il est possible que cela ne fonctionne pas. Pour cela, vérifiez le dossier défini sur cette variable par:

SHOW VARIABLES LIKE "secure_file_priv"

Le résultat 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.

0
RGregg

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

Entrez votre nom de base de données et vos 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 que ce soit le répertoire dans lequel vous souhaitez sortir. MySQL doit avoir la possibilité 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 exec à GZip le CSV.

0
Kohjah Breese

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

Il suffit de quelques astuces dans l’instruction order by - 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 (évidemment, cela dépend du type de champ et du type de champ sélectionné.) DESC)

Supposons que vous ayez trois champs, name (varchar), is_active (bool), date_something_happens (date) et que vous souhaitiez trier les deux autres 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
0
Simon Woolf

Je pense que si vous utilisez une 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.

0
Paul W

Voici un moyen d'obtenir les titres des en-têtes à 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;
0
RNickMcCandless