简体   繁体   中英

SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters

This error to me seems a bug because there are no positional parameters in my query. Here is the method:

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

And this throws the exception:

SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters

Array $params is OK and so generated SQL :

var_dump($params);

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

The strangest thing is that it works with "$sms_sql" only!

Update

Found another strange thing. If I change only the name (to start_date instead of 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;

What happens is that Doctrine/PDO says:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sent1rt_date' in 'where clause'

... as string 1rt was added in the middle of the column name!

I believe the problem is with the Doctrine ORM support for NativeSQL.

I don't find any examples in the documentation of the setParameters method being used for named parameters. All of the examples I see of that method being used are for positional, rather than named.

All of the examples for named parameters use the setParameter (with no "s") method. And they only show a single occurrence of a matching placeholder in the SQL.

As a test (and as a possible workaround), try making each placeholder in the SQL text unique, and then set each one separately.

It looks like "named parameter" support may be somewhat incomplete (compared to what we are used to with Oracle and other ORM frameworks). It looks like Doctrine may have better support for the positional notation. (Which is great for simple statements, but it can be a real bear when you have lots of parameters, and you need to make changes to a SQL statement. That's where the benefit of named parameters really begins to shine... if they are supported right.)

Here's a link to the Doctrine ORM documentation http://doctrine-orm.readthedocs.org/en/latest/reference/query-builder.html?highlight=setParameters (Search for setParameters on that page for examples.)

(See my comments on your question.)

That may not really answer your question, but it may get you moving in the right direction. Be careful out there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM