【问题标题】:PDO prepared statement with prepared sub-queries带有准备好的子查询的 PDO 准备好的语句
【发布时间】:2017-09-17 20:27:47
【问题描述】:

有一个用不同方法准备的复杂查询。这是一个伪代码(不是实际代码):它会在一种方法中准备一个查询,然后在另一种方法中准备一个子查询。

这个想法是其他方法可以添加一些其他查询部分,添加一些条件,并可能对其他表进行一些连接。并且所有子查询都会在他们的方法中准备好。

最后,结果查询将在原始方法中执行。

class{//pseudo code

public function getData($name,$club){
  $pdo = new PDO($dsn, $user, $pass, $opt);
  $stm1 = $pdo->query('SELECT name FROM users WHERE quote=?');
  $stm1 = $pdo->prepare('1');

  $stm2 = $this->getQueryPart();
  $stm1->statementBind($stm2);
  $stm1->execute();

  return $query;
}
protected function getQueryPart(){
  $pdo = new PDO($dsn, $user, $pass, $opt);
  $pdo->prepare('AND email = ? AND status=?', ['email@foobar.com','1']);
  return $pdo;
}

【问题讨论】:

  • 第一个查询中有语法错误。而且在每个函数中创建一个新的连接听起来效率不高,为什么不把它作为参数传递呢?
  • 你不能像这样链接查询,prepare() 接受一个查询字符串,你不能通过这样调用它来添加条件。最后的 querystirng 应该传递给prepare()
  • @Qirel,它不是一次声明,而是 三次 声明它是一个伪代码 - 你不能期望伪代码运行,因为它实际上不是一些正确的代码。更不用说语法错误了。

标签: php sql pdo subquery prepared-statement


【解决方案1】:

仅使用 PDO 是不可能的。您必须创建一个查询构建器类(或使用现有的众多类之一)包装 PDO,它将保存所有查询的属性,并一次构建完整的查询就在你执行它之前。

这是一个如何工作的基本示例:

class Query {
    private $select;
    private $from;
    private $where = [];

    /**
     * Defines the column list (SELECT {$columns})
     *
     * @param string $columns
     * @return this
     */
    public function select($columns) {
        $this->select = $columns;
        return $this;
    }

    /**
     * Defines the table to select from (SELECT * FROM {$table})
     *
     * @param string $table
     * @return this
     */
    public function from($table) {
        $this->from = $table;
        return $this;
    }

    /**
     * List of conditions to AND (key = column, value = value)
     * e.g. $query->where(['name' => 'bob'])
     *
     * @param mixed[string] $conditions
     * @return $this
     */
    public function where(array $conditions) {
        $this->where = $conditions;
        return $this;
    }

    /**
     * Adds an AND condition
     *
     * @param string $column
     * @param mixed $value
     * @return this
     */
    public function where_and($column, $value) {
        $this->where[$column] = $value;
        return $this;
    }

    /**
     * Builds and executes the query, returning a PDOStatement
     *
     * @return PDOStatement
     */
    public function execute() {
        $query = sprintf(
            'SELECT %s FROM %s',
            $this->select,
            $this->from
        );

        $placeholders = array();

        if (!empty($this->where)) {
            $query .= ' WHERE ';

            $index = 0;
            foreach ($this->where as $column => $value) {
                if ($index > 0) {
                    $query .= ' AND ';
                }

                $query .= sprintf('`%s`', $column);

                if ($value === null) {
                    $query .= ' IS NULL';
                } else {
                    $placeholder = sprintf(':placeholder_%d', $index);

                    $query .= ' = ' . $placeholder;
                    $placeholders[$placeholder] = $value;
                }

                $index++;
            }
        }

        $pdo = new PDO($dsn, $user, $pass, $opt);
        $stmt = $pdo->prepare($query);
        $stmt->execute($placeholders);
        return $stmt;
    }
}

例如,通过这个类,您可以执行以下操作:

class MyClass {
    public function getData($name, $club) {
        $query = new Query();
        $query->select('name')
              ->from('users')
              ->where(['quote' => '1']);

        $this->getQueryPart($query);
        $result = $query->execute();

        return $result->fetchAll(PDO::FETCH_ASSOC);
    }

    protected function getQueryPart($query) {
        $query->where_and('email', 'email@foobar.com')
              ->where_and('status', 1);
    }
}

查看此处的示例,该示例实际上并未执行查询,但会打印将执行的查询和占位符:https://3v4l.org/iKu2K

请注意,这是一个非常基本的示例,只是为了让您了解如何进行此类操作。在现实世界的场景中,您可能希望通过OR-conditions 以及LIKE!= 检查的功能来扩展它,甚至可能对条件进行分组,以便您可以执行WHERE a = 1 AND (b = 2 OR c = 5) 之类的操作。更不用说添加对JOINORDER BYLIMIT 和其他花哨的东西的支持了。

【讨论】:

  • 好答案!不过请注意:prepare > bind > execute > fetch 工作流程——包括验证和异常处理——是数据库适配器类的任务。例如,查询构建器只负责构建 sql 语句。这是我的a DbAdapter class 的示例(编辑部分),如果您感兴趣的话。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2012-10-10
  • 1970-01-01
  • 2010-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多