MySQL 递归查询

发布于 2024-08-25 03:29:15 字数 3358 浏览 2 评论 0原文

如何实现 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

错误消息:您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在第 1 行“0”附近使用的正确语法

这种方法启发了寻找 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);
        }
    }

这是 我的主要问题,我正在寻找建议!

How can I implement recursive MySQL Queries. I am trying to look for it but resources are not very helpful.

Trying to implement similar logic.

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

Error Message: 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 inspired to look for an MySQL recursive query approach.

Here is the Approach I was using Earlier:

Current Code:

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);
    }
}

Updated Code

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);
        }
    }

This was my Main Question for which I am looking for suggestions !!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

感情洁癖 2024-09-01 03:29:15
  • 该代码片段中没有任何递归
  • 连接字符串时使用了错误的运算符,它是 。 (点) 不是 +
  • 你必须使用类似 mysqli::multi_query( ) 要使用单个函数调用执行多个语句,这些语句必须用分隔符分隔(默认为分号)
  • 既然您已经使用了prepare()和execute(),为什么不简单地使用使其成为参数化准备好的语句,然后在循环的每次迭代中分配值并执行该语句? (到底什么是 $this 以及 $this->prepare() 返回什么类型的对象?)
  • 编辑和顺便说一句: $this->prepare() 表明您的类扩展了数据库类。它还保存一个文件描述符$this->fin。这有一定的代码味道。我的猜测是您的类使用/具有数据库/数据接收器对象和文件/数据源,但不是数据库+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);
  • There's nothing recursive in that code snippet.
  • The wrong operator is used to concatenate the strings, it's . (dot) not +
  • You'd have to use something like mysqli::multi_query() to execute more than one statement with a single function call and the statements would have to be separated by a delimiter character (by default a semicolon)
  • Since you're already using prepare() and execute() why not simply make it a parametrized prepared statement and then assign the values in each iteration of the loop and execute the statement? (Exactly what is $this and what type of object does $this->prepare() return?)
  • edit and btw: $this->prepare() indicates that your class extends a database class. And it also holds a file descriptor $this->fin. This has a certain code smell. My guess is that your class uses/has a database/datasink object and a file/datasource, but not is a database+readfile class. Only extend a class if your derived class is something.

edit: a simple example

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);
梦旅人picnic 2024-09-01 03:29:15

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

  • 检查您的数据是否确实需要解析,有时
  • ,首先通过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

a few tips about speeding up mysql data import

  • check if your data really requires to be parsed, sometimes load data works just fine for csv
  • if possible, create an sql file first via php and then execute it with mysql command line client
  • use multivalue inserts
  • disable keys before inserting

multivalue insert statement is something like

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

this is much faster than three distinct insert statements.

Disabling keys is important to prevent indexing each time you're executing an INSERT:

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

further reading http://dev.mysql.com/doc/refman/5.1/en/insert-speed.html

○闲身 2024-09-01 03:29:15

受到 这个问题的启发,我想说你应该这样做类似的东西。如果您确实有这么多数据,那么批量导入是最合适的方法。并且您已经将数据存储在文件中。

查看 LOAD DATA INFILE 命令。

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

如果您对速度差异感兴趣,请阅读 INSERT 语句的速度

例如,您可以这样做:

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

这也会忽略第一行,假设它仅指示列。

Inspired by this question I would say you should do something similar. If you really have so many data, then a bulk import is the most appropriate approach for this. And you already have the data in a file.

Have a look at the LOAD DATA INFILE command.

The LOAD DATA INFILE statement reads rows from a text file into a table at a very high speed. The file name must be given as a literal string.

If you are interested in the speed differences then read Speed of INSERT Statements.

E.g. you can do this:

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

This will also ignore the first line assuming that it only indicates the columns.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文