Làm cách nào để xuất kết quả truy vấn MySQL ở định dạng CSV?


1183

Có cách nào dễ dàng để chạy truy vấn MySQL từ dòng lệnh Linux và xuất kết quả ở định dạng CSV không?

Đây là những gì tôi đang làm bây giờ:

mysql -u uid -ppwd -D dbname << EOQ | sed -e 's/        /,/g' | tee list.csv
select id, concat("\"",name,"\"") as name
from students
EOQ

Nó trở nên lộn xộn khi có rất nhiều cột cần được bao quanh bởi dấu ngoặc kép hoặc nếu có dấu ngoặc kép trong kết quả cần phải thoát.


1
Bạn có thể sử dụng REPLACE()trong truy vấn của mình để thoát dấu ngoặc kép.
dsm

Hãy xem câu trả lời của tôi trong [stackoverflow này] [1] [1]: stackoverflow.com/questions/12242772/
Kẻ


2
Câu trả lời được chấp nhận cho câu hỏi stackoverflow này có lẽ là cách tốt nhất: stackoverflow.com/questions/3760631/mysql-d006iter-question
Samuel slund

Tôi đã viết một yêu cầu tính năng trên trình theo dõi lỗi MariaDB ( jira.mariadb.org/browse/MDEV-12879 ) Bạn có thể bỏ phiếu cho nó.
Jared Beck

Câu trả lời:


1760

Từ http://www.tech-recipes.com/rx/1475/save-mysql-query-results-into-a-text-or-csv-file/

SELECT order_id,product_name,qty
FROM orders
WHERE foo = 'bar'
INTO OUTFILE '/var/lib/mysql-files/orders.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';

Sử dụng tên cột này tên sẽ không được xuất.

Cũng lưu ý rằng /var/lib/mysql-files/orders.csvsẽ có trên máy chủ đang chạy MySQL. Người dùng mà quá trình MySQL đang chạy phải có quyền ghi vào thư mục đã chọn, nếu không lệnh sẽ thất bại.

Nếu bạn muốn ghi đầu ra vào máy cục bộ của mình từ một máy chủ từ xa (đặc biệt là máy được lưu trữ hoặc ảo hóa như Heroku hoặc Amazon RDS), giải pháp này không phù hợp.


16
@Tomas nếu bạn có quyền truy cập vào một hệ thống tập tin từ xa và MySQL, bạn phải có thể viết ở đâu đó. thay vì / tmp, hãy thử /home/yourusername/file.csv - nếu thất bại và tập kết quả không lớn, bạn có thể sao chép đầu ra từ máy khách SSH và dán vào máy cục bộ của mình.
Michael Butler

63
Câu hỏi chỉ định MySQL, không "tuân thủ tiêu chuẩn".
Paul Tomblin

35
Làm thế nào để bao gồm tiêu đề là tốt?
Bogdan Gusiev

66
@BogdanGusiev, bạn có thể bao gồm tiêu đề bằng cách thêm trước "CHỌN 'order_id', 'Product_name', 'qty' UNION" trước truy vấn thực. Truy vấn đầu tiên chọn trả về tiêu đề, truy vấn thứ hai trả về dữ liệu thực; UNION kết hợp nó với nhau.
petrkotek

19
@Michael Butler: Vâng, không, thực sự. Nếu bạn đang sử dụng Amazon RDS, Heroku hoặc bất kỳ giải pháp lưu trữ nào khác, bạn không thể chỉ viết thư cho máy chủ của người khác.
Ken Kinder

459
$ mysql your_database --password=foo < my_requests.sql > out.csv

Đó là tab tách. Đặt nó như thế để có được một CSV thực sự (cảm ơn @therefromhere):

... .sql | sed 's/\t/,/g' > out.csv

5
không chỉ vậy, mà nó còn cho phép tạo nội dung từ máy chủ cơ sở dữ liệu từ xa, không giống như việc ghi vào hệ thống tệp cục bộ.
tmarthal

31
Nó được phân tách bằng tab, không được phân tách bằng dấu phẩy.
Flimm

13
@Flimm, giả sử bạn không nhúng dấu phẩy / tab vào các trường bạn có thể chuyển đổi nó bằng cách chuyển kết quả vào| sed 's/\t/,/g'
John Carter

111
sed 'fix' không bù cho dấu phẩy có thể xuất hiện trong bất kỳ dữ liệu nào được chọn và sẽ làm lệch các cột của bạn được xuất ra tương ứng
Joey T

14
Sự tiêu cực là hợp lệ .. nó có thể có hiệu quả với bạn bây giờ nhưng nó cũng có thể cắn bạn trong tương lai khi dữ liệu của bạn bao gồm một tab hoặc dấu phẩy, v.v.
John Hunt

204

mys -batch, -B

In kết quả bằng cách sử dụng tab làm dấu tách cột, với mỗi hàng trên một dòng mới. Với tùy chọn này, mysql không sử dụng tệp lịch sử. Chế độ hàng loạt dẫn đến định dạng đầu ra không phải là bảng và thoát các ký tự đặc biệt. Thoát có thể bị vô hiệu hóa bằng cách sử dụng chế độ thô; xem mô tả cho tùy chọn --raw.

Điều này sẽ cung cấp cho bạn một tập tin tách tab. Vì dấu phẩy (hoặc chuỗi chứa dấu phẩy) không được thoát, nên việc thay đổi dấu phân cách thành dấu phẩy không đơn giản.


