¿Incluir encabezados al usar SELECT INTO OUTFILE?

117

¿Es posible incluir los encabezados de alguna manera cuando se usa MySQL INTO OUTFILE?

Brett
fuente

Respuestas:

166

Tendría que codificar esos encabezados usted mismo. Algo como:

SELECT 'ColName1', 'ColName2', 'ColName3'
UNION ALL
SELECT ColName1, ColName2, ColName3
    FROM YourTable
    INTO OUTFILE '/path/outfile'
Joe Stefanelli
fuente
14
Pero no funcionará si hay un ORDER BYen la SELECTcláusula. La línea de encabezado puede estar en cualquier lugar del archivo generado según el orden.
Bobina
Vea algunas respuestas a continuación para obtener ideas sobre cómo usar ORDER BY y también la respuesta de Matt para obtener rápidamente todos los ColName1, ColName2, etc. Complementos muy útiles para esta gran respuesta.
Andrew T
1
Esta respuesta parece correcta, diablos, incluso la usé casi a ciegas en mi servidor de desarrollo ... Sin encabezados de columna, se necesitan unos 50 segundos para descargar 240 millones de líneas. Con este UNION ALL, el servidor se está metiendo en grandes problemas al intentar hacer una tabla temporal antes de volcar todo, ¡han pasado más de 10 minutos y todavía están esperando que la tabla temporal se escriba en el disco! ¡Sea consciente de eso! Sin duda, preferiría agregar los nombres de las columnas de otra manera, incluso si eso significa abrir el archivo después con otro lenguaje de programación.
Salketer
Esto solo parece funcionar si todas las columnas de YourTable son un tipo de datos de caracteres, lo cual tiene sentido. De lo contrario, obtendrá el error inútil: "Las instrucciones SELECT utilizadas tienen un número diferente de columnas".
TheBamf
1
Esta es una de las razones por las que estoy considerando cambiarme a otro DBMS.
e18r
85

La solución proporcionada por Joe Steanelli funciona, pero hacer una lista de columnas es inconveniente cuando se trata de decenas o cientos de columnas. Aquí se explica cómo obtener la lista de columnas de la tabla my_table en 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

Ahora puede copiar y pegar la fila resultante como primera declaración en el método de Joe.

mate
fuente
2
Esto devuelve todas las columnas concatenadas en un solo campo. No puedo unir eso con otra declaración de selección que devuelve varios campos. Sin embargo, esto es realmente útil para obtener una línea que pueda copiar y pegar como encabezado de mi archivo de salida.
tmoore82
1
La idea es copiar el campo único resultante y pegarlo en su declaración UNION en lugar de escribir manualmente column1, column2, etc.cuando use el método de Joe (la respuesta aceptada) para que pueda obtener la lista de columnas más rápido.
Andrew T
Estaba buscando exportar todo mi esquema de tabla / campos. ¡Esta respuesta combinada con la aceptada funcionó!
Rémi Breton
@ Chris ORDER BY ORDINAL_POSITIONasas que
mate
1
ORDER BY ORDINAL_POSITION debe ser parte de la llamada GROUP_CONCAT (), como enGROUP_CONCAT(CONCAT('"',COLUMN_NAME,'"') order BY ORDINAL_POSITION)
Apuleius
15

Para la selección compleja con ORDER BY utilizo lo siguiente:

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
fuente
Esta solución funciona bien al solicitar la segunda consulta (compleja); si no lo hace de esta manera, terminará ordenando también la primera columna, lo cual no es deseable. Buena sugerencia @evilguc!
Aaron
No funcionó conmigo, después de hacer UNION ALL, el orden de la columna de identificación está desordenado
Mohanad Kaleia
6

Puede usar la declaración preparada con la respuesta de lucek y exportar dinámicamente la tabla con el nombre de las columnas 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;

Gracias lucek.

Vrag
fuente
6

Esto le permitirá tener columnas ordenadas y / o un límite

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
fuente
1
Solo una nota de que este diseño de consulta también funcionó para mí en MariaDB 10.1; otros diseños sugeridos en este hilo no lo hicieron.
ProgrammerDan
Aparece el encabezado en la parte inferior por alguna razón, pero funciona bien para volver a colocarlo en la parte superior en una aplicación de hoja de cálculo, extraño pero alegre
Dmitri DB
También estoy atascado usando mariaDB. con una extracción de solo 100 clientes potenciales, esto fue más de 14 segundos más rápido que ejecutar la respuesta aceptada. Primer pase con aceptado: Query OK, 100 rows affected (14.72 sec) Segundo pase con el suyoQuery OK, 101 rows affected (0.00 sec)
Casper Wilkes
6

Simplemente hago 2 consultas, primero para obtener el resultado de la consulta (límite 1) con nombres de columna (sin código rígido, sin problemas con Joins, Order by, nombres de columna personalizados, etc.), y segundo para hacer la consulta en sí misma y combinar archivos en un CSV expediente:

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
usuario3037511
fuente
5

Enfrenté un problema similar al ejecutar la consulta mysql en tablas grandes en NodeJS. El enfoque que seguí para incluir encabezados en mi archivo CSV es el siguiente

  1. Utilice la consulta OUTFILE para preparar el archivo sin encabezados

        SELECT * INTO OUTFILE [FILE_NAME] FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED 
        BY '\"' LINES TERMINATED BY '\n' FROM [TABLE_NAME]
  2. Obtener encabezados de columna para la tabla utilizada en el 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. Agregue los encabezados de columna al archivo creado en el paso 1 usando el paquete npm prepend -file

