Incluir cabeçalhos ao usar SELECT INTO OUTFILE?

117

É possível incluir os cabeçalhos de alguma forma ao usar o MySQL INTO OUTFILE?

Brett
fonte

Respostas:

166

Você mesmo teria que codificar esses cabeçalhos. Algo como:

SELECT 'ColName1', 'ColName2', 'ColName3'
UNION ALL
SELECT ColName1, ColName2, ColName3
    FROM YourTable
    INTO OUTFILE '/path/outfile'
Joe Stefanelli
fonte
14
Mas não funcionará se houver um ORDER BYna SELECTcláusula. A linha de cabeçalho pode estar em qualquer lugar no arquivo gerado, dependendo do pedido.
Bobina de
Veja algumas respostas abaixo para idéias sobre como usar ORDER BY e também a resposta de matt para uma maneira de obter rapidamente todos os ColName1, ColName2, etc. Complementos muito úteis para esta ótima resposta!
Andrew T,
1
Esta resposta parece certa, diabos, eu até usei quase cegamente no meu servidor de desenvolvimento ... Sem cabeçalhos de coluna, leva cerca de 50 segundos para despejar 240 milhões de linhas. Com este UNION ALL, o servidor está tendo grandes problemas tentando fazer uma tabela temporária antes de despejar tudo, já se passaram mais de 10 minutos e ainda está esperando que a tabela temporária seja gravada no disco! Esteja ciente disso! Você certamente prefere adicionar os nomes das colunas de outra maneira, mesmo que isso signifique abrir o arquivo depois com outra linguagem de programação.
Salketer
Isso só parece funcionar se todas as colunas de YourTable forem um tipo de dados de caractere, o que faz sentido. Caso contrário, você obterá o erro inútil: "As instruções SELECT usadas têm um número diferente de colunas".
TheBamf
1
Este é um dos motivos pelos quais estou pensando em mudar para outro DBMS.
e18r
85

A solução fornecida por Joe Steanelli funciona, mas fazer uma lista de colunas é inconveniente quando dezenas ou centenas de colunas estão envolvidas. Veja como obter a lista da tabela coluna my_table em 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

Agora você pode copiar e colar a linha resultante como primeira instrução no método de Joe.

mate
fonte
2
Isso retorna todas as colunas concatenadas em um único campo. Não consigo unir isso com outra instrução select que retorna vários campos. Isso é realmente útil para obter uma linha que posso copiar e colar como o cabeçalho do meu arquivo de saída.
tmoore82 de
1
A ideia é copiar o único campo resultante e colá-lo em sua instrução UNION em vez de digitar manualmente coluna1, coluna2, etc. ao usar o método de Joe (a resposta aceita) para que você possa obter a lista de colunas mais rápido!
Andrew T
Eu queria exportar todo o meu esquema de tabela / campos. Esta resposta combinada com a aceita fez o truque!
Rémi Breton
@Chris ORDER BY ORDINAL_POSITIONcuida disso
matt
1
ORDER BY ORDINAL_POSITION deve fazer parte da chamada GROUP_CONCAT (), como emGROUP_CONCAT(CONCAT('"',COLUMN_NAME,'"') order BY ORDINAL_POSITION)
Apuleius
15

Para a seleção complexa com ORDER BY, eu uso o seguinte:

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
fonte
Essa solução funciona bem ao solicitar a segunda consulta (complexa); se você não fizer assim, acabará ordenando a primeira coluna também, o que é indesejável. Boa sugestão @evilguc!
Aaron
Não funcionou comigo, depois de fazer UNION ALL a ordem da coluna id está bagunçada
Mohanad Kaleia
6

Você pode usar a declaração preparada com a resposta de Lucek e exportar dinamicamente a tabela com o nome das colunas em 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;

Obrigado, lucek.

Vrag
fonte
6

Isso permitirá que você tenha colunas ordenadas e / ou um 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
fonte
1
Apenas uma observação de que esse layout de consulta funcionou para mim no MariaDB 10.1 também; outros layouts sugeridos neste tópico não.
ProgrammerDan
Aparece o cabeçalho na parte inferior por algum motivo, mas funciona bem para colocá-lo de volta no topo em um aplicativo de planilha, estranho, mas alegre
Dmitri DB
Estou preso usando o mariaDB também. com uma extração de apenas 100 derivações, isso foi 14 segundos mais rápido do que executar a resposta aceita. Primeiro passe com aceito: Query OK, 100 rows affected (14.72 sec) Segundo passe com o seuQuery OK, 101 rows affected (0.00 sec)
Casper Wilkes
6

Eu simplesmente faço 2 consultas, primeiro para obter a saída da consulta (limite 1) com nomes de coluna (sem hardcode, sem problemas com associações, ordenar por, nomes de colunas personalizados, etc) e, em segundo lugar, para fazer a própria consulta e combinar arquivos em um CSV Arquivo:

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
user3037511
fonte
5

Eu enfrentei um problema semelhante ao executar a consulta mysql em grandes tabelas no NodeJS. A abordagem que segui para incluir cabeçalhos em meu arquivo CSV é a seguinte

  1. Use a consulta OUTFILE para preparar o arquivo sem cabeçalhos

        SELECT * INTO OUTFILE [FILE_NAME] FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED 
        BY '\"' LINES TERMINATED BY '\n' FROM [TABLE_NAME]
  2. Buscar cabeçalhos de coluna para a tabela usada no ponto 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. Anexe os cabeçalhos das colunas ao arquivo criado na etapa 1 usando o pacote npm prepend -file