12
đây là một giải pháp ưa thích: 1) danh sách giá trị được phân tách bằng tab là phổ biến trong UNIX 2) Nhập khẩu TSV được hỗ trợ bởi hầu hết các hệ thống nhập khẩu, bao gồm Excel, Bảng tính OpenOffice, v.v. 3) không cần thoát ký tự trích dẫn cho trường văn bản 4 ) làm cho xuất khẩu dòng lệnh trở nên dễ dàng
Joey T

5
đây là giải pháp tốt nhất vì không giống như người đầu tiên không cần phải có quyền trên các máy chủ như RDS
Muayyad Alsadi

8
Một mẹo nhỏ: nếu bạn lưu tệp được phân tách bằng tab dưới dạng .xls thay vì .csv, nó sẽ mở trong excel mà không cần chuyển đổi "văn bản thành dữ liệu" và không có bất kỳ vấn đề nào về cài đặt khu vực.
serbaut

3
@Joey T - bạn vẫn cần thoát các tab và trả lại vận chuyển. Ngoài ra nếu nội dung của một trường trông giống như một trường được trích dẫn hoặc thoát, thì nội dung được nhập có thể không giống như bản gốc.
mc0e

2
bạn sẽ gặp vấn đề với NULL .. chúng sẽ xuất hiện dưới dạng chuỗi null ..
Jonathan

141

Đây là một cách khá sởn gai ốc để làm điều đó. Tìm thấy nó ở đâu đó, không thể lấy bất kỳ tín dụng

mysql --user=wibble --password wobble -B -e "select * from vehicle_categories;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > vehicle_categories.csv

Hoạt động khá tốt. Một lần nữa mặc dù một regex chứng minh chỉ viết.


Regex Giải thích:

  • s /// có nghĩa là thay thế những gì giữa // đầu tiên bằng những gì giữa // thứ hai
  • "g" ở cuối là một sửa đổi có nghĩa là "tất cả các trường hợp, không chỉ đầu tiên"
  • ^ (trong bối cảnh này) có nghĩa là bắt đầu của dòng
  • $ (trong ngữ cảnh này) có nghĩa là kết thúc dòng

Vì vậy, kết hợp tất cả lại với nhau:

s/'/\'/          replace ' with \'
s/\t/\",\"/g     replace all \t (tab) with ","
s/^/\"/          at the beginning of the line place a "
s/$/\"/          at the end of the line place a "
s/\n//g          replace all \n (newline) with nothing

3
Cờ -e chính xác là những gì tôi đang tìm kiếm! Cảm ơn!
Gaurav Gupta

1
Regex này thực sự khá đơn giản; Giống như rất nhiều câu trả lời khác trên trang này, nó chỉ làm sạch đầu ra từ đó mysql -B. Nếu bạn tách regex thành các câu lệnh riêng lẻ trên các dòng riêng biệt, nó sẽ khá đơn giản (đối với người biết regex) để hiểu.
Mei

7
AT cái nhìn đầu tiên, điều này trông khá bị hỏng. Tab và trả lại vận chuyển trong nội dung sẽ được xử lý sai. "S/'/\'/;" hoàn toàn không làm gì cả, bởi vì dấu ngoặc kép trong lệnh shell sẽ sử dụng dấu gạch chéo ngược. Nhiều lỗi tương tự khác với dấu gạch chéo ngược bị mất. Không xử lý dấu gạch chéo ngược trong trường db.
mc0e

1
Có vẻ như lệnh này hoạt động tốt trên Linux nhưng không có trong Mac
Hemerson Varela

6
Điều này sẽ phá vỡ nếu bạn có một trường văn bản chứa các tab, dấu gạch chéo ngược ","và một số thứ khác. Một regex không phải là cách để giải quyết vấn đề này
Aidan

93

Chỉ Unix / Cygwin , dẫn nó qua 'tr':

mysql <database> -e "<query here>" | tr '\t' ',' > data.csv

NB: Điều này xử lý không dấu phẩy nhúng, cũng không nhúng tab.


53

Điều này đã tiết kiệm cho tôi một vài lần. Nhanh chóng và nó hoạt động!

--batch In kết quả bằng cách sử dụng tab làm dấu tách cột, với mỗi hàng trên một dòng mới.

--raw vô hiệu hóa ký tự thoát (\ n, \ t, \ 0 và \)

Thí dụ:

mysql -udemo_user -p -h127.0.0.1 --port=3306 \
   --default-character-set=utf8mb4 --database=demo_database \
   --batch --raw < /tmp/demo_sql_query.sql > /tmp/demo_csv_export.tsv

Để hoàn thiện, bạn có thể chuyển đổi sang csv (nhưng hãy cẩn thận vì các tab có thể nằm bên trong các giá trị trường - ví dụ: trường văn bản)

tr '\t' ',' < file.tsv > file.csv


4
Trừ khi tôi thiếu một cái gì đó, điều này sẽ tạo ra một tệp TSV, không phải là tệp CSV ...
Nhấn vào

@PressingOnAlways Có. Trích dẫn tài liệu MySQL: "In kết quả bằng cách sử dụng tab làm dấu tách cột, với mỗi hàng trên một dòng mới." Nhưng phân tích cú pháp không phải là một vấn đề với bất kỳ dấu phân cách. Tôi đã sử dụng nó để tạo tập tin excel cho khách hàng của tôi.
hrvoj3e

