【问题标题】:Inserting a multi-dimensional php array into a mysql database将多维php数组插入mysql数据库
【发布时间】:2011-12-06 11:58:00
【问题描述】:

我有一个来自 csv 的数组,其结构与此类似:

$array = array(
    array('name', 'age', 'gender'),
    array('Ian', 24, 'male'),
    array('Janice', 21, 'female')
);

我想将它插入到 MySQL 表中,其中第一个数组(姓名、年龄、性别)的项目是列标题,每个后续数组都是表中的一行。

有人可以建议最好的方法吗?

【问题讨论】:

    标签: php mysql multidimensional-array


    【解决方案1】:
    $fields = implode(',', array_shift($array)); // take the field names off the start of the array
    
    $data = array()
    foreach($array as $row) {
        $name = mysql_real_escape_string($row[0]);
        $age = (int) $row[1];
        $gender = mysql_real_escape_string($row[2]);
        $data[] = "('$name', $age, '$gender')";
    }
    
    $values = implode(',', $data);
    
    $sql = "INSERT INTO yourtable ($fields) VALUES $values";
    $result = mysql_query($sql) or die(mysql_error());
    

    这应该产生一个查询字符串,如:

    INSERT INTO yourtable (name, age, gender) VALUES ('Ian', 24, 'male'), ('Janice', 21, 'female'), etc....
    

    【讨论】:

    • 一个问题可能是变量 $name $age $gender 每次都会不同,它们的数量也会不同,所以我可以从第一个数组中获取变量名吗?像计算第一个数组中的元素然后递增它。所以变量将类似于 - $data[0][$x] ?
    • 只要数组中的第一行包含字段名,第二、第三等行有值,那么这个函数将处理任意数量的行。达到 PHP 的内存限制以及查询字符串增长到超过 mysql 的 max_allowed_pa​​cket 限制的任何点。
    • @MarcB 我认为他在谈论不同数量的字段,而不是行。
    • @Aurelio:啊。明白了。在那种情况下,不,这段代码只做 3 个字段。
    • 是的,抱歉,我可能不太清楚。因为我并不总是知道字段的数量和标题。所以我认为 Aurelio 的代码会做到这一点。谢谢
    【解决方案2】:

    假设数组中的值是TRUSTEDSECURE

    $count = count($array);
    $keys = $array[0];
    
    for($i = 1; $i < $count; $i++)
    {
       $query = "INSERT INTO tablename (" . implode(",", $keys) . ") VALUES ('" . implode ("','", $array[$i]) . "');";
       $query = str_replace(',)', ')', $query);
       mysql_query($query);
    }
    

    【讨论】:

    • 引用字段名会将它们转换为字符串,它们将不再被视为字段名。否则,大部分看起来都不错。
    • 你知道为什么我可能会在 implode() 上收到“传递的参数无效”警告吗?
    • @chentudou 你确定你复制好的代码吗?我在发布之前尝试过它并且效果很好。此外,如您所见,如果有更多(或更少)然后 3 个字段,此代码也将起作用。
    • 我又试了一次...内爆警告消失了,但它说 SQL 语法有错误。我会继续努力,可能是我的错误。
    • @AurelioDeRosa:你为 implode 交换了参数。已编辑。
    【解决方案3】:

    对于这个数组,你可以做一些简单的事情:

    $array = csv_array(); // this is your array from csv
    
    $col_name = $array[0][0];
    $col_age = $array[0][1];
    $col_gender = $array[0][2];
    
    for($i = 1; $i < count($array); $i++){
        //this is where your sql goes
        $sql = "INSERT INTO `table` ($col_name, $col_age, $col_gender) 
        VALUES($array[$i][0], $array[$i][1], $array[$i][2])";
    
        $db->query($sql);
    }
    

    您应该清理输入,我在示例中没有这样做。如果您的数组结构不能保证相同,那么您将不得不做其他事情。

    【讨论】:

      【解决方案4】:

      以下代码可以工作,但它假定所有嵌套数组的长度相同,换句话说,每个嵌套数组都包含第一个嵌套数组中定义的所有属性的值。

      $array = array(
          array('name', 'age', 'gender' ),
          array('Ian', 24, 'male'),
          array('Janice', 21, 'female')
      );
      
      $fields = implode(', ', array_shift($array));
      
      $values = array();
      foreach ($array as $rowValues) {
          foreach ($rowValues as $key => $rowValue) {
               $rowValues[$key] = mysql_real_escape_string($rowValues[$key]);
          }
      
          $values[] = "(" . implode(', ', $rowValues) . ")";
      }
      
      $query = "INSERT INTO table_name ($fields) VALUES (" . implode (', ', $values) . ")";
      

      此解决方案适用于第一个嵌套数组中定义的任意数量的属性,只要所有其他嵌套数组的长度相同。对于上面的数组,输出将是:

      INSERT INTO table_name (name, age, gender) VALUES (Ian, 24, male), (Janice, 21, female)
      

      有关演示,请参阅http://codepad.org/7SG7lHaH,但请注意,我删除了 codepad.org 上对 mysql_real_escape_string() 的调用,因为它们不允许该函数。在你自己的代码中你应该使用它。

      【讨论】:

      • 一旦您使用 implode 将它们放入数据库中,您如何将它们分解为您之前拥有的原始数组?我目前正在处理同样的问题
      • “字段列表”中的未知列“Ian”是您的输出。代码不起作用
      【解决方案5】:

      你可以这样做:

      $rows = array(
          array('name', 'age', 'gender'),
          array('Ian', 24, 'male'),
          array('Janice', 21, 'female')
      );
      
      $columns = array_shift($rows);
      
      $rows = array_map(function($row) {
          /*
           * TODO: escape column values
           */
      
         return '"' . implode('", "', $row) . '"';
      }, $rows);
      
      $sql = 'INSERT  INTO ...
                      (' . implode(', ', $columns) . ')
              VALUES  (' . implode('), (', $rows) . ')';
      

      由于mysql(扩展)会在插入时“转换”你的值,你不需要注意列类型:如果列定义为整数,在数据库中,它将被插入为整数,甚至如果您引用该值(例如:年龄)。

      注意我在源代码中标记的TODO:插入值是非常不安全的,而不转义它们(SQL注入)。

      【讨论】:

        【解决方案6】:

        我的解决方案有两种方法。

        1. 将数组值保存为简单 DB 表中数据的序列化表示形式。

        2. 将数组值保存在单独的表字段中。

        工作示例:

        $array = array(
            0 => array ( "name", "age", "gender"),
            1 => array ( "Ian", "24", "male"),
            2 => array ( "Janice", "21", "female")
        );
        
        foreach($array as $key1 => $value1){
            foreach($value1 as $key2 => $value2){
                // assuming the first element (0) in the array is the header value and the header value is a valid array key
                 if($key1 > 0){
                      $items[$key1-1][ $array[0][$key2] ] = $value2;
                 }
            }    
        }
        
        // 1. store values as serialized representation
        foreach ($items as $key => $value) {
            $sql = "INSERT INTO datatable SET data = ".mysql_real_escape_string(serialize($value))."";
            echo $sql.PHP_EOL;
        }
        
        // 2. auto create fields in database and store values
        foreach ($array[0] as $key1) {
            $sql = "ALTER TABLE forms ADD '".$key1."' TEXT NOT NULL";
            echo $sql.PHP_EOL;
        }
        foreach ($items as $key1 => $value1) {
            foreach($value1 as $key2 => $value2){
                $sql = "INSERT INTO datatable SET ".$key2." = '".mysql_real_escape_string($value2)."'";
                echo $sql.PHP_EOL;
            }
        }
        

        【讨论】:

          【解决方案7】:

          数组

          $arrayData = array(
               array(
                  'name' => 'Paul',
                  'age' => 28,
                  'gender' => 'male',
          
          
              ),
               array(
          
                  'name' => 'Rob',
                  'age' => 23,
                  'gender' => 'male',
          
          
              )
          );
          
           foreach($arrayData as $data){
          
                  $query = "INSERT INTO persons (name,gender,age)
                  VALUES ('$data[name]', '$data[gender]',  $data[age])";
          
                  //echo $query;die;
                      mysql_query($query) or die(mysql_error());
                      //exit;
              }
          

          【讨论】:

            【解决方案8】:

            做这种事情的最好方法是在 PDO 库的帮助下使用准备好的语句和事务。 PDO 是 PHP 中任何数据库交互的最简单选择。

            准备好的语句快速、简单,并且它们提供参数绑定,可以保护您免受 SQL 注入的副作用。

            数据库事务确保所有数据都插入或根本不插入。它们还可以显着提高此类任务的性能。

            这是一个示例代码:

            // create new connection to MySQL using PDO class
            $pdo = new \PDO("mysql:host=$host;dbname=$db;charset=$charset", $user, $pass, [
                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                \PDO::ATTR_EMULATE_PREPARES => false
            ]);
            
            $array = array(
                array('name', 'age', 'gender'),
                array('Ian', 24, 'male'),
                array('Janice', 21, 'female')
            );
            
            // discard the header row (1st row) from the array
            array_shift($array);
            
            // start transaction
            $pdo->beginTransaction();
            
            // prepre SQL statemenet with 3 placeholders
            $stmt = $pdo->prepare('INSERT INTO csv_table(name, age, gender) VALUES(?,?,?)');
            foreach ($array as $row) {
                $stmt->execute($row);
            }
            
            // end transaction
            $pdo->commit();
            

            标题行呢?

            正如您在上面的代码中看到的,我正在丢弃标题行。由于 SQL 表是刚性的,我需要事先知道列的名称是什么。如果您想动态地将 CSV 中的列与架构中的列进行匹配,那么您需要添加一些逻辑来查看硬编码的列列表(您也可以从 information_schema 获取此信息)并将其与名称匹配CSV 中的列数。

            代码可以调整如下。如果您的代码中未定义任何列,则迭代 CSV 中的列名并引发异常。如果所有列都经过验证,则implode() 列名并将其注入您的 SQL 字符串。

            $array = array(
                array('name', 'age', 'gender'),
                array('Ian', 24, 'male'),
                array('Janice', 21, 'female')
            );
            
            $table_columns = ['age', 'gender', 'name'];
            
            // Validate CSV header row (1st row) against your schema columns
            $header = array_shift($array);
            foreach ($header as $col_name) {
                if (!in_array($col_name, $table_columns, true)) {
                    throw new \Exception('Incorrect column name specified in CSV file');
                }
            }
            
            // start transaction
            $pdo->beginTransaction();
            
            // prepre SQL statemenet with 3 placeholders
            $stmt = $pdo->prepare('INSERT INTO csv_table('.implode(',', $header).') VALUES(?,?,?)');
            foreach ($array as $row) {
                $stmt->execute($row);
            }
            
            // end transaction
            $pdo->commit();
            

            【讨论】:

              【解决方案9】:

              将多数组插入 SQL 的最直接方法可能是:

              $queryIn = "INSERT INTO table (resultsArray) values (" . print_r($multiArray, true) . "')";
              

              这行得通。

              【讨论】:

                猜你喜欢
                • 2011-12-12
                • 2015-02-20
                • 2017-05-18
                • 2014-05-28
                • 2017-07-03
                • 1970-01-01
                • 2017-06-21
                • 1970-01-01
                • 2014-10-31
                相关资源
                最近更新 更多