Group by in JPA - jpa

My Question is why the GROUP BY didn't show in the glassfish logs.
i added the following data below because someone wants to see it
public List<Message> listAllMessageBySender(String currentUserID) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceUnit");
EntityManager entityManager = emf.createEntityManager();
TypedQuery<Message> eq = entityManager.createQuery("SELECT m FROM Message m WHERE m.sendBy.userId = :userid GROUP BY m.sendTo.userId", Message.class);
eq.setParameter("userid", Integer.parseInt(currentUserID));
List<Message> message = eq.getResultList();
return message;
}
Glassfish 3.1.2.Logs
FINE: SELECT id, message, send_date, send_by, send_to FROM message WHERE (send_by = ?)
bind => [50]
Data:
User A : sendBy.userId = 50
User B : sendTo.userId = 44
User C : sendTo.userId = 43
id send_date send_by send_to message
1 2013-03-14 14:58:46 44 50 50 send message to 44
2 2013-03-14 14:58:46 50 44 reply from 44 to 50
3 2013-03-14 17:38:52 44 50 2nd reply to 50
6 2013-03-14 18:22:10 50 44 44 reply to 50
7 2013-03-14 18:22:10 50 43 new
in the query above is i want to list all the user sent from User A. it causes duplication because there is two send_to 44. the xhtml below shows :
<ui:repeat value="#{messageController.items}" var="messageItem">
<br />
<div onclick="loadMessage()">
<h:panelGroup layout="block" >
<p:graphicImage height="50" width="50" value="#{messageItem.sendTo.profilePicture}"/>
</h:panelGroup>
<h:panelGroup layout="block" style="width: 270px;">
<h:outputText value="#{messageItem.sendTo.registerName}"/>
<h:panelGroup layout="block" style="float:right;">
<h:outputText value="#{messageItem.sendDate}" >
<f:convertDateTime pattern="HH:mm"/>
</h:outputText>
</h:panelGroup>
</h:panelGroup>
</div>
<p:remoteCommand name="loadMessageBean" action="#{messageController.loadMessage(messageItem.id)}" /> </ui:repeat>
ERD
User Table Message Table
user_id message_id
register_name send_date
send_to ----> referenced by user_id User Table
send_by ----> referenced by user_id User Table

This request doesn't make sense. group by is used when the select clause contains at least one aggregation function (sum, avg, min, max, etc.). And all the other columns must appear in the group by clause.
So for example, the following query would make sense:
SELECT max(m.length), sender.userId from Message m
inner join m.sendBy sender
GROUP BY sender.userId
It would return, for each message sender, the length of its longest message.
Tell us, with example data, what you would like your query to return.
If you want to get all the distinct users whom user A sent a message to, the query should simply be
select distinct m.sendTo from Message m
where m.sendBy.userId = :userid

Related

How to run knex queries and insert in band

I have a sql table like this:
// Create table for albums - photos relation with ordering
await knex.schema.createTable('albums_photos', (table) => {
table.integer('album')
.notNullable()
.references('pk')
.inTable('albums')
.onUpdate('CASCADE')
.onDelete('CASCADE')
table.integer('photo')
.notNullable()
.references('pk')
.inTable('photos')
.onUpdate('CASCADE')
.onDelete('CASCADE')
// Photo's order in its album
table.integer('order').notNullable()
})
I did not add db constraint yet but album and order must be unique together.
When I add a new entrie, I want order to be equal to the max value of order for given album, + 1:
async createAlbumPhoto = (albumPk, photoPk) => {
console.log(`Work on photo ${photoPk}`)
// We get current max value for order and album
const maxData = await knex('albums_photos')
.where({ album: albumPk })
.max('order')
.first()
console.log(`Get max ${maxData.max} for photo ${photoPk}`)
// We create new entrie with max + 1
const newAlbumPhoto = await knex('albums_photos')
.insert({
album: albumPk,
photo: photoPk,
order: maxData.max + 1
})
.returning('*')
console.log(`pk ${photoPk} done with order ${newAlbumPhoto[0].order}`)
return newAlbumPhoto[0]
}
When I insert only one photo_album in a while, everything works fine.
But when (web) client send multiple requests one after another, due to asynchronous db requests, I get bad results. Such list of photo pks ['71', '72', '73', '74'] results in:
work on pk 71 (OK)
Get max null for photo 71 (OK)
pk 71 done with order 1 (OK)
work on pk 72
work on pk 73
Get max 1 for photo 72 (OK)
Get max 1 for photo 73 (Wrong)
work on pk 74
Get max 1 for photo 74 (Wrong)
pk 72 done with order 2 (OK)
pk 73 done with order 2 (Wrong)
pk 74 done with order 2 (Wrong)
Orders aren't unique…

Unable to set the ID of an instance