39

Giải pháp OUTFILE do Paul Tomblin đưa ra khiến một tệp được ghi trên chính máy chủ MySQL, do đó, nó sẽ chỉ hoạt động nếu bạn có quyền truy cập FILE , cũng như truy cập đăng nhập hoặc các phương tiện khác để truy xuất tệp từ hộp đó.

Nếu bạn không có quyền truy cập như vậy và đầu ra được phân định bằng tab là sự thay thế hợp lý cho CSV (ví dụ: nếu mục tiêu cuối cùng của bạn là nhập vào Excel), thì giải pháp của Serbaut (sử dụng mysql --batchvà tùy chọn --raw) là cách phù hợp.


36

MySQL Workbench có thể xuất các bản ghi sang CSV và dường như xử lý dấu phẩy trong các trường rất tốt. CSV mở ra trong OpenOffice tốt.


2
Cảm ơn một triệu David. Sau khi dành 3 giờ để nhận các dòng mới để xuất đúng nội dung HTML trong dữ liệu, tôi đã sử dụng MySQL Workbench và trong 2 phút tôi đã sẵn sàng tệp CSV của mình.
mr-euro

Tôi vừa tìm thấy nó có thể lưu dưới dạng XML, điều này thật tuyệt. Tôi hy vọng di chuyển từ ứng dụng này sang ứng dụng khác bằng cách sử dụng XSLT để chuyển đổi XML này thành tệp CSV phù hợp để nhập vào ứng dụng đích.
David Oliver

bàn làm việc mysql là tùy chọn tốt nhất cho tính năng xuất nhập khẩu.
cijagani

1
Tôi vừa xuất thành công hơn nửa triệu hàng bằng cách sử dụng bàn làm việc mysql nên các tệp lớn dường như không phải là vấn đề. Bạn chỉ cần đảm bảo xóa bỏ giới hạn chọn trước khi chạy truy vấn của mình và bạn cũng có thể phải tăng các giá trị sau trong tệp my.ini của mình: max_allowed_packet = 500M, net_read_timeout = 600, net_write_timeout = 600
Vincent

3
Bàn làm việc của MySQL bị rò rỉ bộ nhớ đáng xấu hổ khi xuất dữ liệu trong CSV, nếu bạn có bộ dữ liệu lớn như 1 hoặc 2 triệu hàng, RAM 12 GB (được thử nghiệm trên máy linux của tôi) là không đủ và bộ nhớ không bị xóa trừ khi bạn giết hoặc dừng nó Đối với tập dữ liệu lớn, đây không phải là một giải pháp.
Ostico

33

Làm thế nào về:

mysql your_database -p < my_requests.sql | awk '{print $1","$2}' > out.csv

2
Tôi thật sự thich cai nay. Nó sạch hơn nhiều, và tôi thích việc sử dụng awk. Tuy nhiên, tôi có thể đã đi với điều này: mysql -uUser -pPassword your_database < my_requests.sql | awk 'BEGIN{OFS="=";} {print $1,$2}' > out.csv
Josh

7
Điều này không thành công cho các giá trị trường với không gian.
Barun Sharma

29

Tất cả các giải pháp ở đây cho đến nay, ngoại trừ bàn làm việc của MySQL, đều không chính xác và hoàn toàn có thể không an toàn (tức là vấn đề bảo mật) đối với ít nhất một số nội dung có thể có trong mysql db.

MYSQL Workbench (và tương tự PHPMyAdmin) cung cấp một giải pháp chính xác, nhưng được thiết kế để tải đầu ra xuống vị trí của người dùng. Chúng không hữu ích cho những thứ như tự động xuất dữ liệu.

Không thể tạo csv chính xác đáng tin cậy từ đầu ra của mysql -B -e 'SELECT ...' bởi vì điều đó không thể mã hóa trả về vận chuyển và khoảng trắng trong các trường. Cờ '-s' cho mysql không thực hiện dấu gạch chéo ngược và có thể dẫn đến một giải pháp chính xác. Tuy nhiên, sử dụng ngôn ngữ kịch bản (một ngôn ngữ có cấu trúc dữ liệu nội bộ phù hợp, không phải bash) và các thư viện nơi các vấn đề mã hóa đã được xử lý cẩn thận sẽ an toàn hơn nhiều.

Tôi đã nghĩ về việc viết một kịch bản cho việc này, nhưng ngay khi tôi nghĩ về những gì tôi gọi nó, nó đã xảy ra với tôi để tìm kiếm tác phẩm có sẵn cùng tên. Mặc dù tôi chưa tìm hiểu kỹ về nó, nhưng giải pháp tại https://github.com/robmiller/mysql2csv có vẻ đầy hứa hẹn. Tùy thuộc vào ứng dụng của bạn, cách tiếp cận yaml để chỉ định các lệnh SQL có thể hoặc có thể không kháng cáo mặc dù. Tôi cũng không thích thú với yêu cầu về phiên bản ruby ​​gần đây hơn là tiêu chuẩn với máy tính xách tay Ubuntu 12.04 hoặc máy chủ Debian Squeeze của tôi. Có tôi biết tôi có thể sử dụng RVM, nhưng tôi không muốn duy trì điều đó cho mục đích đơn giản như vậy.

