I'm trying to get a query working using a case statement, and can't figure out how to get the case to return a column value instead of a constant. I have the query working perfectly, except that the column names I'm providing for the results are being quoted or otherwise mishandled by Cake or maybe PDO somewhere down in a layer that I can't dig my way through. I got as far down as bindValue, but none of the documentation I encountered along the way tells me how to do this.
I have found this example comment:
$statement->bindValue(1, 'a title');
$statement->bindValue(2, 5, PDO::INT);
$statement->bindValue('active', true, 'boolean');
$statement->bindValue(5, new \DateTime(), 'date');
but in all these cases, the value provided is a constant. I need to pass in a string that is the name of the column that I want returned.
I tried both 'string'
(resulted in quoted column name) and 'integer'
(resulted in 0). I tried PDO::FETCH_COLUMN
(seemed highly unlikely, but looked like the next best bet from http://php.net/manual/en/pdo.constants.php, and easy to try it...). I tried 'literal'
, inspired by the way you can put literal strings into expressions (resulted in Error: unknown type "literal"
). That error message led me to src/Database/Type.php
, but nothing in there helped me either.
So, I'm pretty much stumped. Here's a simple version of the code I have (leaving out a couple of conditions and unrelated columns):
$query = $this->Games->find();
$team_id = $query->newExpr()->addCase(
[$query->newExpr()->eq('Games.status', 'home_default')],
['home_team_id', 'away_team_id'],
['string', 'string']
);
$defaulting = $query
->select([
'id' => $team_id,
'count' => 'COUNT(Games.id)',
])
->where([
'Games.status IN' => ['home_default', 'away_default'],
])
->group('id')
->toArray();
This generates this SQL:
SELECT
(CASE WHEN Games.status = 'home_default'
THEN 'home_team_id' ELSE 'away_team_id' END) AS `id`,
COUNT(Games.id) AS `count`
FROM games Games
WHERE Games.status in ('home_default','away_default')
GROUP BY id
Note that THEN 'home_team_id' ELSE 'away_team_id' END
should be simply THEN home_team_id ELSE away_team_id END
. This will then allow me to read the list of ids of teams that have defaulted games along with the number of games they defaulted.
By default the values passed to the second argument of QueryExpression::addCase()
are being treated as to be converted to literal values, not as identifiers. If you need the latter, then you should use an expression, an IdentifierExpression
.
use Cake\Database\Expression\IdentifierExpression;
// ...
$team_id = $query->newExpr()->addCase(
[
$query->newExpr()->eq('Games.status', 'home_default')
],
[
new IdentifierExpression('Games.home_team_id'),
new IdentifierExpression('Games.away_team_id')
]
);
Also ditch the third argument in this case, you don't want the values to be string literals (for expressions the types would be ignored anyways).
来源:https://stackoverflow.com/questions/33383845/what-type-do-i-specify-in-addcase-to-return-a-column