需在 Linux 服務器無圖形界面環境下將 MySQL 查詢結果導出為 Excel (.xls) 文件供業務下載分析。本工具基於 Perl DBI + Spreadsheet::WriteExcel::Big 實現,支持命令行參數化、大文件流式寫入、Unicode 編碼處理,無需 Windows/Office 環境。
依賴模塊安裝
# CPAN 安裝
cpan DBI DBD::mysql Unicode::Map Spreadsheet::WriteExcel::Big
# 或系統包管理器
apt-get install libdbi-perl libdbd-mysql-perl libunicode-map-perl libspreadsheet-writeexcel-perl
# 注意:WriteExcel::Big 可能需從 CPAN 獲取最新版
核心腳本:mysql2excel.pl
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Unicode::Map;
use Spreadsheet::WriteExcel::Big; # 支持 > 65536 行、大文件
# ===== 配置區 =====
my $hostname = '192.168.1.133';
my $username = 'user';
my $password = 'pass';
my $dbname = 'db';
my $trans_compress = 1; # 1=啟用壓縮協議
# Excel 列字母映射(支持超出 Z 列)
my @cols = ('A:A','B:B','C:C','D:D','E:E','F:F','G:G','H:H','I:I','J:J',
'K:K','L:L','M:M','N:N','O:O','P:P','Q:Q','R:R','S:S','T:T',
'U:U','V:V','W:W','X:X','Y:Y','Z:Z',
'AA:AA','BB:BB','CC:CC','DD:DD','EE:EE','FF:FF','GG:GG','HH:HH',
'II:II','JJ:JJ','KK:KK','LL:LL','MM:MM','NN:NN','OO:OO','PP:PP',
'QQ:QQ','RR:RR','SS:SS','TT:TT','UU:UU','VV:VV','WW:WW','XX:XX',
'YY:YY','ZZ:ZZ');
# ====================
$| = 1; # 刷新輸出緩衝
# 參數解析:mysql2excel.pl "output.xls" "SELECT * FROM table WHERE ..."
die "Usage: $0 \"SELECT ...\"\n" unless @ARGV == 2;
my ($outFile, $sql) = @ARGV;
$sql =~ s/^\"|\"$//g; # 去除包裹雙引號
warn "MySQL to Excel\nby Perl Script\n=====================\nSQL: $sql\n";
# 數據庫連接
my $dsn = "DBI:mysql:database=$dbname;host=$hostname;mysql_compression=$trans_compress";
my $dbh = DBI->connect($dsn, $username, $password, { RaiseError => 1, PrintError => 0, AutoCommit => 1 })
or die "Connect failed: $DBI::errstr";
my $sth = $dbh->prepare($sql) or die "Prepare failed: $dbh->errstr";
my $rows = $sth->execute() or die "Execute failed: $sth->errstr";
warn "Rows fetched: $rows\n";
# 列名獲取
my $colNames = $sth->{NAME};
my $colCount = @$colNames;
die "Columns ($colCount) exceed max supported (" . scalar(@cols) . ")\n" if $colCount > @cols;
# 創建 Excel 工作簿
my $workbook = Spreadsheet::WriteExcel::Big->new($outFile)
or die "Create workbook failed: $!";
my $worksheet = $workbook->add_worksheet('Data');
# 寫入表頭
my $headerFormat = $workbook->add_format(bold => 1, bgcolor => '#4472C4', color => 'white', border => 1);
for my $i (0 .. $colCount-1) {
$worksheet->write(0, $i, $colNames->[$i], $headerFormat);
}
# 流式寫入數據行
my $rowNum = 1;
my $dataFormat = $workbook->add_format(border => 1);
while (my $rowRef = $sth->fetchrow_arrayref) {
for my $i (0 .. $colCount-1) {
my $val = $rowRef->[$i];
# Unicode 處理:DBI 返回 UTF-8,WriteExcel 內部處理
$worksheet->write($rowNum, $i, $val // '', $dataFormat);
}
$rowNum++;
# 進度提示
warn "Written $rowNum rows...\n" if $rowNum % 10000 == 0;
}
$workbook->close();
warn "Export completed: $rowNum rows written to $outFile\n";
$dbh->disconnect();
使用示例
# 導出全表
perl mysql2excel.pl "orders_2024.xls" "SELECT * FROM orders WHERE YEAR(created_at)=2024"
# 導出多表 JOIN 結果
perl mysql2excel.pl "customer_summary.xls" "
SELECT c.id, c.name, COUNT(o.id) AS order_count, SUM(o.amount) AS total_amount
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.id, c.name
HAVING total_amount > 10000
"
關鍵技術點解析
| 挑戰 | 解決方案 |
| 大文件內存溢出 | Spreadsheet::WriteExcel::Big 使用臨時文件存儲 XML 部分,內存佔用恆定,支持百萬行。 |
| 中文亂碼 | DBI mysql_enable_utf8 => 1(新版默認開啟)+ WriteExcel 內部 UTF-16LE 編碼,無需手動轉碼。 |
| 列數超出 256 (BIFF8 限制) | WriteExcel::Big 基於 Office Open XML (OOXML) 實現,突破 256 列/65536 行限制,生成 .xlsx 兼容格式(雖副檔名 .xls)。 |
| 長時間運行進度不可見 | 每 10000 行 warn 輸出進度,配合 tail -f 監控。 |
| SQL 注入風險 | 腳本直接執行參數 SQL,屬信任內部工具;對外暴露需加參數化驗證層。 |
現代替代方案對比
| 工具 | 語言 | 優點 | 缺點 | 適用場景 |
| 本 Perl 腳本 | Perl | 輕量、無依賴 Office、Linux 原生、流式寫入 | 需 Perl 環境、維護成本、.xls 格式兼容性有限 | 定時任務、嵌入式導出、舊系統集成 |
| Python + openpyxl/pandas | Python | 生態豐富、DataFrame 操作強、原生 .xlsx | 大文件內存壓力大(需分塊寫入) | 數據分析、報表自動化、現代技術棧 |
| Node.js + exceljs | JavaScript | 異步流式、Web 服務集成易 | 大文件性能一般 | API 導出端點、前端觸發下載 |
| mysqldump + csvkit | Shell | 無代碼、標準工具鏈、極快 | 無格式控制、純 CSV | 純數據遷移、不需樣式 |
總結
Perl + Spreadsheet::WriteExcel::Big 為「Linux 無界面導出大 Excel」提供了經典可靠方案。隨著 Python 生態成熟,pandas.ExcelWriter(engine='openpyxl', mode='w') 配合 chunksize 分塊寫入已成主流選擇。選型原則:存量 Perl 系統續用、新建項目首選 Python、Web 服務化用 Node.js、純數據遷移用 mysqldump。
- 上一篇文章: SQL Server 異構數據整合:鏈接服務器聯邦查詢 Access 與 SQL Server 聯合分析
- 下一篇文章: Access 遷移 SQL Server 完整避坑指南:字段類型、函數、語法、行為差異全景對比
Copyright ©
程式碼之家 All Rights Reserved