Hy vọng ai đó sẽ chỉ ra một công cụ phù hợp, đó là một chút thử nghiệm. Nếu không, tôi có thể cập nhật cái này khi tôi tìm hoặc viết nó.


1
Bạn đã đúng, đối với các chuỗi phức tạp trong bảng, bạn phải sử dụng một số thư viện phong nha, không chỉ bash. Tôi nghĩ rằng nodejs có một giải pháp tốt hơn cho loại hành động này. như ví dụ
yeya

1
Xin chào, câu trả lời hay, tôi sẽ thêm một liên kết đến giải pháp python được đề xuất bên dưới stackoverflow.com/a353123787/1504300 , hoạt động tốt và rất đơn giản. Tôi đã cố chỉnh sửa bài đăng của bạn nhưng bản chỉnh sửa đã bị từ chối
thực sự là

26

Nhiều câu trả lời trên trang này là yếu vì chúng không xử lý trường hợp chung về những gì có thể xảy ra ở định dạng CSV. ví dụ: dấu phẩy và dấu ngoặc kép được nhúng trong các trường và các điều kiện khác luôn xuất hiện cuối cùng. Chúng tôi cần một giải pháp chung hoạt động cho tất cả dữ liệu đầu vào CSV hợp lệ.

Đây là một giải pháp đơn giản và mạnh mẽ trong Python:

#!/usr/bin/env python

import csv
import sys

tab_in = csv.reader(sys.stdin, dialect=csv.excel_tab)
comma_out = csv.writer(sys.stdout, dialect=csv.excel)

for row in tab_in:
    comma_out.writerow(row)

Đặt tên cho tệp đó tab2csv, đặt nó trên đường dẫn của bạn, cấp cho nó quyền thực thi, sau đó sử dụng nó như thế này:

mysql OTHER_OPTIONS --batch --execute='select * from whatever;' | tab2csv > outfile.csv

Các hàm xử lý CSV của Python bao gồm các trường hợp góc cho (các) định dạng đầu vào CSV.

Điều này có thể được cải thiện để xử lý các tệp rất lớn thông qua cách tiếp cận phát trực tuyến.


8
Một giải pháp đáng tin cậy hơn nữa là thực sự kết nối với cơ sở dữ liệu với Python, sau đó bạn sẽ có thời gian dễ dàng hơn để làm những gì bạn cần làm để xử lý các bộ dữ liệu lớn hơn (kết quả phân đoạn, phát trực tuyến, v.v.).
Josh Rumbut

@JoshRumbut, thực sự rất muộn, nhưng tôi đã tạo stackoverflow.com/a/41840534/2958070 để bổ sung cho nhận xét của bạn
Ben


17
  1. Hợp lý :

CREATE TABLE () (SELECT data FROM other_table ) ENGINE=CSV ;

Khi bạn tạo bảng CSV, máy chủ sẽ tạo tệp định dạng bảng trong thư mục cơ sở dữ liệu. Tệp bắt đầu bằng tên bảng và có phần mở rộng .frm. Công cụ lưu trữ cũng tạo ra một tệp dữ liệu. Tên của nó bắt đầu bằng tên bảng và có phần mở rộng .CSV. Tệp dữ liệu là một tệp văn bản đơn giản. Khi bạn lưu trữ dữ liệu vào bảng, công cụ lưu trữ sẽ lưu nó vào tệp dữ liệu ở định dạng giá trị được phân tách bằng dấu phẩy.


1
Đẹp vì điều này là chính xác mà không cần bất kỳ điều chỉnh nào khác.
Andrew Schulman

13

Câu trả lời này sử dụng Python và thư viện bên thứ ba phổ biến, PyMySQL . Tôi đang thêm nó bởi vì thư viện csv của Python đủ mạnh để xử lý chính xác nhiều hương vị khác nhau .csvvà không có câu trả lời nào khác đang sử dụng mã Python để tương tác với cơ sở dữ liệu.

import contextlib
import csv
import datetime
import os

# https://github.com/PyMySQL/PyMySQL
import pymysql

SQL_QUERY = """
SELECT * FROM my_table WHERE my_attribute = 'my_attribute';
"""

# embedding passwords in code gets nasty when you use version control
# the environment is not much better, but this is an example
# /programming/12461484
SQL_USER = os.environ['SQL_USER']
SQL_PASS = os.environ['SQL_PASS']

connection = pymysql.connect(host='localhost',
                             user=SQL_USER,
                             password=SQL_PASS,
                             db='dbname')

with contextlib.closing(connection):
    with connection.cursor() as cursor:
        cursor.execute(SQL_QUERY)
        # Hope you have enough memory :)
        results = cursor.fetchall()

output_file = 'my_query-{}.csv'.format(datetime.datetime.today().strftime('%Y-%m-%d'))
with open(output_file, 'w', newline='') as csvfile:
    # http://stackoverflow.com/a/17725590/2958070 about lineterminator
    csv_writer = csv.writer(csvfile, lineterminator='\n')
    csv_writer.writerows(results)

Một câu trả lời sử dụng python đã được cung cấp. stackoverflow.com/a353123787/5470883
Alexander Baltasar

4
@AlexanderBaltasar, phải, và nó có vẻ hữu ích, nhưng nó không sử dụng mã Python để tương tác với cơ sở dữ liệu. Xem bình luận về câu hỏi đó.
Ben