What is unique about my situation is that the ID's can not be randomly assigned so I set it's value within the instance. I created several instances of an entity using the modeler. Below is the XML created:
<cf:entity name="Test4" namespace="Amikids.TimeTracking" categoryPath="/Amikids.TimeTracking">
<cf:property name="Id" key="true" typeName="int" />
<cf:property name="Name" />
<cf:instance>
<cf:instanceValue name="Id">10</cf:instanceValue>
<cf:instanceValue name="Name">Test 1</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">20</cf:instanceValue>
<cf:instanceValue name="Name">Test 2</cf:instanceValue>
</cf:instance>
<cf:instance>
<cf:instanceValue name="Id">30</cf:instanceValue>
<cf:instanceValue name="Name">Test 3</cf:instanceValue>
</cf:instance>
</cf:entity>
There are 2 things that are not working as expected:
The records inserted do not use the ID specificed in the model/xml. Instead they were created incrementally starting at 1:
(The below is displayed in a code snippet only to prevent StackOverflow from reformatting my list so all records appear on one line)
ID Name
1 Test 1
2 Test 2
3 Test 3
When I build the model a second time duplicate records are inserted.
(The below is displayed in a code snippet only to prevent StackOverflow from reformatting my list so all records appear on one line)
ID Name
1 Test 1
2 Test 2
3 Test 3
4 Test 1
5 Test 2
6 Test 3
Although specifying the ID in the instance does not appear to be work, as a simple work around I created the records using code, which allowed me to specify the ID. This has been verified with the following code snippet.
Amikids.TimeTracking.Test4 test4 = new Amikids.TimeTracking.Test4();
test4.Id = 100;
test4.Name = "Test 100";
test4.Save();
test4 = new Amikids.TimeTracking.Test4();
test4.Id = 200;
test4.Name = "Test 200";
test4.Save();

Exception with rownum in mybatis

