DOCTRINE : IN statement ordered? - sql

I am using Symfony2 and doctrine 2, and I have a problem with this query :
$query = $em->createQuery('SELECT a FROM MyBundle:Artiste a WHERE a.id IN (4,12,1)');
$result = $query->getArrayResult();
And I always get results order by a.id, ie 1 then 4 then 12 while I would like to display the results ordered as the list of ids : 4 then 12 then 1.
UPDATE
Thanks to #Bram Gerritsent comment, I register a custom DQL function FIELD, so here is what I have done :
In MyBundle/DQL/Field.php, I have inserted the following code (https://github.com/beberlei/DoctrineExtensions/blob/master/lib/DoctrineExtensions/Query/Mysql/Field.php) (I've just changed the namespace to be namespace MyBundle\DQL;
Then, I add the following in my config.yml as shown in the Symfony2 documentation (http://symfony.com/doc/2.0/cookbook/doctrine/custom_dql_functions.html)
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
default:
auto_mapping: true
dql:
string_functions:
field: MyBundle\DQL\Field
So, I wrote the following query $query = $em->createQuery('SELECT a FROM MyBundle:Artiste a WHERE a.id IN (4,12,1) ORDER BY FIELD(4,12,1)'); but I'm getting this error : [Syntax Error] line 0, col 75: Error: Expected end of string, got '('

You need to have a look into MySql FIELD function.
In native MySql you would do something like this:
ORDER BY FIELD(a.id,4,12,1)
The field function isn't part of the Doctrine 2 distribution, but you can get it from the DoctrineExtensions.
See this StackOverflow post for more information about using the FIELD function in Doctrine 2
EDIT
I have tested it using your query but got the same syntax error. The following query works for me. Not sure why you cannot use ORDER BY field(a.id,4,12,1) directly, but you have to create a HIDDEN field in your select first.
SELECT a, field(a.id,4,12,1) as HIDDEN field FROM MyBundle:Artiste a WHERE a.id IN (4,12,1) ORDER BY field
EDIT2
I have done some more debugging and researching and the DQL parser doesn't seem to support string functions in the order by clause. I've fixed the issue and created a Pull Request.

Not so nice as FIELD function but should work:
SELECT output.a FROM (
SELECT a, ( CASE WHEN a.id = 4 THEN 1 WHEN a.id = 12 THEN 2 a.id = 1 THEN 3 END ) ord FROM MyBundle:Artiste a WHERE a.id IN (4,12,1)) output ORDER BY output.ord

Related

TypeORM: column must appear in the GROUP BY clause or be used in an aggregate function

I'm trying to work out why the following raw SQL works perfectly with PostGres, whereas the SQL generated via TypeORM does not.
Running this works:
SELECT symbol, MAX(created_at) AS created_at
FROM update_history
WHERE exchange = 'NYSE'
AND data_type = 'companyRecord'
GROUP BY symbol
ORDER BY created_at ASC
Example: https://dbfiddle.uk/yocl-rBq
Whereas, the TypeORM sql generated by the following:
const result = this.repository
.createQueryBuilder('h1')
.select(['MAX(h1.createdAt) AS created_at', 'h1.symbol'])
.where('h1.exchange = :exchange', { exchange })
.andWhere('h1.dataType = :dataType', { dataType })
.groupBy('h1.symbol')
.orderBy({ created_at: 'ASC' })
.take(limit)
.getMany();
/* Produces this:
SELECT "h1"."symbol" AS "h1_symbol",
MAX("h1"."created_at") AS created_at
FROM "update_history" "h1"
WHERE "h1"."exchange" = 'NYSE'
AND "h1"."data_type" = 'companyRecord'
GROUP BY "h1"."symbol"
ORDER BY created_at ASC LIMIT 5000
*/
Example (second select box): https://dbfiddle.uk/yocl-rBq
Returns the following error:
QueryFailedError: column "h1.id" must appear in the GROUP BY clause or be used in an aggregate function
If I add h1.id to the GROUP BY clause, the query no longer returns the correct result set, as it is effectively different.
As you can see from the DBFiddle links, both generated SQL queries work outside of TypeORM.
What am I missing here?
You're using getMany() which always adds id field in the select. The query that you've pasted is most probably has been logged before adding getMany(). Try setting logging: true in your ormconfig.js and you'll see the exact query being fired.
You should use getRawMany() and you'll be able to get the exact query and also the desired result.

Can't join FREETEXTTABLE with typeORM functions

I'm working on a graphQL backend with TypeORM
I found FREETEXT, CONTAiNS, FREETEXTTABLE and CONTAINSTABLE options for fulltext searching in my SQL database.
As FREETEXTTABLE has a "RANK column, it is more useful and I’m using this option.
I added required settings to the database and by below query it’s working correctly when applying the query directly into the database:
SELECT * FROM content
INNER JOIN freetexttable( content , *, 'test text') newtable ON newtable.[KEY] = "id"
ORDER BY newtable.RANK desc
OFFSET 0 ROWS FETCH NEXT 12 ROWS ONLY
But when I try to use it with TypeORM like below I have some errors.
import { getRepository } from "typeorm";
let repo = getRepository(Content)
return repo.createQueryBuilder("qb")
.innerJoin(FREETEXTTABLE( qb , *, 'light'), newtable,newtable.[KEY] = qb.id)
.skip(0)
.take(12)
.getManyAndCount();
And it returns this error:
"Error: Invalid object name 'FREETEXTTABLE( qb , *, 'light')'."
Could you please let me know if there is a problem with my code or maybe you know a better option for fulltext search in SQL database
I was searching for the same issue. I was unable to find a solution to use FREETEXTTABLE with typeorm, so I had to implement it using raw SQL. using below code
repo.query(" RAW SQL ")

Group_concat with Query builder laravel

Hello! , i have an issue with an sql Call on laravel 5.5 using query builder. when i do this
$result = DB::table(self::$TABLA_COMPONENTE)
->join(self::$TABLA_ARCHIVOS ,self::$TABLA_COMPONENTE.'.com_id','=',self::$TABLA_ARCHIVOS.'.com_id')
->select(self::$TABLA_COMPONENTE.'.*',DB::raw('group_concat('.self::$TABLA_ARCHIVOS.'.ar_url) as com_archivos'))
->where(self::$TABLA_COMPONENTE.'.com_id',$id)->first();
i get the following error
SQLSTATE[42000]: Syntax error or access violation: 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause (SQL: select componente.*, group_concat(archivos.ar_url) as com_archivos from componente inner join archivos on componente.com_id = archivos.com_id where componente.com_id = 2 limit 1)
this is the raw sql i get by using ->toSql()
This is the sql with ->toSql()
"select `componente`.*, group_concat(archivos.ar_url) as com_archivos from `componente` inner join `archivos` on `componente`.`com_id` = `archivos`.`com_id` where `componente`.`com_id` = ?
And it works fine on Phpmyadmin.
i also tried using Group by with no luck.
If you could help me with a solution I would be very grateful!
This is actually mysql problem not laravel problem. Try add
->groupBy(self::$TABLA_COMPONENTE . '.id')
to you query.
EDITED: something like this one :
$result = DB::table(self::$TABLA_COMPONENTE)
->join(self::$TABLA_ARCHIVOS ,self::$TABLA_COMPONENTE.'.com_id','=',self::$TABLA_ARCHIVOS.'.com_id')
->select(self::$TABLA_COMPONENTE.'.*',DB::raw('group_concat('.self::$TABLA_ARCHIVOS.'.ar_url) as com_archivos'))
->groupBy(self::$TABLA_COMPONENTE . '.id')
->where(self::$TABLA_COMPONENTE.'.com_id',$id)->first();
note : it is not testet

Translating SQL query to Doctrine2 DQL

I'm trying to translate this (My)SQL to DQL
SELECT content, created, AVG(rating)
FROM point
GROUP BY DAY(created)
ORDER BY created ASC
And I'm stuck at GROUP BY part, apparently DAY/WEEK/MONTH isn't recognized as valid "function".
[Semantical Error] line 0, col 80 near '(p.created) ORDER': Error: Cannot group by undefined identification variable.
$this->createQueryBuilder('p')
->select('p')
->groupBy('DAY(p.created)')
->orderBy('p.created', 'ASC')
Q: Is it possible to create this kind of query with query builder, or should I use native query?
It is not possible to use custom DAY/WEEK/MONTH user functions in GROUP BY queries in Doctrine 2.1.?, only SELECT queries are supported (not sure for 2.2.? branch), so I ended up using native query, and everything works fine.
Quick overview of the code:
// creating doctrines result set mapping obj.
$rsm = new Doctrine\ORM\Query\ResultSetMapping();
// mapping results to the message entity
$rsm->addEntityResult('Omglol\AppBundle\Entity\Message', 'm');
$rsm->addFieldResult('m', 'id', 'id');
$rsm->addFieldResult('m', 'content', 'content');
$rsm->addFieldResult('m', 'rating', 'rating');
$rsm->addFieldResult('m', 'created', 'created');
$sql = "SELECT id, content, AVG(rating) as rating, created
FROM message
WHERE domain_id = ?
GROUP BY WEEK(created)";
$query = $this->_em->createNativeQuery($sql, $rsm);
$query->setParameter(1, $domainId);
$query->getResult();
There is the same topic in :
Link to google group

Java EE not compiling a query with the IN operator

I've written a query that works good if used into MySql Workbench, but it won't compile if used in my Java EE project!
Here's the query :
#NamedQuery(name = "Book.findByCourse", query = "SELECT b FROM Book b WHERE b.teaching IN (SELECT T.id FROM Teaching T, Course C WHERE T.course = C.id AND C.id = :course)")
The query works fine, but I've got this error in my Java EE project :
Error compiling the query [...], line 0, column 0: invalid IN expression argument [SubqueryNode
Left: null
Right: null], expected argument of type [entity.Teaching].
What's wrong with it?
First of all you are trying to select ids only in your subquery and then compare it to full pojo object (not sure if that's possible at all)
In my opinion you should either got with native query (#NamedNativeQuery) to achieve what you want or use Criteria Builder like for example here