A execução de cada etapa foi controlada por meio de promessas em NodeJS.

rahul shukla
fonte
3

Este é um cheat alternativo se você estiver familiarizado com Python ou R, e sua tabela cabe na memória.

Importe a tabela SQL para Python ou R e, em seguida, exporte de lá como um CSV e você obterá os nomes das colunas, bem como os dados.

Veja como faço isso usando R, requer a 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')

É uma espécie de trapaça, mas descobri que essa era uma solução rápida quando meu número de colunas era muito longo para usar o método concat acima. Nota: R adicionará uma coluna 'row.names' no início do CSV, então você vai querer descartá-la se precisar contar com o CSV para recriar a tabela.

Pontos de união
fonte
2

Portanto, se todas as colunas em my_tablesão um tipo de dados de caractere , podemos combinar as principais respostas (por Joe, matt e evilguc) juntas, para obter o cabeçalho adicionado automaticamente em uma consulta SQL 'simples', por exemplo

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

onde as últimas linhas tornam a saída csv.

Observe que isso pode ser lento se my_tablefor muito grande.

TheBamf
fonte
tem o erro "As instruções SELECT usadas têm um número diferente de colunas". Senhor
Bowei Liu
1

Acho que se você usar um UNION vai funcionar:

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

Não conheço uma maneira de especificar os cabeçalhos com a sintaxe INTO OUTFILE diretamente.

Paul W
fonte
1
UNION ALL seria mais seguro e rápido.
toxalot
1

Na verdade, você pode fazer isso funcionar mesmo com um ORDER BY.

Só precisa de alguns truques na ordem por instrução - usamos uma instrução case e substituímos o valor do cabeçalho por algum outro valor que é garantido para classificar primeiro na lista (obviamente, isso depende do tipo de campo e se você está classificando ASC ou DESC)

Digamos que você tenha três campos, nome (varchar), is_active (bool), date_something_happens (date), e deseja classificar os dois segundos em ordem decrescente:

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

Uma vez que a funcionalidade de 'incluir-cabeçalhos' ainda não parece estar embutida, e a maioria das "soluções" aqui precisam digitar os nomes das colunas manualmente e / ou nem mesmo levar as junções em consideração, eu recomendo contornar o problema .

  • A melhor alternativa que encontrei até agora é usar uma ferramenta decente (eu uso o HeidiSQL ).
    Coloque sua solicitação, selecione a grade, basta clicar com o botão direito e exportar para um arquivo. Ele tem todas as opções necessárias para uma exportação limpa, e deve atender à maioria das necessidades.

  • Na mesma ideia, a abordagem do user3037511 funciona bem e pode ser automatizada facilmente .
    Basta iniciar sua solicitação com alguma linha de comando para obter seus cabeçalhos. Você pode obter os dados com um SELECT INTO OUTFILE ... ou executando sua consulta sem limite, à sua escolha.

    Observe que o redirecionamento de saída para um arquivo funciona perfeitamente no Linux E no Windows.


Isso me faz querer destacar que 80% das vezes, quando eu quero usar SELECT FROM INFILE ou SELECT INTO OUTFILE, acabo usando outra coisa devido a algumas limitações (aqui, a ausência de 'opções de cabeçalhos', em um AWS-RDS, os direitos ausentes e assim por diante.)

Por isso, eu não exatamente responder à da op pergunta ... mas deve responder a necessidades :)
EDIT: e para realmente responder a sua pergunta:
a partir de 2017/09/07, você simplesmente não pode incluir cabeçalhos se continue com o comando SELECT INTO OUTFILE
: |

Balmipour
fonte
1

um exemplo do meu sensor de nome de tabela de banco de dados com colunas (id, tempo, unidade)

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

Eu estava escrevendo meu código em PHP e tive alguns problemas para usar as funções concat e união, e também não usei variáveis ​​SQL, de qualquer maneira que fiz isso funcionar, aqui está o meu 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);
user5671922
fonte
0

Esta é uma maneira de obter os títulos dos cabeçalhos dos nomes das colunas 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
fonte
1
Devo dizer que é uma boa solução. Adotei para meus propósitos. Obrigado!
Denis Kulagin
0

Eu gostaria de acrescentar algo à resposta fornecida por Sangam Belose. Aqui está seu 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

No entanto, se você não configurou seu "secure_file_priv"nas variáveis, pode não funcionar. Para isso, verifique a pasta definida nessa variável:

SHOW VARIABLES LIKE "secure_file_priv"

A saída deve ser semelhante a esta:

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)

Você pode alterar essa variável ou alterar a consulta para enviar o arquivo para o caminho padrão mostrado.

RGregg
fonte
0

O MySQL sozinho não é suficiente para fazer isso de forma simples. Abaixo está um script PHP que produzirá colunas e dados em CSV.

Insira o nome do banco de dados e as tabelas perto do topo.

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

?>

Você precisará que este seja o diretório para o qual deseja enviar a saída. O MySQL precisa ter a capacidade de gravar no diretório.

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

Você pode editar as opções de exportação de CSV na consulta:

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

No final, há uma chamada exec para GZip, o CSV.

Kohjah Breese
fonte
-1
SELECIONE 'ColName1', 'ColName2', 'ColName3'
UNION ALL
SELECIONE ColName1, ColName2, ColName3
    DE YourTable
    INTO OUTFILE 'c: \\ datasheet.csv' CAMPOS TERMINADOS POR ',' OPCIONALMENTE CONCLUÍDO POR '"' LINHAS TERMINADAS POR '\ n' 
manoj singh
fonte