Header einschließen, wenn SELECT INTO OUTFILE verwendet wird?

117

Ist es möglich, die Header bei Verwendung von MySQL irgendwie einzuschließen INTO OUTFILE?

Brett
quelle

Antworten:

166

Sie müssten diese Header selbst hart codieren. Etwas wie:

SELECT 'ColName1', 'ColName2', 'ColName3'
UNION ALL
SELECT ColName1, ColName2, ColName3
    FROM YourTable
    INTO OUTFILE '/path/outfile'
Joe Stefanelli
quelle
14
Aber es wird nicht funktionieren, wenn es eine ORDER BYin der SELECTKlausel gibt. Die Kopfzeile kann sich je nach Reihenfolge an einer beliebigen Stelle in der generierten Datei befinden.
COil
In den folgenden Antworten finden Sie Ideen zur Verwendung von ORDER BY sowie in der Antwort von matt, wie Sie schnell alle ColName1, ColName2 usw. erhalten können. Sehr nützliche Add-Ons zu dieser großartigen Antwort!
Andrew T
1
Diese Antwort scheint ungefähr richtig zu sein, zum Teufel, ich habe sie sogar fast blind auf meinem Entwicklungsserver verwendet ... Ohne Spaltenüberschriften dauert es ungefähr 50 Sekunden, um 240 Millionen Zeilen zu löschen. Mit dieser UNION ALL gerät der Server in große Probleme beim Versuch, eine temporäre Tabelle zu erstellen, bevor alles ausgegeben wird. Es ist jetzt über 10 Minuten her und wartet immer noch darauf, dass die temporäre Tabelle auf die Festplatte geschrieben wird! Sei dir dessen bewusst! Sie würden es sicherlich vorziehen, die Spaltennamen auf eine andere Weise hinzuzufügen, auch wenn dies bedeutet, dass die Datei anschließend mit einer anderen Programmiersprache geöffnet wird.
Salketer
Dies scheint nur zu funktionieren, wenn alle Spalten von YourTable ein Zeichendatentyp sind, was sinnvoll ist. Andernfalls wird der nicht hilfreiche Fehler "Die verwendeten SELECT-Anweisungen haben eine andere Anzahl von Spalten" angezeigt.
TheBamf
1
Dies ist einer der Gründe, warum ich erwäge, zu einem anderen DBMS zu wechseln.
e18r
85

Die von Joe Steanelli bereitgestellte Lösung funktioniert, aber das Erstellen einer Liste von Spalten ist unpraktisch, wenn Dutzende oder Hunderte von Spalten beteiligt sind. Hier erfahren Sie , wie Sie die Spaltenliste der Tabelle my_table in my_schema abrufen .

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

Jetzt können Sie die resultierende Zeile als erste Anweisung in Joes Methode kopieren und einfügen.

matt
quelle
2
Dies gibt alle in einem einzigen Feld verketteten Spalten zurück. Ich kann das nicht mit einer anderen select-Anweisung verbinden, die mehrere Felder zurückgibt. Dies ist sehr nützlich, um eine Zeile zu erhalten, die ich kopieren und als Kopfzeile meiner Outfile einfügen kann.
tmoore82
1
Die Idee ist, das resultierende einzelne Feld zu kopieren und in Ihre UNION-Anweisung einzufügen, anstatt Spalte1, Spalte2 usw. manuell einzugeben, wenn Sie Joes Methode (die akzeptierte Antwort) verwenden, damit Sie die Liste der Spalten schneller erhalten!
Andrew T
Ich wollte alle meine Tabellen- / Feldschemata exportieren. Diese Antwort in Kombination mit der akzeptierten hat es geschafft!
Rémi Breton
@ Chris ORDER BY ORDINAL_POSITIONkümmert sich darum
Matt
1
ORDER BY ORDINAL_POSITION sollte wie in Teil des Aufrufs GROUP_CONCAT () sein GROUP_CONCAT(CONCAT('"',COLUMN_NAME,'"') order BY ORDINAL_POSITION)
Apuleius
15

Für die komplexe Auswahl mit ORDER BY verwende ich Folgendes:

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
quelle
Diese Lösung funktioniert gut, wenn Sie die zweite (komplexe) Abfrage bestellen. Wenn Sie dies nicht auf diese Weise tun, bestellen Sie am Ende auch die erste Spalte, was unerwünscht ist. Netter Vorschlag @evilguc!
Aaron
Hat nicht mit mir gearbeitet, nachdem ich UNION ALL gemacht habe, ist die Reihenfolge der ID-Spalten durcheinander
Mohanad Kaleia
6