Following is my sql query that is used in mybatis mapper xml.
<select id="getData" fetchSize="30" resultType="java.util.HashMap" >
select * from table
where module='AB'
and rownum < 15
</select>
I am getting below exception while using rownum :
Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 130; columnNumber: 16; The content of elements must consist of well-formed character data or markup.
Below things I have tried:
ROWNUM<=15 AND <![CDATA[ ROWNUM <= 15 ]]>
But still it is not working.
Try this:
<select id="getData" fetchSize="30" resultType="java.util.HashMap" >
select * from table
where module='AB'
<![CDATA[ AND ROWNUM <= 15 ]]>
</select>
or ROWNUM <= 15 (with whitespaces after ROWNUM and before 15).
Are you sure you have tried the < or the <![CDATA[ ]]> on all the right places? (seems it's a large(r) file with perhaps multiple errors).
Since the code example you give is without the = and in the things you tried you add an =. And your error is on line 130 column 16 of your file, and we only see 5 lines and the < does not seem to be in column 16.
You could try to use: http://www.validome.org/xml/ and see if the entire configuration file is valid?
You can also read more about this on another question on Stack Overflow: https://stackoverflow.com/a/29136039/244748

Mybatis resultmap ​only outputs one of three records

I have 3 records to be populated from a medication table​:​
select * from ccda_medication where client_id = 100009;
client_id | rxcui | drug | medicationtime | status | directions |pharmacynote
-----------+--------+---------------------------------------+----------------+--------+------------------------------------+
100009 | 573621 | Albuterol 0.09 MG/ACTUAT [Proventil] | 20120806 | ACTIVE | 2 puffs every 6 hours PRN wheezing |
100009 | 866924 | Metoprolol Tartrate 25 MG Oral Tablet | 20120806 | ACTIVE | by mouth once daily|
100009 | 197517 | Clarithromycin 500 MG Oral Tablet | 20120806 | ACTIVE | by mouth twice daily for 7 days|
(3 rows)
The debug also shows that 3 records were retrieved from database.
==> Preparing: select * from ccda_medication where client_id = ?
==> Parameters: 100009(Integer)
<==Columns: client_id, rxcui, drug, medicationtime, status, directions, pharmacynote
<==Row: 100009, 573621, Albuterol 0.09 MG/ACTUAT [Proventil], 20120806, ACTIVE, 2 puffs every 6 hours PRN wheezing,
<==Row: 100009, 866924, Metoprolol Tartrate 25 MG Oral Tablet, 20120806, ACTIVE, by mouth once daily,
<==Row: 100009, 197517, Clarithromycin 500 MG Oral Tablet, 20120806, ACTIVE, by mouth twice daily for 7 days,
<== Total: 3
but I only g​e​t one record ​when I call selectMedications- the last one: Row: 100009, 197517
​Interestingly, if I ​flatten out Substance to contain all fields directly (no inner class), I get all 3 records, so the column names are correct.
The Mapper file is as the following:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ccda.mapper.interfaces.MedicationMapper">
<select id="**selectMedications**"
resultMap="MedicationsResultMap"
parameterType="Integer">
select * from ccda_medication where client_id = #{id}
</select>
<resultMap id="MedicationsResultMap" type="ccda.model.Substance">
<result property="status" column="status"/>
<association property="substanceTime" javaType="ccda.model.EffectiveTime">
<result property="low" column="medicationtime"/>
<result property="high" column="medicationtime"/>
</association>
<association property="medication" javaType="ccda.model.Medication">
<result property="rxcui" column="rxcui"/>
<result property="drug" column="drug"/>
<result property="directions" column="directions"/>
<result property="fillInstructions" column="pharmacynote"/>
</association>
</mapper>
The Substance, Medication and MedicationMapper are as the following:
package ccda.model;
public class Substance
{
public String status;
public EffectiveTime substanceTime;
public Medication medication;
}
package ccda.model;
public class Medication
{
public int rxcui;
public String drug;
public String directions;
public String fillInstructions;
}
package ccda.mapper.interfaces;
import java.util.List;
import ccda.model.Medication;
import ccda.model.Substance;
public interface MedicationMapper
{
List<Substance> selectMedications( int id );
}
​Can you please help me figure out why is that? Thanks A LOT!
The problem is that identifier field for substance is not specified. Because of this mybatis doesn't know what is the identity of returned entities and in this case it thinks that all records refer to the same entity.
So specify id in the resultMap and use unique field from ccda_medication for it.

mybatis return result map with duplicate entry

I am using mybatis to retrieve data from DB, the data returned is containing duplicate entries.
Required result : Column Name , Value
Expected result is : column1 value A
But returned result is : COLUMN1 value A , column1 value A.
Hope able to clarify my doubt.
Can anybody tell me why it is happening?
<select id="getContentMap" resultType="map" parameterType="map">
select planId,location_qualifier from disclaimer_disclosure_content where
<choose>
<when test="plan_id != null">
plan_id = #{plan_id}
</when>
<when test="product_id != null">
product_id = #{product_id}
</when>
<otherwise>
issuer_id = #{issuer_id}
</otherwise>
</choose>
and effective_date >= #{effective_date}
and location_qualifier LIKE CONCAT('%' , #{location_qualifier} , '%')
</select>
The issue you are seeing is a bug in MyBatis 3 up until release 3.0.6: http://code.google.com/p/mybatis/issues/detail?id=303.
After that release you get the answer I outlined in my other answer (which was done with MyBatis 3.1.1).
You have four options:
Just ignore it and only grab the uppercase or lowercase entries
Upgrade to at least 3.0.6
Stop using map as resultType and move to a POJO domain object
Use the workaround below:
workaround for MyBatis < 3.0.6
Use full uppercase column aliases and they will only show up once (as uppercase) in your map:
<select id="getContentMap" resultType="map" parameterType="map">
select plan_id as PLAN_ID, location_qualifier as LOCATION_QUALIFIER from disclaimer_disclosure_content
where
<!-- SNIP: is the same as you had -->
</select>
This results in the output:
{PLAN_ID=2, LOCATION_QUALIFIER=Bar}
(or something similar depending on exactly how your select looks).
You will probably need to report more information, such as:
what database are you using?
what version of MyBatis 3 are you using (or are you still using iBATIS)?
what does your table structure look like?
In any case, I tried out a slightly simplified version of your query using MySQL 5.1 and MyBatis-3.1.1 and it worked fine - meaning that I only got back one entry of the column name in the result map. I provide my setup below so you can try to reproduce it or diagnose where your code may be wrong.
First, you have a error in your select statement. You have
SELECT planId
but then you have:
WHERE ... plan_id = #{plan_id}
so you probably meant SELECT plan_id in the SELECT clause.
Here is what worked for me.
My slightly simplified MyBatis select mapping is:
<select id="getContentMap" resultType="map" parameterType="map">
SELECT plan_id, location_qualifier FROM disclaimer_disclosure_content
WHERE
<choose>
<when test="plan_id != null">
plan_id = #{plan_id}
</when>
<otherwise>
product_id = #{product_id}
</otherwise>
</choose>
AND location_qualifier LIKE CONCAT('%' , #{location_qualifier} , '%')
</select>
Second, my MySQL table for this query:
mysql> select * from disclaimer_disclosure_content;
+---------+--------------------+------------+
| plan_id | location_qualifier | product_id |
+---------+--------------------+------------+
| 1 | Foo | 101 |
| 2 | Bar | 102 |
| 3 | Baz | 103 |
| 4 | Quux | 104 |
+---------+--------------------+------------+
4 rows in set (0.01 sec)
Third, my Java code to use the mapping:
#Test
public void testForSO() throws Exception {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("plan_id", 2);
paramMap.put("location_qualifier", "Ba");
List<Map<String,Object>> lmap = session.selectList("getContentMap", paramMap);
assertNotNull(lmap);
Map<String,Object> m = lmap.get(0);
assertNotNull(m);
System.out.println(m.toString());
}
This passes and prints out:
{location_qualifier=Bar, plan_id=2}
I also tried it with
Map<String,Object> m = session.selectOne("getContentMap", paramMap);
and get the same expected result.