I want to replicate the following query which sorts all users by name, but those whose names start with Z come first:
SELECT *
FROM user
ORDER BY LEFT(name, 1) != 'Z', name
I have this:
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('u')
->addSelect($qb->expr()->neq($qb->expr()->substring('u.name', 1, 1), $qb->expr()->literal('Z')) . ' AS HIDDEN firstLetterIsNotZ')
->from(user::class, 'u')
->orderBy('firstLetterIsNotZ')
->addOrderBy('u.name');
The generated DQL looks sane enough:
SELECT s, SUBSTRING(u.name, 1, 1) <> 'Z' AS HIDDEN descriptionFirstLetter
FROM user u
ORDER BY firstLetterIsNotZASC, s.description ASC
But the lexer does not like it: Error: Expected Doctrine\\ORM\\Query\\Lexer::T_FROM, got '<'
Doctrine does not handle conditions well inside of the select statement.
You can circumvent the issue by wrapping your condition with a CASE WHEN
to produce your desired result.
I've also parameterized the letter condition to allow it to be more portable, in case you wish to add it as dynamic value.
$em = $this->getEntityManager();
$expr = $em->getExpressionBuilder();
$q = $em->createQueryBuilder()
->select('u')
->addSelect('(CASE WHEN ' . $expr->neq($expr->substring('u.name', 1, 1), ':letter') . ' THEN 0 ELSE 1 END) AS HIDDEN firstLetterIsNotZ')
->from(user::class, 'u')
->orderBy('firstLetterIsNotZ')
->addOrderBy('u.name')
->setParameter('letter', 'Z')
->getQuery();
dump($q->getDQL());
dump($q->getResult());
Resulting DQL
SELECT u, (CASE WHEN SUBSTRING(u.name, 1, 1) <> :letter THEN 1 ELSE 0 END) AS HIDDEN firstLetterIsNotZ
FROM user u
ORDER BY firstLetterIsNotZ ASC, u.name ASC
Resulting Data: (firstLetterIsNotZ not HIDDEN)
array:3 [▼
0 => array:2 [▼
0 => User {#2163 ▶}
"firstLetterIsNotZ" => "0"
]
1 => array:2 [▼
0 => User {#2167 ▶}
"firstLetterIsNotZ" => "1"
]
2 => array:2 [▼
0 => User {#2168 ▶}
"firstLetterIsNotZ" => "1"
]
]
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.