Includere le intestazioni quando si utilizza SELECT INTO OUTFILE?


117

È possibile includere le intestazioni in qualche modo quando si utilizza MySQL INTO OUTFILE?

Risposte:


166

Dovresti codificare manualmente quelle intestazioni. Qualcosa di simile a:

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

14
Ma non funziona se c'è una ORDER BYnella SELECTclausola. La riga di intestazione può trovarsi ovunque nel file generato a seconda dell'ordine.
Bobina

Vedi alcune risposte di seguito per idee sull'uso di ORDER BY e anche la risposta di matt per un modo per ottenere rapidamente tutti i ColName1, ColName2, ecc. Componenti aggiuntivi molto utili per questa ottima risposta!
Andrew T

1
Questa risposta sembra corretta, diavolo l'ho persino usata quasi alla cieca sul mio server di sviluppo ... Senza intestazioni di colonna, ci vogliono circa 50 secondi per scaricare 240 milioni di righe. Con questo UNION ALL, il server sta incontrando grossi problemi nel tentativo di creare una tabella temporanea prima di scaricare tutto, sono passati più di 10 minuti e ancora in attesa che la tabella temporanea venga scritta su disco! Sii consapevole di questo! Preferiresti sicuramente aggiungere i nomi delle colonne in un altro modo, anche se ciò significa aprire il file dopo con un altro linguaggio di programmazione.
Salketer

Questo sembra funzionare solo se tutte le colonne di YourTable sono un tipo di dati carattere, il che ha senso. Altrimenti si ottiene l'errore inutile: "Le istruzioni SELECT utilizzate hanno un numero diverso di colonne".
TheBamf

1
Questo è uno dei motivi per cui sto pensando di passare a un altro DBMS.
e18r

85

La soluzione fornita da Joe Steanelli funziona, ma fare un elenco di colonne è scomodo quando sono coinvolte dozzine o centinaia di colonne. Ecco come ottenere l'elenco delle colonne della tabella 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

Ora puoi copiare e incollare la riga risultante come prima istruzione nel metodo di Joe.


2
Restituisce tutte le colonne concatenate insieme in un unico campo. Non riesco a unirlo con un'altra istruzione select che restituisce più campi. Questo è davvero utile per ottenere una riga che posso copiare e incollare come intestazione del mio file di uscita, però.
tmoore82

1
L'idea è di copiare il singolo campo risultante e incollarlo nell'istruzione UNION invece di digitare manualmente colonna1, colonna2, ecc. Quando si utilizza il metodo di Joe (la risposta accettata) in modo da poter ottenere l'elenco delle colonne più rapidamente!
Andrew T

Stavo cercando di esportare tutto il mio schema di tabelle / campi. Questa risposta combinata con quella accettata ha fatto il trucco!
Rémi Breton

@Chris se ne ORDER BY ORDINAL_POSITIONoccupa
matt

1
ORDER BY ORDINAL_POSITION dovrebbe far parte della chiamata GROUP_CONCAT (), come inGROUP_CONCAT(CONCAT('"',COLUMN_NAME,'"') order BY ORDINAL_POSITION)
Apuleius

15

Per complessi selezionare con ORDER BY utilizzo quanto segue:

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';

Questa soluzione funziona bene quando si ordina la seconda query (complessa); se non lo fai in questo modo finirai per ordinare anche la prima colonna, il che è indesiderabile. Bel suggerimento @evilguc!
Aaron

Non ha funzionato con me, dopo aver fatto UNION ALL l'ordine della colonna id è incasinato
Mohanad Kaleia

6

Puoi utilizzare l'istruzione preparata con la risposta di lucek ed esportare dinamicamente la tabella con il nome delle colonne in 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;

Grazie lucek.


6

Questo ti permetterà di avere colonne ordinate e / o un 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';

1
Solo una nota che questo layout di query ha funzionato per me anche in MariaDB 10.1; altri layout suggeriti in questo thread non lo hanno fatto.
ProgrammerDan

Fa apparire l'intestazione in basso per qualche motivo, ma funziona bene per rimetterla in cima in un'app per fogli di calcolo, strano ma applausi
Dmitri DB

Sono bloccato anche usando mariaDB. con un'estrazione di soli 100 lead, questo è stato di oltre 14 secondi più veloce rispetto all'esecuzione della risposta accettata. Primo passaggio con accettato: Query OK, 100 rows affected (14.72 sec) Secondo passaggio con il tuoQuery OK, 101 rows affected (0.00 sec)
Casper Wilkes

6

Faccio semplicemente 2 query, la prima per ottenere l'output della query (limite 1) con i nomi delle colonne (nessun hardcode, nessun problema con i join, Order by, nomi di colonne personalizzati, ecc.) E la seconda per eseguire la query stessa e combinare i file in un CSV file:

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

Ho affrontato un problema simile durante l'esecuzione della query mysql su tabelle di grandi dimensioni in NodeJS. L'approccio che ho seguito per includere le intestazioni nel mio file CSV è il seguente

  1. Utilizza la query OUTFILE per preparare il file senza intestazioni

        SELECT * INTO OUTFILE [FILE_NAME] FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED 
        BY '\"' LINES TERMINATED BY '\n' FROM [TABLE_NAME]
  2. Recupera le intestazioni di colonna per la tabella utilizzata al punto 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. Aggiungi le intestazioni di colonna al file creato nel passaggio 1 utilizzando il pacchetto npm prepend-file

L'esecuzione di ogni passaggio è stata controllata utilizzando le promesse in NodeJS.