11

Điều này rất đơn giản và nó hoạt động trên mọi thứ mà không cần các chế độ hàng loạt hoặc các tệp đầu ra:

select concat_ws(',',
    concat('"', replace(field1, '"', '""'), '"'),
    concat('"', replace(field2, '"', '""'), '"'),
    concat('"', replace(field3, '"', '""'), '"'))

from your_table where etc;

Giải trình:

  1. Thay thế "bằng ""trong từng lĩnh vực ->replace(field1, '"', '""')
  2. Bao quanh mỗi kết quả trong dấu ngoặc kép -> concat('"', result1, '"')
  3. Đặt dấu phẩy giữa mỗi kết quả được trích dẫn -> concat_ws(',', quoted1, quoted2, ...)

Đó là nó!


1
Lưu ý rằng NULLcác giá trị sẽ bị bỏ qua concat_ws(), dẫn đến sự không khớp cột. Để tránh điều này, chỉ cần sử dụng một chuỗi trống thay thế: IFNULL(field, '')(hoặc bất cứ điều gì khác mà bạn sử dụng để đại diện NULL)
Marco Roy

10

Ngoài ra, với câu trả lời ở trên, bạn có thể có bảng MySQL sử dụng công cụ CSV.

Sau đó, bạn sẽ có một tệp trên đĩa cứng sẽ luôn ở định dạng CSV mà bạn chỉ có thể sao chép mà không cần xử lý.


1
Các giới hạn của điều này về kích thước tập tin / ghi / đọc / vv là gì?
Zach Smith

8

Để mở rộng các câu trả lời trước, một lớp lót sau xuất một bảng dưới dạng tệp được phân tách bằng tab. Nó phù hợp để tự động hóa, xuất cơ sở dữ liệu mỗi ngày hoặc lâu hơn.

mysql -B -D mydatabase -e 'select * from mytable'

Để thuận tiện, chúng ta có thể sử dụng cùng một kỹ thuật để liệt kê các bảng của MySQL và để mô tả các trường trên một bảng:

mysql -B -D mydatabase -e 'show tables'

mysql -B -D mydatabase -e 'desc users'

Field   Type    Null    Key Default Extra
id  int(11) NO  PRI NULL    auto_increment
email   varchar(128)    NO  UNI NULL    
lastName    varchar(100)    YES     NULL    
title   varchar(128)    YES UNI NULL    
userName    varchar(128)    YES UNI NULL    
firstName   varchar(100)    YES     NULL    

4
Để chuyển đổi sang CSV:mysql -B -D mydatabase -e 'select * from mytable' | sed -e 's/\t/,/g'
DSimon

7
Việc sử dụng sed -e 's/\t/,/g'chỉ an toàn nếu bạn chắc chắn rằng dữ liệu của bạn không chứa bất kỳ dấu phẩy hoặc tab nào.
đánh thức

7

Xây dựng trên user7610, đây là cách tốt nhất để làm điều đó. Với mysql outfile60 phút sở hữu tập tin và các vấn đề ghi đè.

Nó không tuyệt, nhưng nó hoạt động trong 5 phút.

php csvdump.php localhost root password database tablename > whatever-you-like.csv

<?php

$server = $argv[1];
$user = $argv[2];
$password = $argv[3];
$db = $argv[4];
$table = $argv[5];

mysql_connect($server, $user, $password) or die(mysql_error());
mysql_select_db($db) or die(mysql_error());

// fetch the data
$rows = mysql_query('SELECT * FROM ' . $table);
$rows || die(mysql_error());


// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');

// output the column headings

$fields = [];
for($i = 0; $i < mysql_num_fields($rows); $i++) {
    $field_info = mysql_fetch_field($rows, $i);
    $fields[] = $field_info->name;
}
fputcsv($output, $fields);

// loop over the rows, outputting them
while ($row = mysql_fetch_assoc($rows)) fputcsv($output, $row);

?>

1
Đẹp, sạch sẽ và hoạt động nhanh chóng - đây là một giải pháp tuyệt vời nếu bạn có thể chạy PHP trong môi trường đó!
John Fiala

7

Ngoài ra, nếu bạn đang thực hiện truy vấn trên dòng lệnh Bash, tôi tin rằng trlệnh có thể được sử dụng để thay thế các tab mặc định thành các dấu phân cách tùy ý.

$ echo "SELECT * FROM Table123" | mysql Database456 | tr "\t" ,


5

Đây là những gì tôi làm:

echo $QUERY | \
  mysql -B  $MYSQL_OPTS | \
  perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^[\d.]+$/ ? $_ : qq("$_")} @F ' | \
  mail -s 'report' person@address

Tập lệnh perl (được cắt từ nơi khác) thực hiện tốt công việc chuyển đổi các trường cách nhau tab thành CSV.


Điều đó thật tuyệt. Cải thiện nhẹ có thể là trích dẫn mọi thứ trừ những con số perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^\d+(?:\.\d+)?$/ ? $_ : qq("$_")} @F '- bạn sẽ không trích dẫn1.2.3
artfulrobot 15/03/2017

5

Không chính xác như định dạng CSV, nhưng teelệnh từ máy khách MySQL có thể được sử dụng để lưu kết quả đầu ra vào một tệp cục bộ :

tee foobar.txt
SELECT foo FROM bar;

