各位前輩你們好 想請教PhpSpreadsheet套件產出Excel格式問題
目前遇到程式技術上困難。
開發系統環境(自己家裡的環境)
OS Windows 10
php version 7.4.28
PhpSpreadsheet-1.20.0 version
Microsoft Excel 365 version
p.s. 開發系統環境(公司系統)
|OS|PHP version|PHPExcel|PHPMailer|Microsoft Excel version|
|---- |---|
|CentOS7|7.0.33 |1.8.0 |5.2.26 |2016
這是利用PhpSpreadsheet套件產出的格式
附上我的程式碼
<?php
// Load Composer's autoloader
require_once 'D:\06.programming\php\vendor\autoload.php';
// Import PhpSpreadsheet classes into the global namespace
// These must be at the top of your script, not inside a function
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
// Connecting to SQL Server
require_once 'D:\06.programming\php\Config\connect-sqlserver.php';
// ========== 建立工作表一 ==========
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheetIndex(0);
$sheet = $spreadsheet->getActiveSheet(0);
// Excel 儲存格 A2~C2填入文字
$TitleData = ['國家代碼', '國家地區', '人口數量'];
$sheet->fromArray($TitleData, NULL, 'A2');
// Excel 設定儲存格格式
$styleArray = [
'alignment' => [
'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
],
'fill' => [
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_GRADIENT_LINEAR,
'startColor' => [
'rgb' => 'ffff00',
],
'endColor' => [
'rgb' => 'ffff00',
],
],
];
$sheet->getStyle('A2:C2')->applyFromArray($styleArray);
// 設定儲存格,寬度
$sheet->getColumnDimension('A')->setWidth(10);
$sheet->getColumnDimension('B')->setWidth(15);
$sheet->getColumnDimension('C')->setWidth(10);
// ============== END ==============
// ========== 連接資料庫取得資料 ==========
$conn = OpenConnection();
// SQL Server 撈取資料
$tsql = "
SELECT
CountryCode
,District
,MAX(Population) AS Population
FROM city
WHERE District LIKE 'C%' OR District LIKE 'D%'
GROUP BY CountryCode, District
ORDER BY CountryCode, District
";
$result = sqlsrv_query($conn, $tsql);
if ($result == false) {
die(sqlsrv_errors());
} else {
// $rowsheet從Excel儲存格第3列開始填入資料
$rowsheet = 3;
while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC))
{
$sheet->setCellValue('A'.$rowsheet, $row['CountryCode'])
->setCellValue('B'.$rowsheet, $row['District'])
->setCellValue('C'.$rowsheet, $row['Population']);
$rowsheet++;
}
}
// ============== END ==============
// ========== Save Excel on Windows D disk ==========
$writer = new Xlsx($spreadsheet);
$writer->save('test.xlsx');
// ========== END ==========
sqlsrv_close($conn);
?>
假如想要呈現這樣的Excel格式呢?
問題?國家人口數量要怎麼呈現?卡住?
我的想法
反推儲存格文字的第幾欄?第幾列?
利用陣列?取得Excel儲存格欄位在哪裡?填入國家人口數量?
更改我的程式碼,我直接擷取重點程式片段
// ========== 連接資料庫取得資料 ==========
$conn = OpenConnection();
$tsql = "
SELECT
CountryCode
,District
,MAX(Population) AS Population
FROM city
WHERE District LIKE 'C%' OR District LIKE 'D%'
GROUP BY CountryCode, District
ORDER BY CountryCode, District
";
$tsql2 = "
SELECT
CountryCode
FROM city
WHERE District LIKE 'C%' OR District LIKE 'D%'
ORDER BY CountryCode
";
$tsql3 = "
SELECT
District
FROM city
WHERE District LIKE 'C%' OR District LIKE 'D%'
ORDER BY District
";
$result = sqlsrv_query($conn, $tsql);
$result2 = sqlsrv_query($conn, $tsql2);
$result3 = sqlsrv_query($conn, $tsql3);
if ($result == false) {
die(sqlsrv_errors());
} else {
// 開始顯示國家人口數量??
/*
$rowsheet = 3;
while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC))
{
??
}
*/
// 第3列開始以下顯示國家代碼
$rowsheet = 3;
while ($row = sqlsrv_fetch_array($result2, SQLSRV_FETCH_ASSOC))
{
$sheet->setCellValue('A'.$rowsheet, $row['CountryCode']);
$rowsheet++;
}
// 第B欄開始往右顯示國家地區
$colsheet = "B";
while ($row = sqlsrv_fetch_array($result3, SQLSRV_FETCH_ASSOC))
{
$sheet->setCellValue($colsheet.'2', $row['District']);
$colsheet++;
}
}
// ============== END ==============
為甚麼要搞這麼麻煩?
抱歉,因為公司上層和各單位使用者要求我必須呈現這種格式...
煩請各位了,謝謝...
可以用 PHP 處理一下,大概像這樣吧
<?php
require('vendor/autoload.php');
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$data = [
['ANT', 'Curacao', 2345],
['ARG', 'Catamarca', 134935],
['BLZ', 'Cayo', 7105],
['COL', 'Caldas', 337580],
['ARG', 'Chaco', 229212],
['COL', 'Caqueta', 108574],
];
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$rowOffset = 3;
$rowOffsetArr = [];
$nCol = 2;
foreach ($data as $row) {
$key = $row[0];
if (!isset($rowOffsetArr[$key])) {
$sheet->setCellValueByColumnAndRow(1, $rowOffset, $key);
$rowOffsetArr[$key] = $rowOffset++;
}
$nRow = $rowOffsetArr[$key];
$sheet->setCellValueByColumnAndRow($nCol, 2, $row[1]);
$sheet->setCellValueByColumnAndRow($nCol, $nRow, $row[2]);
++$nCol;
}
$writer = new Xlsx($spreadsheet);
$writer->save('test.xlsx');
謝謝淺水員前輩!
之前在忙其它專案和IT的雜事,比較沒時間處理程式問題。
我有研讀並且理解您的程試碼。
後續再修改我自己的程式,有成功且符合公司的需求。
不過還有其它小問題啦XD,我自己嘗試修改。
附上修改完的程式
$rowOffset = 4;
$rowOffsetArr = [];
$colOffsetArr = [];
$colOffset = 1;
while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_NUMERIC))
{
//var_dump($row);
$key1 = $row[0];
if (!isset($rowOffsetArr[$key1])) {
$sheet->setCellValue('A'.$rowOffset, $key1);
$rowOffsetArr[$key1] = $rowOffset++;
}
$key2 = $row[1];
if (!isset($colOffsetArr[$key2])) {
$sheet->setCellValueByColumnAndRow($colOffset, 3, $key2);
$colOffsetArr[$key2] = $colOffset++;
}
$nRow = $rowOffsetArr[$key1];
$nCol = $colOffsetArr[$key2];
$sheet->setCellValueByColumnAndRow($nCol, $nRow, $row[2]);
}
原本
PHPExcel產出來的格式
也可以在 SQL 階段就做出結果
dbfiddle 練習結果
DECLARE @colnameList varchar(200)
SET @colnameList = NULL
SELECT @colnameList = COALESCE(@colnameList + ',','') + DISTRICT
FROM CITY;
DECLARE @SQLQuery NVARCHAR(MAX)
SET @SQLQuery ='
SELECT *
FROM (
SELECT l.COUNTRYCODE, l.DISTRICT, l.POPULATION
FROM dbo.CITY l
) t
PIVOT (
MAX(POPULATION)
FOR DISTRICT IN ('+@colnameList+')
) p;
'
EXEC(@SQLQuery)
支持海寶大,
我個人的習慣是,在SQL階段就搞定一切,
php端則簡單無比,一行一行一列一列地秀出來就好,
反正EXCEL的格式也很像資料表格樣子,
不管是直接程式處理或是 sql procedure
有時候也要注意 atomic 的問題
需要的話要加上 TRANSACTION
請教淺水教練:
【TRANSACTION】不是主要用在寫入或刪除階段嗎?
像這個只是 select 的用途,有必要動用到 TRANSACTION ?
又,是【淺水】還是【潛水】啊?
我的想法是:
假設兩個 SELECT 中間有人刪除或是修改資料的話
要看對後續的取得結果影響大不大
不一定是寫入或刪除才需要加
另外因為 SQL 的語法比較固定
所以一些寫法雖然能得到正確結果
但演算法的時間複雜度卻多繞一圈的話
也未必都要用 SQL 處理
以上是我個人想法啦
不一定都對,就一起討論了
(我 Microsoft SQL Server 不熟)
PS. 「潛水」是光看文不發表意見,我之前想提醒自己多發文就改「淺水」了,別潛太深的意思。