Sie können eine vorbereitete Anweisung mit der Antwort von lucek verwenden und eine dynamische Tabelle mit dem Spaltennamen in CSV exportieren:

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

Danke lucek.

Vrag
quelle
6

Dadurch können Sie Spalten und / oder ein Limit bestellt haben

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
quelle
1
Nur eine Anmerkung, dass dieses Abfragelayout auch in MariaDB 10.1 für mich funktioniert hat; andere in diesem Thread vorgeschlagene Layouts haben dies nicht getan.
ProgrammerDan
Öffnet den Header aus irgendeinem Grund unten, funktioniert aber gut, um ihn in einer Tabellenkalkulations-App wieder oben zu platzieren. Seltsam, aber Prost
Dmitri DB
Ich stecke auch mit mariaDB fest. Mit einer Extraktion von nur 100 Leads war dies über 14 Sekunden schneller als das Ausführen der akzeptierten Antwort. Erster Durchgang mit akzeptiert: Query OK, 100 rows affected (14.72 sec) Zweiter Durchgang mit IhremQuery OK, 101 rows affected (0.00 sec)
Casper Wilkes
6

Ich mache einfach 2 Abfragen, erstens, um eine Abfrageausgabe (Limit 1) mit Spaltennamen (kein Hardcode, keine Probleme mit Joins, Sortieren nach, benutzerdefinierten Spaltennamen usw.) zu erhalten, und zweitens, um eine Abfrage selbst durchzuführen und Dateien in einer CSV zu kombinieren Datei:

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
quelle
5

Beim Ausführen der MySQL-Abfrage für große Tabellen in NodeJS trat ein ähnliches Problem auf. Der Ansatz, mit dem ich Header in meine CSV-Datei aufgenommen habe, ist wie folgt

  1. Verwenden Sie die Abfrage OUTFILE, um eine Datei ohne Header vorzubereiten

        SELECT * INTO OUTFILE [FILE_NAME] FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED 
        BY '\"' LINES TERMINATED BY '\n' FROM [TABLE_NAME]
  2. Rufen Sie die Spaltenüberschriften für die in Punkt 1 verwendete Tabelle ab

        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. Hängen Sie die Spaltenüberschriften an die in Schritt 1 erstellte Datei mit an Paket npm " prepend-file" erstellt wurde

Die Ausführung jedes Schritts wurde unter Verwendung von Versprechungen in NodeJS gesteuert.

rahul shukla
quelle
3

Dies ist ein alternativer Cheat, wenn Sie mit Python oder R vertraut sind und Ihre Tabelle in den Speicher passen kann.

Importieren Sie die SQL-Tabelle in Python oder R und exportieren Sie sie von dort als CSV. Sie erhalten dann die Spaltennamen sowie die Daten.

So mache ich es mit R, erfordert die RMySQL-Bibliothek:

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 ist ein kleiner Betrug, aber ich fand, dass dies eine schnelle Problemumgehung war, als meine Anzahl von Spalten zu lang war, um die oben beschriebene Concat-Methode zu verwenden. Hinweis: R fügt am Anfang der CSV eine Spalte 'row.names' hinzu, sodass Sie diese Spalte löschen möchten, wenn Sie sich beim Neuerstellen der Tabelle auf die CSV verlassen müssen.

Punkte verbinden
quelle
2

Also, wenn alle Spalten in my_tableeinem Zeichendatentyp sind , können wir die Top-Antworten (von Joe, matt und evilguc) miteinander zu verknüpfen, wird der Header automatisch in einer ‚einfachen‘ SQL - Abfrage hinzugefügt werden, zB

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

wo die letzten paar Zeilen die Ausgabe csv machen.

Beachten Sie, dass dies langsam sein kann, wenn my_tablees sehr groß ist.

TheBamf
quelle
Es hat den Fehler "Die verwendeten SELECT-Anweisungen haben eine andere Anzahl von Spalten". Sir
Bowei Liu
1

Ich denke, wenn Sie eine UNION verwenden, wird es funktionieren:

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

Ich kenne keine Möglichkeit, die Header mit der INTO OUTFILE-Syntax direkt anzugeben.

Paul W.
quelle
1
UNION ALL wäre sicherer und schneller.
Toxalot
1

Eigentlich können Sie es sogar mit einem ORDER BY zum Laufen bringen.

Benötigt nur einige Tricks in der Reihenfolge nach Anweisung - wir verwenden eine case-Anweisung und ersetzen den Header-Wert durch einen anderen Wert, der garantiert zuerst in der Liste sortiert wird (dies hängt natürlich vom Feldtyp ab und davon, ob Sie ASC oder sortieren) DESC)

