学说在哪里出问题

时间:2014-09-11 15:19:57

标签: php mysql doctrine-orm doctrine silex

在开始之前,我相信我已尝试过上一篇文章:How to use WHERE IN with Doctrine 2

所以我有一个Silex应用程序通过作曲家使用Doctrine连接到MySQL数据库(doctrine / dbal 2.2。*)

我尝试运行的查询构建器是:

$qb = $this->db->createQueryBuilder();

$stmt = $qb->select('DAY(datefield1) x, COUNT(*) value')
    ->from('table1', 's')
    ->join('s', 'table2', 't', 't.key=s.key')
    ->where('MONTH(datefield1) = :billMonth')
    ->andWhere('YEAR(datefield1) = :billYear')
    ->andWhere('t.key IN (:keylist)')
    ->groupBy('x')
    ->orderBy('x', 'asc')
    ->setParameter(':billMonth', $month)
    ->setParameter(':billYear', $year)
    ->setParameter(':keylist', implode(",", $keylist))
    ->execute();

return $stmt->fetchAll(\PDO::FETCH_ASSOC);

参数是(月= 8)(年= 2014)(密钥列表=数组(1,2,3,4))

查询不会失败,但奇怪的是它并不包含它应该包含的所有数据。

我已经尝试过 - > gt; setParameter(':keylist',$ keylist)来使用原始数组,但这并没有用。

我也试过这种语法:

$ qb->添加('其中',$ qb-> expr() - > in(' r.winner',数组(&#39 ;? 1')));

然而,由于in方法在表达式构建器类中不可用,因此引发了错误。

请有人注意这一点,让我不必对我的SQL进行硬编码吗?

6 个答案:

答案 0 :(得分:2)

好看,因为这个旧线程已经看到了一些动作,因为我上次查看我想确认问题已经很久解决了 - setParameter中的第三个参数允许您通知Doctrine如何处理数组:

    $qb = $this->db->createQueryBuilder();

    $stmt = $qb
        ->select('*')
        ->from(self::DB_TABLE, 'x')
        ->where('x.service IN (:services)')
        ->orderBy('x.session_end', 'DESC')
        ->addOrderBy('x.direction', 'DESC')
        ->setParameter(':services', $services, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
        ->setFirstResult($offset)
        ->setMaxResults($count)
        ->execute();

    $result = $stmt->fetchAll(\PDO::FETCH_ASSOC);

答案 1 :(得分:1)

DB占位符/参数用于单个值。由于在数组上调用1,2,3,4,您传入的是整体字符串implode()。给出:

WHERE t.key IN (:keylist)

然后此查询将作为等效的

执行
WHERE t.key IN ('1,2,3,4')
                ^-------^---note the quotes

因为它是一个字符串,而IN子句中只有一个字符串,所以它的功能相当于

WHERE t.key = '1,2,3,4'

而不是

WHERE (t.key = 1 OR t.key = 2 OR ....)

你想要它。设置多个参数,一个用于数组中的每个值,或者直接在查询中嵌入字符串

->andWhere('t.key IN (' . implode(',', $keylist) . ')')

这当然会让你了解sql注入攻击漏洞。

答案 2 :(得分:1)

如果你自己构建sql查询,你可以使用DBAL的PARAM_INT_ARRAY类型:

use Doctrine\DBAL\Connection as DB;

$db->executeQuery('SELECT DAY(datefield1) x, COUNT(*) value
FROM table1 s
JOIN table2 t ON t.key=s.key
WHERE MONTH(datefield1) = :billMonth
    AND YEAR(datefield1) = :billYear
    AND t.key IN (:keylist)
GROUP BY x
ORDER BY x ASC',
array(':billMonth' => $month, ':billYear' => $year, ':keylist' => $keylist),
array(':billMonth' => \PDO::PARAM_INT, ':billYear' => \PDO::PARAM_INT, ':keylist' => DB::PARAM_INT_ARRAY
)->fetchAll(\PDO::FETCH_ASSOC);

答案 3 :(得分:0)

处理此类IN子句的正确方法非常简单:

$qb = $this->db->createQueryBuilder();

$stmt = $qb->(...)
    ->andWhere('t.key IN (:keylist)')
    ->setParameter(':keylist', $keylist)
    ->getQuery()
    ->getArrayResult();

我已经使用了十几次并且它有效 - 教义非常聪明,可以处理你的$keylist数组。

另一件事是,我不知道你为什么要使用fetchAll方法,这里的方法是还原剂 - execute()就足够了。也许这是你问题的根源。

我的建议:尝试以开发模式(app_dev.php)触发操作并检查app/logs/dev.log - 您将找到所有执行的SQL查询。验证数据库是否返回了您希望从Doctrine中获取的数据。

答案 4 :(得分:0)

    ->add('where', $qb->expr()->andX(                    
                        $qb->expr()->in('r.winner', ':winner')
                    ))
                ->setParameters(array(
                        "winner" => $winners,
                        "billMonth", $month,
                     // add all params here
                    ));

答案 5 :(得分:0)

您应该通过如下所示的querybuilder使用in表达式,并更改设置参数的方式:

->andWhere($qb->expr()->in('t.key', ':keylist'))

完整的代码:

$qb = $this->db->createQueryBuilder();
$stmt = $qb->select('DAY(datefield1) x, COUNT(*) value')
    ->from('table1', 's')
    ->join('s', 'table2', 't', 't.key=s.key')
    ->where('MONTH(datefield1) = :billMonth')
    ->andWhere('YEAR(datefield1) = :billYear')
    ->andWhere('t.key')
    ->andWhere($qb->expr()->in('t.key', ':keylist'))
    ->groupBy('x')
    ->orderBy('x', 'asc')
    ->setParameter(':billMonth', $month)
    ->setParameter(':billYear', $year)
    ->setParameter(':keylist', $keylist)
    ->execute();

return $stmt->fetchAll(\PDO::FETCH_ASSOC);