La ejecución de cada paso se controló mediante promesas en NodeJS.

rahul shukla
fuente
3

Este es un truco alternativo si está familiarizado con Python o R, y su tabla puede caber en la memoria.

Importe la tabla SQL a Python o R y luego exporte desde allí como un CSV y obtendrá los nombres de las columnas y los datos.

Así es como lo hago usando R, requiere la biblioteca 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')

Es un poco engañoso, pero descubrí que esta era una solución rápida cuando mi número de columnas era demasiado largo para usar el método concat anterior. Nota: R agregará una columna 'row.names' al comienzo del CSV, por lo que querrá eliminarla si necesita confiar en el CSV para recrear la tabla.

Uniendo puntos
fuente
2

Entonces, si todas las columnas my_tableson de un tipo de datos de caracteres , podemos combinar las respuestas principales (por Joe, matt y evilguc) juntas, para que el encabezado se agregue automáticamente en una consulta SQL 'simple', por ejemplo

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

donde las últimas dos líneas hacen que la salida sea csv.

Tenga en cuenta que esto puede ser lento si my_tablees muy grande.

TheBamf
fuente
tiene el error "Las sentencias SELECT usadas tienen un número diferente de columnas". Sir
Bowei Liu
1

Creo que si usa UNION funcionará:

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

No conozco una forma de especificar los encabezados con la sintaxis INTO OUTFILE directamente.

Paul W
fuente
1
UNION ALL sería más seguro y rápido.
Toxalot
1

En realidad, puede hacer que funcione incluso con un ORDER BY.

Solo necesita algunos trucos en el orden por declaración: usamos una declaración de caso y reemplazamos el valor del encabezado con algún otro valor que se garantiza que se clasificará primero en la lista (obviamente, esto depende del tipo de campo y de si está ordenando ASC o DESC)

Digamos que tiene tres campos, name (varchar), is_active (bool), date_something_happens (date), y desea ordenar los dos segundos en orden descendente:

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
fuente
1

Dado que la funcionalidad 'include-headers' no parece estar incorporada todavía, y la mayoría de las "soluciones" aquí necesitan escribir los nombres de las columnas manualmente y / o ni siquiera tener en cuenta las uniones, recomiendo solucionar el problema .

  • La mejor alternativa que encontré hasta ahora es usar una herramienta decente (yo uso HeidiSQL ).
    Ponga su solicitud, seleccione la cuadrícula, simplemente haga clic derecho y exporte a un archivo. Tiene todas las opciones necesarias para una exportación limpia, y debería manejar la mayoría de las necesidades.

  • En la misma idea, el enfoque de user3037511 funciona bien y se puede automatizar fácilmente .
    Simplemente inicie su solicitud con alguna línea de comando para obtener sus encabezados. Puede obtener los datos con un SELECT INTO OUTFILE ... o ejecutando su consulta sin el límite, el suyo para elegir.

    Tenga en cuenta que la redirección de salida a un archivo funciona a la perfección tanto en Linux como en Windows.


Esto me hace querer resaltar que el 80% de las veces, cuando quiero usar SELECT FROM INFILE o SELECT INTO OUTFILE, termino usando algo más debido a algunas limitaciones (aquí, la ausencia de 'opciones de encabezados', en un AWS-RDS, los derechos que faltan, etc.)

Por lo tanto, no respondo exactamente a la pregunta del operador ... pero debería responder a sus necesidades :)
EDITAR: y realmente responder a su pregunta: no
A partir del 2017-09-07, simplemente no puede incluir encabezados si seguir con el comando SELECT INTO OUTFILE
: |

Balmipour
fuente
1

un ejemplo de mi sensor de nombre de tabla de base de datos con columnas (id, tiempo, unidad)

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
fuente
0

Estaba escribiendo mi código en PHP, y tuve un poco de problema al usar las funciones concat y union, y tampoco usé variables SQL, de cualquier manera que lo hice funcionar, aquí está mi código:

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

A continuación, se muestra una forma de obtener los títulos de encabezado de los nombres de las columnas de forma dinámica.

/* 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
fuente
1
Toda una solución debería decir. Lo adopté para mis propósitos. ¡Gracias!
Denis Kulagin
0

Me gustaría agregar a la respuesta proporcionada por Sangam Belose. Aquí está su código:

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

Sin embargo, si no ha configurado su "secure_file_priv"dentro de las variables, es posible que no funcione. Para eso, verifique la carpeta establecida en esa variable por:

SHOW VARIABLES LIKE "secure_file_priv"

La salida debería verse así:

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)

Puede cambiar esta variable o cambiar la consulta para generar el archivo en la ruta predeterminada que se muestra.

RGregg
fuente
0

MySQL por sí solo no es suficiente para hacer esto simplemente. A continuación se muestra un script PHP que generará columnas y datos en CSV.

Ingrese el nombre de su base de datos y las tablas cerca de la parte superior.

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

?>

Necesitará que este sea el directorio al que le gustaría enviar la salida. MySQL debe tener la capacidad de escribir en el directorio.

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

Puede editar las opciones de exportación de CSV en la consulta:

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

Al final hay una llamada ejecutiva a GZip el CSV.

Kohjah Breese
fuente
-1
SELECCIONE 'ColName1', 'ColName2', 'ColName3'
UNIÓN TODOS
SELECCIONE ColName1, ColName2, ColName3
    DE YourTable
    INTO OUTFILE 'c: \\ datasheet.csv' CAMPOS TERMINADOS POR ',' OPCIONALMENTE ENCERRADOS POR '"' LÍNEAS TERMINADAS POR '\ n' 
manoj singh
fuente