Angenommen, Sie haben drei Felder, name (varchar), is_active (bool), date_something_happens (date), und Sie möchten die zweiten beiden absteigend sortieren:

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

Da die Funktion "Include-Header" noch nicht integriert zu sein scheint und die meisten "Lösungen" hier die Spaltennamen manuell eingeben und / oder Verknüpfungen nicht einmal berücksichtigen müssen, würde ich empfehlen das Problem umgehen .

  • Die beste Alternative, die ich bisher gefunden habe, ist die Verwendung eines anständigen Tools (ich verwende HeidiSQL ).
    Stellen Sie Ihre Anfrage, wählen Sie das Raster aus, klicken Sie mit der rechten Maustaste und exportieren Sie es in eine Datei. Es hat alle notwendigen Optionen für einen sauberen Export und sollte die meisten Anforderungen erfüllen.

  • In der gleichen Idee funktioniert der Ansatz von user3037511 einwandfrei und kann einfach automatisiert werden .
    Starten Sie einfach Ihre Anfrage mit einer Befehlszeile , um Ihre Header zu erhalten. Sie können die Daten mit einem SELECT INTO OUTFILE abrufen ... oder indem Sie Ihre Abfrage ohne das Limit ausführen, das Sie auswählen können.

    Beachten Sie, dass die Umleitung der Ausgabe in eine Datei sowohl unter Linux als auch unter Windows wie ein Zauber wirkt.


Aus diesem Grund möchte ich hervorheben, dass ich in 80% der Fälle, wenn ich SELECT FROM INFILE oder SELECT INTO OUTFILE verwenden möchte, am Ende etwas anderes verwende aufgrund einiger Einschränkungen (hier das Fehlen von "Header-Optionen") ein AWS-RDS, die fehlenden Rechte usw.)

Daher kann genau beantworten , die ich nicht auf die op Frage ... aber es sollte seine Antwort Bedürfnisse :)
EDIT: und tatsächlich seine Frage zu beantworten: Nein
Ab 2017.09.07, die Sie gerade nicht Header enthalten können , wenn Sie Halten Sie sich an den Befehl SELECT INTO OUTFILE
: |

Balmipour
quelle
1

ein Beispiel aus meiner Datenbank Tabellenname Sensor mit colums (id, Zeit, Einheit)

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

Ich habe meinen Code in PHP geschrieben, und ich hatte ein paar Probleme mit der Verwendung von Concat- und Union-Funktionen und habe auch keine SQL-Variablen verwendet.

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

Hier ist eine Möglichkeit, die Headertitel dynamisch aus den Spaltennamen abzurufen.

/* 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
quelle
1
Eine ziemliche Lösung sollte ich sagen. Adoptierte es für meine Zwecke. Vielen Dank!
Denis Kulagin
0

Ich möchte die Antwort von Sangam Belose ergänzen. Hier ist sein 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

Wenn Sie Ihre "secure_file_priv"Variablen jedoch nicht eingerichtet haben , funktioniert dies möglicherweise nicht. Überprüfen Sie dazu den Ordner, der für diese Variable festgelegt wurde, indem Sie:

SHOW VARIABLES LIKE "secure_file_priv"

Die Ausgabe sollte folgendermaßen aussehen:

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)

Sie können diese Variable entweder ändern oder die Abfrage ändern, um die Datei in den angezeigten Standardpfad auszugeben.

RGregg
quelle
0

MySQL allein reicht nicht aus, um dies einfach zu tun. Unten finden Sie ein PHP-Skript, das Spalten und Daten an CSV ausgibt.

Geben Sie oben Ihren Datenbanknamen und Ihre Tabellen ein.

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

?>

Dies muss das Verzeichnis sein, in das Sie ausgeben möchten. MySQL muss in der Lage sein, in das Verzeichnis zu schreiben.

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

Sie können die CSV-Exportoptionen in der Abfrage bearbeiten:

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

Am Ende gibt es einen Exec-Aufruf an GZip der CSV.

Kohjah Breese
quelle
-1
SELECT 'ColName1', 'ColName2', 'ColName3'
UNION ALL
SELECT ColName1, ColName2, ColName3
    VON YourTable
    IN OUTFILE 'c: \\ datasheet.csv' FELDER BEENDET VON ',' OPTIONAL UMGEBEN VON '"' LINIEN BEENDET VON '\ n' 
Manoj Singh
quelle