在数据库插入之前验证xlsx文件的正确方法

Kav*_*aft 8 php mysql phpexcel

在玩PHPExcel时,我遇到了一些问题,如何正确处理验证/并将值插入数据库.我不需要任何代码,只需要一般的概念如何做.

首先,我遍历第一行以检查列是否与给定的列匹配(如果它适合模式).

在下一步,我得到行,同时它的beeing验证行/列明智.如果类型不匹配,我将收到错误.

在验证行时,我需要获取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');
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

显示

 try {

            $data['s'] = $this->gm
                    ->read_data($sheetData)
                    ->column_validation()
                    ->get_sheet_data()
                    ->display_errors()
                    ->display_result();


        } catch (Exception $e) {

            $data['ex'] = $e->getMessage();
        }
Run Code Online (Sandbox Code Playgroud)

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) |
+---+---------------+---+---+------------+---------+--------------+-----------+-------------+---------------+----------------+------------+------------+--------+
Run Code Online (Sandbox Code Playgroud)

小智 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
}
Run Code Online (Sandbox Code Playgroud)

同样,对于问题 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
Run Code Online (Sandbox Code Playgroud)

如果数据没有问题,那么您可以从临时表执行 INSERT 到数据表中。这将您的查询限制为初始插入(您也可以批处理以获得更好的性能)、数据检查以及从临时数据到实际数据的插入。

回顾

这一切都取决于您的应用程序。如果您可以不用执行选项 1 并且已经实现了它,那么现在就可以了。如果您没有看到此应用程序疯狂增长,则无需过度优化。

但是,如果您担心规模和增长,那么我个人会考虑实施选项 3。