Bạn có thể vô hiệu hóa nó bằng cách sử dụng notee.

Vấn đề với SELECT … INTO OUTFILE …;nó là nó đòi hỏi phải có quyền ghi tập tin tại máy chủ.


Nếu phần mở rộng .csv được sử dụng thay vì .txt, có bất kỳ vấn đề định dạng nào cần lưu ý không?
datalifenyc

@myidealab Các vấn đề định dạng phát sinh từ dấu phẩy, v.v. không được thoát. CSV là một định dạng văn bản đơn giản vì vậy không có vấn đề định dạng chỉ từ việc hoán đổi phần mở rộng.
jkmartindale

3

Sử dụng giải pháp được đăng bởi Tim, tôi đã tạo tập lệnh bash này để tạo thuận lợi cho quá trình (mật khẩu gốc được yêu cầu, nhưng bạn có thể sửa đổi tập lệnh dễ dàng để yêu cầu bất kỳ người dùng nào khác):

#!/bin/bash

if [ "$1" == "" ];then
    echo "Usage: $0 DATABASE TABLE [MYSQL EXTRA COMMANDS]"
    exit
fi

DBNAME=$1
TABLE=$2
FNAME=$1.$2.csv
MCOMM=$3

echo "MySQL password:"
stty -echo
read PASS
stty echo

mysql -uroot -p$PASS $MCOMM $DBNAME -B -e "SELECT * FROM $TABLE;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > $FNAME

Nó sẽ tạo một tệp có tên: database.table.csv


3

Nếu bạn đã thiết lập PHP trên máy chủ, bạn có thể sử dụng mysql2csv để xuất tệp CSV (thực sự hợp lệ) cho truy vấn mysql bắt buộc. Xem câu trả lời của tôi tại MySQL - CHỌN * VÀO ĐỊA ĐIỂM NGOÀI TRỜI?để biết thêm một chút bối cảnh / thông tin.

Tôi đã cố gắng duy trì các tên tùy chọn mysqlđể nó đủ để cung cấp --file--querycác tùy chọn:

./mysql2csv --file="/tmp/result.csv" --query='SELECT 1 as foo, 2 as bar;' --user="username" --password="password"

"Cài đặt" mysql2csvqua

wget https://gist.githubusercontent.com/paslandau/37bf787eab1b84fc7ae679d1823cf401/raw/29a48bb0a43f6750858e1ddec054d3552f3cbc45/mysql2csv -O mysql2csv -q && (sha256sum mysql2csv | cmp <(echo "b109535b29733bd596ecc8608e008732e617e97906f119c66dd7cf6ab2865a65  mysql2csv") || (echo "ERROR comparing hash, Found:" ;sha256sum mysql2csv) ) && chmod +x mysql2csv

(tải xuống nội dung của ý chính, kiểm tra tổng kiểm tra và thực hiện nó).


3

Điều gì làm việc cho tôi:

SELECT *
FROM students
WHERE foo = 'bar'
LIMIT 0,1200000
INTO OUTFILE './students-1200000.csv'
FIELDS TERMINATED BY ',' ESCAPED BY '"'
ENCLOSED BY '"'
LINES TERMINATED BY '\r\n';

Không có giải pháp nào trong luồng này hoạt động cho trường hợp cụ thể của tôi, tôi có dữ liệu json khá trong một trong các cột, điều này sẽ bị rối trong đầu ra csv của tôi. Đối với những người có vấn đề tương tự, thay vào đó, hãy thử các dòng bị chấm dứt bởi \ r \ n.

Ngoài ra, một vấn đề khác đối với những người đang cố gắng mở csv bằng Microsoft Excel, hãy nhớ rằng có giới hạn 32.767 ký tự mà một ô duy nhất có thể chứa, phía trên nó tràn ra các hàng bên dưới. Để xác định bản ghi nào trong một cột có vấn đề, hãy sử dụng truy vấn bên dưới. Sau đó, bạn có thể cắt bớt những hồ sơ đó hoặc xử lý chúng theo ý muốn.

SELECT id,name,CHAR_LENGTH(json_student_description) AS 'character length'
FROM students
WHERE CHAR_LENGTH(json_student_description)>32767;

2

Nếu sau đó bạn gặp lỗi secure-file-priv, sau khi chuyển vị trí tệp đích của bạn bên trong C:\ProgramData\MySQL\MySQL Server 8.0\Uploadsvà sau đó là truy vấn-

SELECT * FROM attendance INTO OUTFILE 'C:\ProgramData\MySQL\MySQL Server 8.0\Uploads\FileName.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';

không hoạt động, bạn chỉ cần thay đổi \(acrylic) từ truy vấn thành /(forwardsplash)

Và nó hoạt động !!

Thí dụ:

CHỌN * TỪ tham dự VÀO OUTFILE 'C: / ProgramData / MySQL / MySQL Server 8.0 / Tải lên / FileName.csv' CÁC L FINH VỰC KẾT THÚC B'NG ',' ĐƯỢC KẾT HỢP '' 'CÁC DÒNG KẾT THÚC B'NG' \ n ';

Mỗi lần bạn chạy truy vấn thành công, nó sẽ tạo tệp csv mới mỗi lần! Thật tuyệt phải không?


1

Tập lệnh bash nhỏ để thực hiện truy vấn đơn giản đối với các kết xuất CSV, được lấy cảm hứng từ https://stackoverflow.com/a/5395421/2841607 .

