Java EE not compiling a query with the IN operator - sql

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

Related

Metabase - Field Filter as text

I have this SQL query:
select concept, count(*)
from annotation
where exists (select 1
from annotation a2
where a2.comment_commentid = annotation.comment_commentid and a2.concept = 'Fatigue'
)
group by concept;
And I want to replace 'Fatigue' with {{word}}, to do a filter widget, maping to the column from database.
I have the following error:
ERROR: syntax error at or near "=" Position: 307
What I need to change to aplly the filter? selecting the available words from that column?
With variable type as Text it works... But don't display all the available options, in filter, as variable type Field Filter do...
Thanks!
The outer annotation table needs an alias too. When in doubt, the inner scope always prevails whern resolving names, and the inner exists(...) query an an annotation name in scope, too)
[And the cause of your error is probably that the middleware gets confused]
select concept, count(*)
from annotation a1 -- <<-- HERE!
where exists (select 1
from annotation a2
where a2.comment_commentid = a1.comment_commentid and a2.concept = 'Fatigue'
)
group by concept;

How can I produce a join on a substring and an integer in Entity Framework?

Using Entity Framework, I'm trying to join two tables like this.
...
join f in ent.FTypes on Int32.Parse(c.CourseID[0].ToString()) equals f.FTypeID
...
The first character of the string CourseID is a digit, and FTypeID is an int.
This doesn't seem to work though. The exception message I get is:
LINQ to Entities does not recognize the method 'Int32 Parse(System.String)' method, and this method cannot be translated into a store expression."} System.Exception {System.NotSupportedException}
What I want to replicate is the SQL string equivalent (which works fine):
join FType f on SUBSTRING(c.CourseID, 1, 1) = f.FTypeID
Does anyone have the solution to have to do this in LINQ to Entities?
This is a rather nasty join, but I did some testing in Entity Framework with similar data and arrived at something you can test on yours.
It uses string.Substring to grab the first character from your string operand, and then uses a combination of the EF-only method SqlFunctions.StringConvert (these methods are found in System.Data.Objects.SqlClient) with a cast to double1 and finally a string.Trim2 for your integer operand.
I have tested this and confirmed that all functions are supported at least in EF 4. Several other methods proposed or featured in the question do not work, because Entity Framework does not know how to tranlsate them to the appropriate SQL equivalent.
join f in ent.FTypes
on c.CourseID.Substring(0, 1)
equals SqlFunctions.StringConvert((double)f.FTypeID).Trim()
It produces a SQL join that looks like the following:
INNER JOIN [dbo].[FTypes] AS [Extent2]
ON ((SUBSTRING([Extent1].[CourseID], 0 + 1, 1)) = (LTRIM(RTRIM(STR( CAST( [Extent2].[FTypeID] AS float))))))
OR ((SUBSTRING([Extent1].[CourseID], 0 + 1, 1) IS NULL) AND (LTRIM(RTRIM(STR( CAST( [Extent2].[FTypeID] AS float)))) IS NULL))
So based on that, you might want to do some additional filtering as necessary.
Give it a shot and see if that helps solve the problem.
1 The cast to double is necessary because SqlFunctions.StringConvert does not have an overload for integer and there is no other single best match, so I force one.
2 The resultant string needs to be trimmed because the string conversion generates some excess padding.
I'm not sure this worked 8 years ago, but modern EF6 implementation allows you to add anonymous types, so you can add the conversion to your initial select statements, and then you can just compare that new properties directly in the join.
from c in ent.Courses
select new { typeId = c.CourseId.Substring(0, 1), c }
join f in ent.FTypes.Select(t => new { stringId =
t.FTypeId.ToString(), t }
on c.typeId equals f.stringId into ...
NOTE: The join-statement does not appear to support ToString() but the select-statements do.
You could also move the CouresId.Substring into the join statement, but that may run less efficiently there.
Results in SQL like this:
INNER JOIN [ent].[FTypes] AS [Extent2] ON
(LTRIM(RTRIM(SUBSTRING([Extent1].[nvarchar(max)], 3 + 1, 1)))) =
CAST([Extent2].[Id] AS nvarchar(max))

DOCTRINE : IN statement ordered?

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

LINQ To NHibernate ignores the 'Group by' clause

I use NHibernate 3.2.0 and I cannot make the LINQ provider generate a proper SQL query for this statement:
var result = (from translation in session.Query<TmTranslation>()
where translation.Id > 0
group translation by translation.Language into grp
select new { Lang = grp.Key.Code }).ToList();
The generated SQL is
select tmtranslat0_.id as id32_,
tmtranslat0_.status as status32_,
tmtranslat0_.text as text32_,
tmtranslat0_.last_revision as last4_32_,
tmtranslat0_.fk_id_translation_unit as fk5_32_,
tmtranslat0_.fk_id_translator as fk6_32_,
tmtranslat0_.fk_id_last_modifier as fk7_32_,
tmtranslat0_.fk_id_last_match_category as fk8_32_,
tmtranslat0_.fk_id_language as fk9_32_
from "TRANSLATION" tmtranslat0_
where tmtranslat0_.id > 0
which, of course leads to loading all the entities from the database and grouping the result set in memory (the result itself is correct).
I would like something like this
select tmtranslat0_.fk_id_language
from "TRANSLATION" tmtranslat0_
where tmtranslat0_.id > 0
group by tmtranslat0_.fk_id_language
to be generated instead.
Am I missing something?
Thank you very much.
The only thing I can suggest, is to use QueryOver API.

Nhibernate upgraded getting 'Antlr.Runtime.NoViableAltException' on outer join using *=

so we upgraded to newer Nhibernate and Fluent Nhibernate.
now I' getting this exception:
FailedNHibernate.Hql.Ast.ANTLR.QuerySyntaxException: Exception of type 'Antlr.Runtime.NoViableAltException' was thrown. near line 1, column 459
On this hql, which worked fine before the upgrade.
SELECT s.StudId, s.StudLname, s.StudFname, s.StudMi, s.Ssn, s.Sex, s.Dob, et.EnrtypeId, et.Active, et.EnrId, sss.StaffLname, sss.StaffFname, sss.StaffMi,vas.CurrentAge FROM CIS3G.Jcdc.EO.StudentEO s , CIS3G.Jcdc.EO.EnrollmentEO e , CIS3G.Jcdc.EO.EnrollmentTypeEO et , CIS3G.Jcdc.EO.VwStaffStudentStaffEO sss, CIS3G.Jcdc.EO.VwAgeStudentEO vas WHERE ( e.EnrId = et.EnrId ) AND ( s.StudId = vas.StudId ) AND ( s.StudId = e.StudId ) AND ( et.EnrtypeId *= sss.EnrtypeId ) AND ( Isnull ( sss.StudStaffRoleCd , 1044 ) = 1044 ) AND ( s.StudId = 4000 )
Clearly it does nto like the *= syntax, I tried rewritign is as ansi sql outer join and no joy.
Can anyone tell me what ineed to change the sql to so I can get the outer join to work correctly?
Thanks,
Eric-
We got it working with the ansi sql and calling nhibernate slightly differently.
Is there any way to force antlr to allow t-sql, or to stop antlr parsing all together?
All this sql worked fine before we got the version that added antlr parsing.
In MANY places we are passing T-Sql to NHibernate, becasue we're porting from another app with all the complex SQl already written, and We'd like to avoid having to rewrite & retest all the sql as ansi standard.
Shouldn't the antrl parsing only be applied to HQL only not direct SQL anyway? You reduce the
native compatibility for other DBs, like ours.
Thanks,
Eric=
You don't need to do explicit joins with NHibernate in order to get the related entities. Instead, map those relations as many-to-one.
For example, your Student class could have a References(x => x.EnrollmentType). With that, you'd only need to select the student (you don't even need HQL if you know the Id; you can use session.Get) and you could just navigate to the other properties.
I recommend you read the NHibernate documentation