3

Questo è un trucco alternativo se hai familiarità con Python o R e la tua tabella può entrare nella memoria.

Importa la tabella SQL in Python o R, quindi esporta da lì come CSV e otterrai i nomi delle colonne e i dati.

Ecco come lo faccio usando R, richiede la libreria 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')

È un po 'un trucco, ma ho scoperto che questa era una soluzione rapida quando il mio numero di colonne era troppo lungo per utilizzare il metodo concat sopra. Nota: R aggiungerà una colonna "row.names" all'inizio del CSV, quindi ti consigliamo di eliminarla se devi fare affidamento sul CSV per ricreare la tabella.


2

Quindi, se tutte le colonne in my_tablesono un tipo di dati carattere , possiamo combinare le risposte migliori (di Joe, matt e evilguc) insieme, per ottenere l'intestazione aggiunta automaticamente in una 'semplice' query SQL, ad es.

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';

dove l'ultima coppia di righe crea l'output csv.

Tieni presente che potrebbe essere lento se my_tableè molto grande.


presenta l'errore "Le istruzioni SELECT utilizzate hanno un numero diverso di colonne". Sir
Bowei Liu

1

Penso che se usi UNION funzionerà:

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

Non conosco un modo per specificare direttamente le intestazioni con la sintassi INTO OUTFILE.


1
UNION ALL sarebbe più sicuro e veloce.
toxalot

1

In realtà puoi farlo funzionare anche con ORDER BY.

Ha solo bisogno di qualche trucco nell'istruzione order by - usiamo un'istruzione case e sostituiamo il valore dell'intestazione con qualche altro valore che è garantito per l'ordinamento per primo nell'elenco (ovviamente questo dipende dal tipo di campo e se stai ordinando ASC o DESC)

Supponiamo che tu abbia tre campi, nome (varchar), is_active (bool), date_something_happens (date) e desideri ordinare i secondi due in modo discendente:

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

1

Poiché la funzionalità "include-headers" non sembra essere ancora incorporata e la maggior parte delle "soluzioni" qui devono digitare manualmente i nomi delle colonne e / o non prendere nemmeno in considerazione i join, ti consiglio di aggirare il problema .

  • La migliore alternativa che ho trovato finora è utilizzare uno strumento decente (io uso HeidiSQL ).
    Inserisci la tua richiesta, seleziona la griglia, fai semplicemente clic con il tasto destro ed esporta in un file. Ha tutte le opzioni necessarie per un'esportazione pulita, e dovrebbe gestire la maggior parte delle esigenze.

  • Nella stessa idea, l'approccio di user3037511 funziona bene e può essere automatizzato facilmente .
    Basta avviare la richiesta con una riga di comando per ottenere le intestazioni. È possibile ottenere i dati con SELEZIONA IN OUTFILE ... o eseguendo la query senza limiti, a tua scelta.

    Nota che il reindirizzamento dell'output a un file funziona come un fascino sia su Linux che su Windows.


Ciò mi fa venir voglia di evidenziare che l' 80% delle volte, quando voglio usare SELECT FROM INFILE o SELECT INTO OUTFILE, finisco per usare qualcos'altro causa di alcune limitazioni (qui, l'assenza di 'opzioni intestazioni', su un AWS-RDS, i diritti mancanti e così via.)

Quindi, non rispondo esattamente alla domanda dell'operatore ... ma dovrebbe rispondere alle sue esigenze :)
EDIT: e per rispondere effettivamente alla sua domanda: no
A partire dal 07/09/2017, non puoi includere intestazioni se tu restare con il comando SELECT INTO OUTFILE
: |


1

un esempio dal sensore del nome della tabella del mio database con colonne (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

0

Stavo scrivendo il mio codice in PHP e ho avuto un po 'di problemi nell'usare le funzioni di concatenazione e unione, e inoltre non ho usato le variabili SQL, in alcun modo l'ho fatto funzionare, ecco il mio codice:

//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

Ecco un modo per ottenere dinamicamente i titoli delle intestazioni dai nomi delle colonne.

/* 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;

1
Piuttosto una soluzione dovrei dire. L'ho adottato per i miei scopi. Grazie!
Denis Kulagin

0

Vorrei aggiungere alla risposta fornita da Sangam Belose. Ecco il suo codice:

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

Tuttavia, se non hai impostato il tuo "secure_file_priv"all'interno delle variabili, potrebbe non funzionare. Per questo, controlla la cartella impostata su quella variabile da:

SHOW VARIABLES LIKE "secure_file_priv"

L'output dovrebbe essere simile a questo:

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)

È possibile modificare questa variabile o modificare la query per visualizzare il file nel percorso predefinito visualizzato.


0

MySQL da solo non è sufficiente per farlo semplicemente. Di seguito è riportato uno script PHP che produrrà colonne e dati in CSV.

Immettere il nome del database e le tabelle nella parte superiore.

<?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() );
}

?>

Avrai bisogno che questa sia la directory in cui desideri eseguire l'output. MySQL deve avere la capacità di scrivere nella directory.

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

Puoi modificare le opzioni di esportazione CSV nella query:

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

Alla fine c'è una chiamata exec a GZip il CSV.


-1
SELEZIONA "ColName1", "ColName2", "ColName3"
UNION ALL
SELEZIONA ColName1, ColName2, ColName3
    DA YourTable
    INTO OUTFILE "c: \\ datasheet.csv" FIELDS TERMINATED BY "," OPZIONALMENTE INCLUSO DA "" "LINEE TERMINATE DA" \ n " 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.