递归MySQL查询

时间:2010-03-12 19:48:33

标签: php mysql recursion

如何实现递归MySQL查询。我试图寻找它,但资源不是很有帮助。

尝试实现类似的逻辑。

public function initiateInserts()
{
    //Open Large CSV File(min 100K rows) for parsing.
    $this->fin = fopen($file,'r') or die('Cannot open file');

    //Parsing Large CSV file to get data and initiate insertion into schema.
    $query = "";
    while (($data=fgetcsv($this->fin,5000,";"))!==FALSE)
    {
        $query = $query + "INSERT INTO dt_table (id, code, connectid, connectcode) 
                 VALUES (" + $data[0] + ", " + $data[1] + ", " + $data[2] + ", " + $data[3] + ")";
    }
     $stmt = $this->prepare($query);
     // Execute the statement
     $stmt->execute();
     $this->checkForErrors($stmt);
}

@Author:Numenor

错误讯息:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '0' at line 1

This Approach启发了寻找MySQL递归查询方法。

以下是我之前使用的方法:

当前代码:

public function initiateInserts()
{
    //Open Large CSV File(min 100K rows) for parsing.
    $this->fin = fopen($file,'r') or die('Cannot open file');

    //Parsing Large CSV file to get data and initiate insertion into schema.
    while (($data=fgetcsv($this->fin,5000,";"))!==FALSE)
    {
        $query = "INSERT INTO dt_table (id, code, connectid, connectcode) 
                 VALUES (:id, :code, :connectid, :connectcode)";

        $stmt = $this->prepare($query);
        // Then, for each line : bind the parameters
        $stmt->bindValue(':id', $data[0], PDO::PARAM_INT);
        $stmt->bindValue(':code', $data[1], PDO::PARAM_INT);
        $stmt->bindValue(':connectid', $data[2], PDO::PARAM_INT);
        $stmt->bindValue(':connectcode', $data[3], PDO::PARAM_INT);

        // Execute the statement
        $stmt->execute();
        $this->checkForErrors($stmt);
    }
}

更新的代码

public function initiateInserts()
{
    //Open Large CSV File(min 100K rows) for parsing.
    $this->fin = fopen($file,'r') or die('Cannot open file');

    //Prepare insertion query to insert data into schema.
    $query = "INSERT INTO dt_table (id, code, connectid, connectcode) 
                 VALUES (:id, :code, :connectid, :connectcode)";

    $stmt = $this->prepare($query);
    // Then, for each line : bind the parameters
    $stmt->bindValue(':id', $data[0], PDO::PARAM_INT);
    $stmt->bindValue(':code', $data[1], PDO::PARAM_INT);
    $stmt->bindValue(':connectid', $data[2], PDO::PARAM_INT);
    $stmt->bindValue(':connectcode', $data[3], PDO::PARAM_INT);

  //Loop through CSV file and execute inserts prepared, but this is not working
  //and there are not data being populated into database. 
   while (($data=fgetcsv($this->fin,5000,";"))!==FALSE)
        {
            // Execute the statement
             list($id, $code, $connid, $conncode)=$data;

            $stmt->execute();
            $this->checkForErrors($stmt);
        }
    }

这是my Main Question我正在寻找建议!!!

3 个答案:

答案 0 :(得分:3)

  • 该代码段中没有recursive
  • 错误的运算符用于连接字符串,. (dot)不是+
  • 你必须使用像mysqli::multi_query()这样的东西来执行一个带有单个函数调用的语句,并且语句必须用分隔符分隔(默认是分号)
  • 由于您已经在使用prepare()和execute(),为什么不简单地将它作为参数化的预准备语句,然后在循环的每次迭代中分配值并执行语句? (究竟什么是$ this以及$ this-> prepare()返回什么类型的对象?)
  • edit and btw:$this->prepare()表示您的类扩展了数据库类。它还包含一个文件描述符$this->fin。这有一定的code smell。我的 guess 是您的类使用/具有数据库/数据链接对象和文件/数据源,但 是数据库+ readfile类。如果您的派生类,则只扩展一个类。

编辑:一个简单的例子

class Foo {
  protected $pdo;
  public function __construct(PDO $pdo) {
    $this->pdo = $pdo;
  }

  public function initiateInserts($file)
  {
    $query = '
      INSERT INTO
        dt_table_tmp
        (id, code, connectid, connectcode)
      VALUES
        (:id, :code, :connid, :conncode)
    ';
    $stmt = $this->pdo->prepare($query);
    $stmt->bindParam(':id', $id);
    $stmt->bindParam(':code', $code);
    $stmt->bindParam(':connid', $connid);
    $stmt->bindParam(':conncode', $conncode);

    $fin = fopen($file, 'r') or die('Cannot open file');
    while ( false!==($data=fgetcsv($fin,5000,";")) ) {
      list($id, $code, $connid, $conncode)=$data;
      $stmt->execute();
    }
  }
}

$pdo = new PDO("mysql:host=localhost;dbname=test", 'localonly', 'localonly'); 
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// set up a demo table and some test data
$pdo->exec('CREATE TEMPORARY TABLE dt_table_tmp (id int, code int, connectid int, connectcode int)');
$sourcepath = 'sample.data.tmp';
$fh = fopen($sourcepath, 'wb') or die('!fopen(w)');
for($i=0; $i<10000; $i++) {
  fputcsv($fh, array($i, $i%4, $i%100, $i%3), ';');
}
fclose($fh); unset($fh);
// test script
$foo = new Foo($pdo);
$foo->initiateInserts($sourcepath);

答案 1 :(得分:1)

关于加快mysql数据导入的一些提示

  • 检查您的数据是否真的需要解析,有时load data适用于csv
  • 如果可能,首先通过php创建一个sql文件,然后使用mysql命令行客户端
  • 执行它
  • 使用多值插入
  • 插入前禁用密钥

多值插入语句类似于

INSERT INTO users(name, age) VALUES
     ("Sam", 13), 
     ("Joe", 14),
     ("Bill", 33);

这比三个不同的插入语句快得多。

禁用密钥对于每次执行INSERT时阻止索引非常重要:

 ALTER TABLE whatever DISABLE KEYS;
 INSERT INTO whatever .....  
 INSERT INTO whatever .....  
 INSERT INTO whatever .....  
 ALTER TABLE whatever ENABLE KEYS;

进一步阅读http://dev.mysql.com/doc/refman/5.1/en/insert-speed.html

答案 2 :(得分:0)

灵感来自this question我会说你应该做类似的事情。如果您确实拥有这么多数据,那么批量导入是最合适的方法。并且您已将数据存储在文件中。

查看LOAD DATA INFILE命令。

  

LOAD DATA INFILE语句以非常高的速度将文本文件中的行读取到表中。文件名必须以文字字符串形式给出。

如果您对速度差异感兴趣,请阅读Speed of INSERT Statements

E.g。你可以这样做:

$query = "LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
          FIELDS TERMINATED BY ';' 
          LINES TERMINATED BY '\r\n'
          IGNORE 1 LINES;
         "

这也会忽略第一行,假设它只表示列。