0

这个错误对我来说似乎是一个错误,因为我的查询中没有位置参数。这是方法:

public function getAll(User $user, DateTime $start = null, DateTime $end = null)
{
    $params = array('user_id' => $user->getId());

    $rsm = new \Doctrine\ORM\Query\ResultSetMapping(); // Result set mapping
    $rsm->addScalarResult('subtype', 'subtype');
    $rsm->addScalarResult('count',   'count');

    $sms_sql =
    "SELECT CONCAT('sms_', IF(is_auto = 0, 'user' , 'auto')) AS subtype, " .
    "SUM(messages_count * (customers_count + recipients_count)) AS count " .
    "FROM outgoing_message AS m INNER JOIN small_text_message AS s ON " . 
    "m.id = s.id WHERE status <> 'pending' AND user_id = :user_id";

    $news_sql =
    "SELECT CONCAT('news_', IF(is_auto = 0, 'user' , 'auto')) AS subtype, " .
    "SUM(customers_count + recipients_count) AS count " .
    "FROM outgoing_message AS m JOIN newsletter AS n ON m.id = n.id " .
    "WHERE status <> 'pending' AND user_id = :user_id";

    if($start) :
        $sms_sql        .= " AND sent_at >= :start";
        $news_sql       .= " AND sent_at >= :start";
        $params['start'] = $start->format('Y-m-d');
    endif;

    $sms_sql  .= ' GROUP BY type, is_auto';
    $news_sql .= ' GROUP BY type, is_auto';

    return $this->_em->createNativeQuery("$sms_sql UNION ALL $news_sql", $rsm)
        >setParameters($params)->getResult();
}

这引发了异常:

SQLSTATE[HY093]:无效参数号:混合命名参数和位置参数

数组$params没问题,因此生成了 SQL

var_dump($params);

array (size=2)
  'user_id' => int 1
  'start' => string '2012-01-01' (length=10)

最奇怪的是它只适用于"$sms_sql"

更新

又发现了一件奇怪的事。如果我只更改名称(改为start_date而不是start):

    if($start) :
        $sms_sql             .= " AND sent_at >= :start_date";
        $news_sql            .= " AND sent_at >= :start_date";
        $params['start_date'] = $start->format('Y-m-d');
    endif;

发生的事情是 Doctrine/PDO 说:

SQLSTATE [42S22]:找不到列:1054 'where 子句'中的未知列'sent1rt_date'

...因为1rt在列名中间添加了字符串!

4

1 回答 1

2

我相信问题在于对 NativeSQL 的 Doctrine ORM 支持。

setParameters我在用于命名参数的方法的文档中找不到任何示例。我看到的所有使用该方法的示例都是针对位置的,而不是命名的。

命名参数的所有示例都使用setParameter(没有“s”)方法。而且它们仅在 SQL 中显示匹配占位符的一次出现。

作为一项测试(并且作为一种可能的解决方法),尝试使 SQL 文本中的每个占位符都是唯一的,然后分别设置每个占位符。

看起来“命名参数”支持可能有些不完整(与我们习惯使用的 Oracle 和其他 ORM 框架相比)。看起来 Doctrine 可能对位置符号有更好的支持。(这对于简单的语句非常有用,但是当您有很多参数并且您需要对 SQL 语句进行更改时,它可能是一个真正的负担。这就是命名参数的好处真正开始发挥作用的地方......如果它们是支持的权利。)

这是 Doctrine ORM 文档的链接http://doctrine-orm.readthedocs.org/en/latest/reference/query-builder.html?highlight=setParameterssetParameters在该页面上搜索示例。)

(请参阅我对您问题的评论。)

这可能无法真正回答您的问题,但它可能会让您朝着正确的方向前进。在外面小心点。

于 2012-07-06T21:11:27.903 回答