#!/bin/bash

# $1 = query to execute
# $2 = outfile
# $3 = mysql database name
# $4 = mysql username

if [ -z "$1" ]; then
    echo "Query not given"
    exit 1
fi

if [ -z "$2" ]; then
    echo "Outfile not given"
    exit 1
fi

MYSQL_DB=""
MYSQL_USER="root"

if [ ! -z "$3" ]; then
    MYSQL_DB=$3
fi

if [ ! -z "$4" ]; then
    MYSQL_USER=$4
fi

if [ -z "$MYSQL_DB" ]; then
    echo "Database name not given"
    exit 1
fi

if [ -z "$MYSQL_USER" ]; then
    echo "Database user not given"
    exit 1
fi

mysql -u $MYSQL_USER -p -D $MYSQL_DB -B -s -e "$1" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > $2
echo "Written to $2"

1

Kịch bản bash sau đây làm việc cho tôi. Nó tùy ý cũng có được lược đồ cho các bảng được yêu cầu.

#!/bin/bash
#
# export mysql data to CSV
#/programming/356578/how-to-output-mysql-query-results-in-csv-format
#

#ansi colors
#http://www.csc.uvic.ca/~sae/seng265/fall04/tips/s265s047-tips/bash-using-colors.html
blue='\033[0;34m'
red='\033[0;31m'
green='\033[0;32m' # '\e[1;32m' is too bright for white bg.
endColor='\033[0m'

#
# a colored message 
#   params:
#     1: l_color - the color of the message
#     2: l_msg - the message to display
#
color_msg() {
  local l_color="$1"
  local l_msg="$2"
  echo -e "${l_color}$l_msg${endColor}"
}


#
# error
#
# show the given error message on stderr and exit
#
#   params:
#     1: l_msg - the error message to display
#
error() {
  local l_msg="$1"
  # use ansi red for error
  color_msg $red "Error:" 1>&2
  color_msg $red "\t$l_msg" 1>&2
  usage
}

#
# display usage 
#
usage() {
  echo "usage: $0 [-h|--help]" 1>&2
  echo "               -o  | --output      csvdirectory"    1>&2
  echo "               -d  | --database    database"   1>&2
  echo "               -t  | --tables      tables"     1>&2
  echo "               -p  | --password    password"   1>&2
  echo "               -u  | --user        user"       1>&2
  echo "               -hs | --host        host"       1>&2
  echo "               -gs | --get-schema"             1>&2
  echo "" 1>&2
  echo "     output: output csv directory to export mysql data into" 1>&2
  echo "" 1>&2
  echo "         user: mysql user" 1>&2
  echo "     password: mysql password" 1>&2
  echo "" 1>&2
  echo "     database: target database" 1>&2
  echo "       tables: tables to export" 1>&2
  echo "         host: host of target database" 1>&2
  echo "" 1>&2
  echo "  -h|--help: show help" 1>&2
  exit 1
}

#
# show help 
#
help() {
  echo "$0 Help" 1>&2
  echo "===========" 1>&2
  echo "$0 exports a csv file from a mysql database optionally limiting to a list of tables" 1>&2
  echo "   example: $0 --database=cms --user=scott --password=tiger  --tables=person --output person.csv" 1>&2
  echo "" 1>&2
  usage
}

domysql() {
  mysql --host $host -u$user --password=$password $database
}

getcolumns() {
  local l_table="$1"
  echo "describe $l_table" | domysql | cut -f1 | grep -v "Field" | grep -v "Warning" | paste -sd "," - 2>/dev/null
}

host="localhost"
mysqlfiles="/var/lib/mysql-files/"

# parse command line options
while true; do
  #echo "option $1"
  case "$1" in
    # options without arguments
    -h|--help) usage;;
    -d|--database)     database="$2" ; shift ;;
    -t|--tables)       tables="$2" ; shift ;;
    -o|--output)       csvoutput="$2" ; shift ;;
    -u|--user)         user="$2" ; shift ;;
    -hs|--host)        host="$2" ; shift ;;
    -p|--password)     password="$2" ; shift ;;
    -gs|--get-schema)  option="getschema";; 
    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; usage;;
    (*) break;;
  esac
  shift
done

# checks
if [ "$csvoutput" == "" ]
then
  error "ouput csv directory not set"
fi
if [ "$database" == "" ]
then
  error "mysql database not set"
fi
if [ "$user" == "" ]
then
  error "mysql user not set"
fi
if [ "$password" == "" ]
then
  error "mysql password not set"
fi

color_msg $blue "exporting tables of database $database"
if [ "$tables" = "" ]
then
tables=$(echo "show tables" | domysql)
fi

case $option in
  getschema) 
   rm $csvoutput$database.schema
   for table in $tables
   do
     color_msg $blue "getting schema for $table"
     echo -n "$table:" >> $csvoutput$database.schema
     getcolumns $table >> $csvoutput$database.schema
   done  
   ;;
  *)
for table in $tables
do
  color_msg $blue "exporting table $table"
  cols=$(grep "$table:" $csvoutput$database.schema | cut -f2 -d:)
  if [  "$cols" = "" ]
  then
    cols=$(getcolumns $table)
  fi
  ssh $host rm $mysqlfiles/$table.csv
