DbUtils QueryRunner with fields of the same name - java

I swear I've done this before and it's worked fine, but it seems that with the query I have (below) I can't map two columns of the same name (in this case 'email') even when using "as" in my query. I've also tried without the "as" - just having 'u.email assessorEmail' and that query works as well, but with the same problem, the field just doesn't appear in my results when I debug.
getQueryRunner().query("SELECT u.email AS assessorEmail, f.formid, f.firstName, f.surname, f.email, f.valid, f.invalidreason FROM users AS u RIGHT JOIN userforms AS uf ON u.id=uf.user LEFT JOIN forms AS f ON uf.form=f.formid WHERE u.role=? AND f.submitted=1 AND f.valid=0 ORDER BY u.email", new MapListHandler(), Role.ASSESSOR);
MySql result:
assessorEmail formid firstName surname email valid invalidreason
assessor#test.com 547 John Doe user#test.com 0
Eclipse->inspect variable:
[{valid=false, invalidreason=, email=user#test.com, surname=Doe, firstName=John, formid=547}]
If I remove f.email from the query, the u.email appears successfully as 'email' (still not assessorEmail).
Is this a DbUtils thing? A QueryRunner thing? Even a MySql Java connector thing? I'm sure I'm missing something really obvious here...

After a little more digging I found a bug listing for this issue http://bugs.mysql.com/bug.php?id=32504. Seems to be an issue with the connector.
Adding "useOldAliasMetadataBehavior=true" as a parameter to the JDBC URL did the trick.

Related

Java Criteria builder- how to build a complex join query?

I'm new to Criteria API (and JAVA in general, but lets not talk about this).
I'm trying to build a really complex query using it, which goes like this:
SELECT ac.firstName as firstName, ac.lastName as lastName, du.idNumber as idNumber, du.dateOfBirth as dateOfBirth, du.gender as gender, du.settlement as settlement, du.street as street, du.buildingNumber as buildingNumber, du.id as driverID, pa.phoneNumber as phoneNumber, ea.emailAddress as emailAddress
FROM newDB.accounts ac
inner join driver_users du on du.id = ac.id
inner join phone_authentications pa on pa.identity_id=ac.identity_id
inner join email_authentications ea on ea.identity_id=ac.identity_id
where du.idNumber=:searchParams.idNumber and emailAddress like searchParams.emailAddress
After a lot of digging I managed to understand the syntx of the Criteria API and how to work with it, but im not sure on few things:
how do I make it pull out of various tables? I saw the "Root" command where you define the root table to pull from, so I guess my case should be Root<DriverSearchResultDto> root = criteriaBuilder.from(DriverSearchResultDto.class);, but is it really the root? Just assumed so because it came after the "from" clause... and what about the inner-joins? how do I add them with the specified join condition?
The DriverSearchResultDto I based my criteria-builder upon is not an entity and not connected directly to a table, its a custom DTO I created to recieve the results from the query. Is it ok? I went through the rest of the code written before I got here, and all the criteria-builders used are actual entities conneted to DB tables, so I wanna make sure I'm using it right (the fields inside has the exact same names tho- e.g firstName, lastName, etc).
how do I make a "like" condition in criteria? couldn't find a lot of info on this as well.
a newbie question about queries- I didn't get to work much on sql DBs lately. I'm not really new to the syntax but just not sure about something: as you can see, all the paramters I wanna pull from the DB are written like ac.lastName as lastName- no change to the name of parameter itself. Is it just the previous programmer being weird, or is it necessary when pulling from few tables at the same time (or on other condition?) to specify paramters name to not include table? will it not know how to parse the response into the results object?
Tnx alot!

Why do I recover a deleted record with UCanAccess?

I have been using UCanAccess to use Access databases my problem is when i want to delete a recor this returns automatically.
For example if i have:
Table Names
Id Name
1 Jessy
2 Abraham
String deleteQuery = "DELETE From Names where Id =?";
PreparedStatement pstm = con.getConnection().prepareStatement(deleteQuery);
pstm.setInt(1, 1); // "id" is type numeric
pstm.executeUpdate();
pstm.close();
it will works And then if i open the database the recor will be there!
that's my problem. (i hide the connection code but i have it)
Try to use compact feature provided by Access. On the Tools menu, point to Database Utilities, and then click Compact and Repair Database. This might help.
Do you do the commit after? If not and autocommit=false, just do it.
I found the problem, I was using data type OLE to save images simple sentences doesn't works so the way to delete a row with OLE field is creating Database and Table objects from java. It works.

JPA Criteria API using ISNULL in a order by statement

I use MySQL 5.5 with Hibernate 3.6 and JPA 2.0. I have a User table with a firstName which could also be null or an empty string. I want to have those empty firstName results last in my search results. For that I wrote the following SQL query which works just fine:
SELECT * FROM User ORDER BY ISNULL(firstName), firstName = "", firstName ASC LIMIT 100
Now want to translate this to JPA using the criteria API and I am not quite so sure about the order by. Here is what I have:
criteriaQuery = criteriaQuery.orderBy(cb.asc(cb.isNull(users.get(User_.firstName))), cb.asc(cb.equal(users.get(User_.firstName), "")), cb.asc(users.get(User_.firstName)));
However, the code snippet above does not work, because the CriteriaBuilder.isNull() method is traslated to IS NULL and not to the ISNULL() function of MySQL. I get the following exception:
org.hibernate.hql.ast.QuerySyntaxException: unexpected AST node: is null
Any ideas on how to check for null in the Order by statement with JPA 2.0
That is not possible. In JPA you can ORDER BY fields only that you select (that are in the SELECT part of your query). The problem is that there is no IS_NULL function, that can be used in the SELECT part.
I got the exact same problem as you do, finally I solve it using this way, maybe you can try:
CriteriaQuery<> query;
query.orderBy(cb.desc(cb.selectCase().
when(cb.isNull("field name"),0).otherwise(1)),
cb.asc("field name");

jsp jstl sql strange behaviour with as in mysql

In mysql i m having a stored procedure which has a sql like:
select firstname as i_firstname , lastname as i_lastname from roleuser
where user_id = uid ;
I m using a jstl code to get the values: -
<sql:query var="comm_codes" dataSource="jdbc/myDatasource">
call sp_select_username(?);
<sql:param>${user_id}</sql:param>
</sql:query>
<c:forEach var="rows" items="${comm_codes.rows}">
${rows.i_firstname} ${rows.i_lastname}
</c:forEach>
But this code does not return anything but when the replace the above code ${rows.i_firstname} with ${rows.firstname} i get the correct values.
Anything wrong with jstl, is this replicable or my fault here...
Question also posted here and here
thanks
I know it is an old post, but I encountered this problem as well. It is discussed here: http://forums.mysql.com/read.php?39,432843,432862#msg-432862
Importantly, the poster in the mysql forum states
ResultSetMetaData.getColumnName() will return the actual name of the column, if it exists
This provides a work-around - prevent the column name from existing, so that the alias must be used. As an example, the original poster's stored procedure could be modified to be
select concat(first name,'') as i_firstname ,
concat(lastname,'') as i_lastname from roleuser
where user_id = uid ;
In this case, the original column is now unknown, and the alias is used. I've tested this on my system in a similar situation at it worked. Likewise, if you need to use an alias for an int, you can try SELECT (id+0) AS id_alias. I'm sure most column types have similar solutions. Hope this helps.

Referring to an earlier aliased field in a criteria query

In this query:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> q = cb.createTupleQuery();
// FROM GamePlayedEvent gpe
Root<GamePlayedEvent> gpe = q.from(GamePlayedEvent.class);
// SELECT gameId, COUNT(*) AS count, AVG(duration)
// AS avDur, AVG(rewardCurrency) AS avCur, AVG(rewardXP) avXp
q.select(cb.tuple(
gpe.<String>get("gameId"),
cb.count(gpe).alias("count"),
cb.avg(gpe.<Double>get("duration")).alias("avDur"),
cb.avg(gpe.<Integer>get("rewardCurrency")).alias("avCur"),
cb.avg(gpe.<Integer>get("rewardXp")).alias("avXp")
));
// WHERE loginTime BETWEEN ...
q.where(cb.between(gpe.<Date>get("time"), fromTime, toTime));
// GROUP BY gameId
q.groupBy(gpe.<String>get("gameId"));
// ORDER BY count DESC
q.orderBy(cb.desc(???));
How can I add the ORDER BY count DESC, referring to the "count" defined in the SELECT clause?
What if you just captured the count expression, and used it directly?
Expression event_count = cb.count(gpe);
q.select(cb.tuple(
gpe.<String>get("gameId"),
event_count,
...
));
q.orderBy(cb.desc(event_count));
I came across the same problem today but none of the suggested solutions worked for me because I needed to reuse the expression not only in the order by clause but also in the group by clause.
One obvious solution would be to create a view on the database level but this is a bit clumsy, creates an unnecessary subquery and even not possible if the db user isn't granted enough privileges. A better option which I ended up implementing is to write something like this
q.select(cb.tuple(
gpe.<String>get("gameId"),
cb.count(gpe),
...
)).groupBy(cb.literal(2)).orderBy(cb.literal(2));
The first downside of this approach is that the code is errorprone. The other drawback is that the generated sql query contains ordinal position notation, which works on some databases (like postgresql or mariadb) but doesn't work on others (like sql server). In my case, however, I found this to be the best option.
Tested on jpa 2.1 with hibernate 5.2.3 as a provider and postgresql 9.6.
Even though the Pro JPA 2 book describes that the alias method can be used to generate a sql query alias (on page 251) I have had no success with making it work with neither EclipseLink or Hibernate. For your question I would say that your orderBy line should read:
q.orderBy(cb.desc(cb.count(gpe));
if it was supported by the different vendors.
As far as my research goes it seams that the alias method is only used for naming elements in the tuble used in the select (so only for projection).
I have one question though. Why would you want to use the JPA Criteria API for this query. It (the query) seams to be static in nature so why not use JPQL where you can define your query aliases directly.
Have you tried setting up a projection with an alias?
criteria.setProjection(Projections.projectionList()
.add(Projections.count("item.id"), "countItems"));
criteria.addOrder(Order.desc("countItems"));
For a sum aggregation field I have the following code which worked for me:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<T> cq = cb.createQuery(entity);
Root<T> root = cq.from(entity);
cq.orderBy(cb.desc(cb.sum(root.get(orderByString))));
// orderByString is string entity field that is being aggregated and which we want to put in orderby clause as well.

Categories