在玩PHPExcel时,我遇到了一些问题,如何正确处理验证/并将值插入数据库。我不需要任何代码,只需要一般的概念如何去做。
首先,我遍历第一行以检查列是否与给定列匹配(如果它符合架构)。
在下一步中,我得到了行,同时它的行验证了行/列。如果类型不匹配,我将收到错误。
在验证行时,我需要获取Worker名称并将其转换为id get_worker_id()
。
问题编号#1。 这样的解决方案是一个好习惯吗它将产生多达100个查询。前行 - 1。
问题编号#2
我还需要再次验证行,我将使用worker_id,F和G列来检查数据库中是否存在此类记录。我只是简单地引入一个类似于get_worker_id()
的函数,但如果条目存在,它将返回true / false。
但这又是一种正确的做法吗?通过原始计算,我的方法将产生100个选择(get_worker_id),100个选择(验证是否存在),100个插入(如果一切正常)。
我不确定我是否正确地做到了。你可以给我一些建议吗?
感谢前锋。
处理xlsx文件的模型。
class Gratyfikant_model extends CI_Model {
private $_limit = 100;
const columns = array(
'A' => "Z",
'B' => "KS",
'C' => "G",
'D' => "S",
'E' => "Numer",
'F' => "Miesiąc", // required
'G' => "Data wypłaty", // required
'H' => "Pracownik", // required
'I' => "Brutto duże", // required
'J' => "ZUS pracownik", // required
'K' => "ZUS pracodawca", // required
'L' => "Do wypłaty", // required
'M' => "Obciążenie", // required
'N' => "FW");
const validators = array(
'F' => 'date',
'G' => 'date',
'H' => 'string',
'I' => 'float',
'J' => 'float',
'K' => 'float',
'L' => 'float',
'M' => 'float',
);
const validators_errors = array(
'float' => "Wartość nie jest liczbą",
'string' => "Wartość nie jest poprawna",
'date' => "Wartość nie jest datą"
);
protected $_required = array(
'H', 'I', 'J', 'K', 'L', 'M'
);
private $_sheet = array();
private $_sheet_pracownicy = array();
private $_agregacja = array();
protected $_invalid_rows = array();
public function __construct() {
parent::__construct();
}
public function read_data(array $dane) {
if (count($dane) > $this->_limit) {
throw new Exception('Limit wierszy to ' . $this->_limit);
}
$this->_sheet = $dane;
return $this;
}
public function column_validation() {
foreach ($this->_required as $r) {
if (!isset($this->_sheet[1][$r]) || $this->_sheet[1][$r] != self::columns[$r] || !array_key_exists($r, $this->_sheet[1])
) {
throw new Exception('Kolumna - ' . $r . ' - Wartość nagłówka nie pasuje do szablonu, powinno być ' . self::columns[$r]);
}
}
return $this;
}
function validateDate($date) {
$d = DateTime::createFromFormat('Y-m-d', $date);
return $d && $d->format('Y-m-d') === $date;
}
private function row_validation($k, $a, $v, $f) {
switch ($v) {
case "date":
$cellval = $this->validateDate(PHPExcel_Style_NumberFormat::toFormattedString($f, PHPExcel_Style_NumberFormat::FORMAT_DATE_YMD));
break;
case "float":
$cellval = is_float($f);
break;
case "string":
$cellval = is_string($f);
break;
default:
break;
}
if (!$cellval) {
$this->_invalid_rows[$a][$k] = $v;
}
}
public function get_sheet_data() {
$dane = $this->_sheet;
unset($dane[1]); // remove first col
$zus_pracownik = 0;
$zus_pracodawca = 0;
$zus_lacznie = 0;
$do_wyplaty = 0;
$obciazenie = 0;
$brutto = 0;
foreach ($dane as $a => $d) {
foreach (self::validators as $k => $v) {
echo $this->row_validation($k, $a, $v, $d[$k]);
}
if (!is_null($d["H"]) && !empty($d["H"])) {
// $this->_sheet_pracownicy[$d["H"]]["numer"] = PHPExcel_Style_NumberFormat::toFormattedString($d["E"], PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY);
$this->_sheet_pracownicy[] = array(
"pracownik" => $d["H"],
"miesiac" => PHPExcel_Style_NumberFormat::toFormattedString($d["F"], PHPExcel_Style_NumberFormat::FORMAT_DATE_YMD),
"data_wyplaty" => PHPExcel_Style_NumberFormat::toFormattedString($d["G"], PHPExcel_Style_NumberFormat::FORMAT_DATE_YMD),
"zus_pracownik" => $d["J"],
"zus_pracodawca" => $d["K"],
"zus_lacznie" => bcadd($d["K"], $d["J"]),
"do_wyplaty" => $d["L"],
"obciazenie" => $d["M"],
"brutto" => $d["I"],
"id_prac" => $this->get_worker_id($d["H"]));
$zus_pracownik = bcadd($zus_pracownik, $d["J"]);
$zus_pracodawca = bcadd($zus_pracodawca, $d["K"]);
$zus_lacznie = bcadd($zus_lacznie, bcadd($d["K"], $d["J"]));
$do_wyplaty = bcadd($do_wyplaty, $d["L"]);
$obciazenie = bcadd($obciazenie, $d["M"]);
$brutto = bcadd($brutto, $d["I"]);
}
}
$this->_agregacja = array(
"zus_pracownik" => $zus_pracownik,
"zus_pracodawca" => $zus_pracodawca,
"zus_lacznie" => $zus_lacznie,
"do_wyplaty" => $do_wyplaty,
"obciazenie" => $obciazenie,
"brutto" => $brutto
);
return $this;
}
public function display_result() {
if (empty($this->_invalid_rows)) {
return array(
"wartosci" => $this->_sheet_pracownicy,
"agregacja" => $this->_agregacja
);
}
}
public function display_errors() {
foreach ($this->_invalid_rows as $k => $a) {
foreach ($a as $key => $value) {
throw new Exception('Pole ' . $key . '' . $k . ' ' . self::validators_errors[$value]);
}
}
return $this;
}
public function get_worker_id($getAd) {
$this->db->select('id_pracownika as id')
->from('pracownicy')
->like('CONCAT( imie, \' \', nazwisko )', $getAd)
->or_like('CONCAT( nazwisko, \' \', imie )', $getAd);
$query = $this->db->get();
$result = $query->result_array();
if (isset($result[0]["id"])) {
return $result[0]["id"];
} else {
throw new Exception('Nie odnaleziono ' . $getAd . ' w bazie danych, proszę dodać pracownika a następnie ponownie wczytać plik');
}
}
}
显示
try {
$data['s'] = $this->gm
->read_data($sheetData)
->column_validation()
->get_sheet_data()
->display_errors()
->display_result();
} catch (Exception $e) {
$data['ex'] = $e->getMessage();
}
XLSX文件示例
+---+---------------+---+---+------------+---------+--------------+-----------+-------------+---------------+----------------+------------+------------+--------+
| Z | KS | G | S | Numer | Miesiąc | Data wypłaty | Pracownik | Brutto duże | ZUS pracownik | ZUS pracodawca | Do wypłaty | Obciążenie | FW |
+---+---------------+---+---+------------+---------+--------------+-----------+-------------+---------------+----------------+------------+------------+--------+
| | nieprzekazany | G | | 03.08.2017 | sie.17 | 08.09.2017 | Worker1 | 2000 | 274,2 | 392,2 | 1459,48 | 2392,2 | (brak) |
| | nieprzekazany | G | | 03.08.2017 | sie.17 | 08.09.2017 | Worker2 | 1000 | 137,1 | 171,6 | 768,24 | 1171,6 | (brak) |
| | nieprzekazany | G | | 03.08.2017 | sie.17 | 08.09.2017 | Worker3 | 2000 | 274,2 | 392,2 | 1413,88 | 2392,2 | (brak) |
| | nieprzekazany | G | | 03.08.2017 | sie.17 | 08.09.2017 | Worker4 | 2000 | 274,2 | 392,2 | 1418,88 | 2392,2 | (brak) |
+---+---------------+---+---+------------+---------+--------------+-----------+-------------+---------------+----------------+------------+------------+--------+
答案 0 :(得分:2)
这实际上取决于应用程序的规模以及导入此Excel文件的频率。例如,如果您的应用程序几乎没有流量,那么每行运行多个查询并不是世界末日。如果您已经安装并运行了服务器和数据库,那么您也可以使用它们。相反,如果您的应用程序处于持续高负荷状态,那么尝试最小化您运行的查询量可能是一个好主意。
选项1
如果您的应用程序很小并且/或者没有太多流量,那么您不必担心需要进行约300次查询。 MySQL并不脆弱,如果你已经很好地索引了数据,那么你的查询将非常快。
选项2
首先查询您需要的数据并将其存储在内存中,以便在PHP中执行逻辑检查。
这意味着对于问题1,您应该在一个查询中获取所有工作者,然后在PHP中构建查找数组。
这是一个非常粗略的例子:
// Get all workers
SELECT worker_name, worker_id FROM workers;
// Build a lookup array from the query results
$worker_array = array(
'Worker1' => 1,
'Worker2' => 2,
...
);
// Then as you loop each row check if the work is in your lookup array
if ( ! isset($worker_array[$excel_row['worker_name']])) {
// do something
}
对于问题2,您可以在一个查询中获取您的唯一数据样本(您不需要整个记录,只需要唯一的字段)。但是,如果您拥有大量唯一数据样本,则可能会出现问题。
选项3
在MySQL中创建临时表并导入Excel数据,而不执行任何逻辑检查。然后,您可以完全在SQL中执行逻辑检查。
这是一个非常粗略的例子,不知道你的数据结构:
-- Get all records in the Excel data that match unique data samples
SELECT
*
FROM
temporary_table tt
JOIN
workers w
ON w.worker_name=tt.worker_name
JOIN
data d
ON d.worker_id=w.worker_id
AND d.col_f=tt.col_f
AND d.col_g=tt.col_g
如果数据没有问题,那么您可以从临时表执行INSERT到数据表中。这会将您的查询限制为初始插入(您可以批量处理以获得更好的性能),数据检查以及从临时数据到实际数据的插入。
<强>小结强>
这一切都取决于您的申请。如果你能够完成选项1并且你已经实现了它,那么现在就可以了。如果你没有看到这个应用程序变得疯狂,你就不需要过度优化。
但是,如果您担心规模和增长,那么我个人会考虑实施选项3。
答案 1 :(得分:2)
这里有许多问题:
将导入分为几个阶段。
至于天气,你需要一些分块,这取决于你的脚本消耗多少时间和内存。如果您需要它,就像将X行读取到内存然后处理它一样简单。极端情况下,您可以单独加载每条记录。 如果你不需要它,只需将它全部加载到数组中。
分块 - 在一次迭代中消耗多达X行,然后清除内存然后消耗下一个块......
答案 2 :(得分:1)
https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/
或者只搜索n + 1查询问题