cat <<EOF | mysql --host $host -u$user --password=$password $database 
SELECT $cols FROM $table INTO OUTFILE '$mysqlfiles$table.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
EOF
  scp $host:$mysqlfiles/$table.csv $csvoutput$table.csv.raw
  (echo "$cols"; cat $csvoutput$table.csv.raw) > $csvoutput$table.csv
  rm $csvoutput$table.csv.raw
done
  ;;
esac

1

Tôi gặp phải vấn đề tương tự và Câu trả lời của Paul không phải là một lựa chọn vì đó là RDS. Thay thế tab bằng dấu phẩy không hoạt động vì dữ liệu đã nhúng dấu phẩy & tab. Tôi thấy rằng mycli là một lựa chọn thay thế cho máy khách mysql hỗ trợ đầu ra csv ngoài hộp có --csvcờ

mycli db_name --csv -e "select * from flowers" > flowers.csv

1

Nếu bạn gặp lỗi này trong khi bạn cố gắng xuất tệp của mình

LRI 1290 (HY000): Máy chủ MySQL đang chạy với tùy chọn --secure-file-private để nó không thể thực thi câu lệnh này

và bạn không thể giải quyết lỗi này. Bạn có thể làm một điều chỉ bằng cách chạy tập lệnh python này

import mysql.connector
import csv

con = mysql.connector.connect(
    host="localhost",
    user="root",
    passwd="Your Password"
)

cur = con.cursor()

cur.execute("USE DbName")
cur.execute("""
select col1,col2 from table
where <cond>
""")

with open('Filename.csv',mode='w') as data:
    fieldnames=["Field1","Field2"]
    writer=csv.DictWriter(data,fieldnames=fieldnames)
    writer.writeheader()
    for i in cur:
        writer.writerow({'Field1':i[0],'Field2':i[1]})

Chào mừng bạn đến với Stack Overflow! Điều này không trả lời câu hỏi. Vui lòng xem lại stackoverflow.com/help/how-to-answer .
stephenwade

0

Nếu có PHP được cài đặt trên máy bạn đang sử dụng, bạn có thể viết một tập lệnh PHP để làm điều đó. Nó yêu cầu cài đặt PHP có cài đặt phần mở rộng MySQL.

Bạn có thể gọi trình thông dịch PHP từ dòng lệnh như vậy:

php --php-ini path/to/php.ini your-script.php

Tôi bao gồm cả --php-inichuyển đổi, bởi vì bạn có thể cần phải sử dụng cấu hình PHP của riêng bạn cho phép mở rộng MySQL. Trên PHP 5.3.0+, tiện ích mở rộng đó được bật theo mặc định, do đó không còn cần thiết phải sử dụng cấu hình để kích hoạt nó.

Sau đó, bạn có thể viết tập lệnh xuất của mình giống như bất kỳ tập lệnh PHP thông thường nào:

<?php
    #mysql_connect("localhost", "username", "password") or die(mysql_error());
    mysql_select_db("mydb") or die(mysql_error());

    $result = mysql_query("SELECT * FROM table_with_the_data p WHERE p.type = $typeiwant");

    $result || die(mysql_error());

    while($row = mysql_fetch_row($result)) {
      $comma = false;
      foreach ($row as $item) {

        # Make it comma separated
        if ($comma) {
          echo ',';
        } else {
          $comma = true;
        }

        # Quote the quotes
        $quoted = str_replace("\"", "\"\"", $item);

        # Quote the string
        echo "\"$quoted\"";
      }
        echo "\n";
    }
?>

Ưu điểm của phương pháp này là, nó không có vấn đề gì với các trường varchar và văn bản, có văn bản chứa dòng mới. Các trường đó được trích dẫn chính xác và những dòng mới trong đó sẽ được trình đọc CSV diễn giải như một phần của văn bản, không phải là dấu phân tách bản ghi. Đó là một cái gì đó rất khó để sửa sau đó với sed hoặc như vậy.


1
Khác xa với sự phức tạp không cần thiết, đây là giải pháp duy nhất ở đây đi theo một hướng có khả năng đúng - mặc dù với công việc nhiều hơn một chút. CSV phức tạp hơn lần đầu tiên xuất hiện và bạn đã phạm nhiều lỗi. ví dụ dấu gạch chéo ngược trong bản gốc. Tốt hơn là sử dụng một thư viện đã giải quyết tất cả các vấn đề để ghi vào CSV.
mc0e

@ mc0e Thông thường, bạn có thể nhân đôi báo giá hoặc thoát báo giá. Tôi quyết định tăng gấp đôi trích dẫn, do đó tôi không cần một nhân vật thoát. Phần mềm khác nhau có ý tưởng khác nhau về chi tiết CSV. Ví dụ, LOAD DATA trong MySQL thực sự coi \ là ký tự thoát, trong khi Open Office Calc thì không. Khi tôi viết câu trả lời tôi đã xuất dữ liệu vào một bảng tính.
user7610

1
Mã của tôi xử lý tất cả mọi thứ cần thiết để xuất dữ liệu của tôi trở lại trong ngày;) Câu trả lời của bạn cũng là một bước đi đúng hướng, nhưng như nhận xét đầu tiên ở đó, nên 1) kết nối trực tiếp với cơ sở dữ liệu sql từ tập lệnh như cũng như 2) sử dụng một thư viện csv thích hợp.
user7610
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.