MyBatis data querying issues - sql

Here's a sample code:
#Results(
id = "displayData", value = {
#Result(property = "Caller", column = "c.CALLER"),
#Result(property = "Event", column = "t.RECORD_TEXT"),
#Result(property = "Receiver", column = "c.RECEIVER"),
#Result(property = "Timestamp", column = "e.RECORD_DATE")
}
)
#Select("SELECT c.CALLER, c.RECEIVER, e.RECORD_DATE, t.RECORD_TEXT FROM T_CALL c " +
"INNER JOIN T_EVENT e ON e.CALL_ID=c.RECORD_ID INNER JOIN T_EVENT_TYPE t " +
"ON e.RECORD_EVENT_ID=t.RECORD_ID WHERE c.CALLER LIKE '%${searchTerm}%' OR " +
"t.RECORD_TEXT LIKE '%${searchTerm}%' OR c.RECEIVER LIKE '%${searchTerm}%' " +
"ORDER BY ${ordering} LIMIT ${limit} OFFSET ${offset}")
List<DisplayData> findAndSortDataToDisplay(#Param("searchTerm") String searchTerm, #Param("ordering") String ordering,
#Param("limit") int limit, #Param("offset") int offset);
The problem with is that "Event" and "Timestamp" are set to NULL at runtime (other two are set properly)!
Can anyone help with some advice on how to fix this?
(The whole code is available here: https://github.com/arthurmarkus2013/SampleWebsite)
EDIT:
I'm not 100% sure, but it seems like this code does work:
#Select("SELECT c.CALLER, e.EVENTS_GROUP_ID FROM T_CALL c INNER JOIN T_EVENT e " +
"ON e.CALL_ID=c.RECORD_ID WHERE c.CALLER = ${callerId}")
int fetchEventsGroupId(#Param("callerId") int callerId);
The difference is, that this definition contains only one JOIN clause, whereas the first one contains two of them. In other words, I'm pretty much sure, that the issue is caused by those JOINs!
But the problem is, that I am provided with an absolute requirement, that both definitions work as intended!

To help you, I need more details about DisplayData type.
If Event and Timestamp has a one-to-many/one-to-one relation with T_CALL you need read about association and collection.
refer to Mybatis Docs
using annotations, refer to #Many #one Mybatis annotations
I hope this can help you, good luck !

Related

How to write an Open SQL statement with substring in the JOIN ON condition? [duplicate]

I have the following select statement in ABAP:
SELECT munic~mandt VREFER BIS AB ZZELECDATE ZZCERTDATE CONSYEAR ZDIMO ZZONE_M ZZONE_T USAGE_M USAGE_T M2MC M2MT M2RET EXEMPTMCMT EXEMPRET CHARGEMCMT
INTO corresponding fields of table GT_INSTMUNIC_F
FROM ZCI00_INSTMUNIC AS MUNIC
INNER JOIN EVER AS EV on
MUNIC~POD = EV~VREFER(9).
"where EV~BSTATUS = '14' or EV~BSTATUS = '32'.
My problem with the above statement is that does not recognize the substring/offset operation on the 'ON' clause. If i remove the '(9) then
it recognizes the field, otherwise it gives error:
Field ev~refer is unknown. It is neither in one of the specified tables
nor defined by a "DATA" statement. I have also tried doing something similar in the 'Where' clause, receiving a similar error:
LOOP AT gt_instmunic.
clear wa_gt_instmunic_f.
wa_gt_instmunic_f-mandt = gt_instmunic-mandt.
wa_gt_instmunic_f-bis = gt_instmunic-bis.
wa_gt_instmunic_f-ab = gt_instmunic-ab.
wa_gt_instmunic_f-zzelecdate = gt_instmunic-zzelecdate.
wa_gt_instmunic_f-ZZCERTDATE = gt_instmunic-ZZCERTDATE.
wa_gt_instmunic_f-CONSYEAR = gt_instmunic-CONSYEAR.
wa_gt_instmunic_f-ZDIMO = gt_instmunic-ZDIMO.
wa_gt_instmunic_f-ZZONE_M = gt_instmunic-ZZONE_M.
wa_gt_instmunic_f-ZZONE_T = gt_instmunic-ZZONE_T.
wa_gt_instmunic_f-USAGE_M = gt_instmunic-USAGE_M.
wa_gt_instmunic_f-USAGE_T = gt_instmunic-USAGE_T.
temp_pod = gt_instmunic-pod.
SELECT vrefer
FROM ever
INTO wa_gt_instmunic_f-vrefer
WHERE ( vrefer(9) LIKE temp_pod ). " PROBLEM WITH SUBSTRING
"AND ( BSTATUS = '14' OR BSTATUS = '32' ).
ENDSELECT.
WRITE: / sy-dbcnt.
WRITE: / 'wa is: ', wa_gt_instmunic_f.
WRITE: / 'wa-ever is: ', wa_gt_instmunic_f-vrefer.
APPEND wa_gt_instmunic_f TO gt_instmunic_f.
WRITE: / wa_gt_instmunic_f-vrefer.
ENDLOOP.
itab_size = lines( gt_instmunic_f ).
WRITE: / 'Internal table populated with', itab_size, ' lines'.
The basic task i want to implement is to modify a specific field on one table,
pulling values from another. They have a common field ( pod = vrefer(9) ). Thanks in advance for your time.
If you are on a late enough NetWeaver version, it works on 7.51, you can use the OpenSQL function LEFT or SUBSTRING. Your query would look something like:
SELECT munic~mandt VREFER BIS AB ZZELECDATE ZZCERTDATE CONSYEAR ZDIMO ZZONE_M ZZONE_T USAGE_M USAGE_T M2MC M2MT M2RET EXEMPTMCMT EXEMPRET CHARGEMCMT
FROM ZCI00_INSTMUNIC AS MUNIC
INNER JOIN ever AS ev
ON MUNIC~POD EQ LEFT( EV~VREFER, 9 )
INTO corresponding fields of table GT_INSTMUNIC_F.
Note that the INTO clause needs to move to the end of the command as well.
field(9) is a subset operation that is processed by the ABAP environment and can not be translated into a database-level SQL statement (at least not at the moment, but I'd be surprised if it ever will be). Your best bet is either to select the datasets separately and merge them manually (if both are approximately equally large) or pre-select one and use a FAE/IN clause.
They have a common field ( pod = vrefer(9) )
This is a wrong assumption, because they both are not fields, but a field an other thing.
If you really need to do that task through SQL, I'll suggest you to check native SQL sentences like SUBSTRING and check if you can manage to use them within an EXEC_SQL or (better) the CL_SQL* classes.

Hibernate, SQL in HQL (NativeQuery)

I am starting out at Hibernate. I am at the point, where I try out SQL in HQL.
I saw a code example which I wanted to recreate, but my output ended up being different.
To use SQL in HQL, that person said, if you want to only use a couple of columns, you need to use a Map to get certain columns (So I canĀ“t simply use addEntity here).
My Student table got sId, sName, sMarks. Now I want to retrieve only the Students names (sName) and their marks (sMarks).
The Problem is, that I only get "null" as values for the names and marks whilst the object shows me the proper values:
Console Output:
Hibernate: SELECT sName,sMarks FROM student
{SNAME=Nameless fool number 1, SMARKS=65}
null : null
The Code:
NativeQuery querySQL2 = session.createNativeQuery("SELECT sName,sMarks "
+ "FROM student");
querySQL2.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List students = querySQL2.getResultList();
for (Object o : students)
{
System.out.println(o);
Map m = (Map)o;
System.out.println(m.get("sName") + " : " + m.get("sMarks"));
}
Why do I get the proper Object with Syso(o) and just null with Syso(m.get("..."))?
Thank you in advance!
Actually you already answered your question
{SNAME=Nameless fool number 1, SMARKS=65}. Hibernate convert column names to upper case.

JOOQ - Select Distinct with Join - Fetch mapper

This is the SQL I am trying to create with JOOQ -
select distinct(kmp.*) from office_all_company_kmp kmp
inner join company_kmp companykmp on kmp.id=companykmp.kmp_id
where companykmp.company_id=?1
I am writing code in Kotlin. I had 2 issues doing this -
In the select clause, unless I add a .asList() to the fields array, I couldn't get it compiling.
The fetch mapper had to be handcoded. Is there a way I can use do this without writing all that code? I can map records fetched back from one table without writing any mapping.
Here's what I am talking about:
fun OfficeAllCompanyKmpDao.findByCompany(companyId: UUID): List<OfficeAllCompanyKmp> =
this.ctx()
.selectDistinct(OFFICE_ALL_COMPANY_KMP.fields().asList()) // without the asList() it wouldn't compile
.from(OFFICE_ALL_COMPANY_KMP)
.join(COMPANY_KMP).on(OFFICE_ALL_COMPANY_KMP.ID.eq(COMPANY_KMP.KMP_ID))
.where(COMPANY_KMP.COMPANY_ID.eq(companyId))
.fetch { // how do I write the mapper without manually writing code like the below?
OfficeAllCompanyKmp(
id = it[OFFICE_ALL_COMPANY_KMP.ID],
officeId = it[OFFICE_ALL_COMPANY_KMP.OFFICE_ID],
din = it[OFFICE_ALL_COMPANY_KMP.DIN],
pan = it[OFFICE_ALL_COMPANY_KMP.PAN],
name = it[OFFICE_ALL_COMPANY_KMP.NAME],
dateOfBirth = it[OFFICE_ALL_COMPANY_KMP.DATE_OF_BIRTH],
address = it[OFFICE_ALL_COMPANY_KMP.ADDRESS],
email = it[OFFICE_ALL_COMPANY_KMP.EMAIL],
kmpDetails = it[OFFICE_ALL_COMPANY_KMP.KMP_DETAILS],
createdTimestamp = it[OFFICE_ALL_COMPANY_KMP.CREATED_TIMESTAMP],
updatedTimestamp = it[OFFICE_ALL_COMPANY_KMP.UPDATED_TIMESTAMP],
versionNo = it[OFFICE_ALL_COMPANY_KMP.VERSION_NO],
createdUserId = it[OFFICE_ALL_COMPANY_KMP.CREATED_USER_ID],
updatedUserId = it[OFFICE_ALL_COMPANY_KMP.UPDATED_USER_ID]
)
}
A better approach than inner joining and then removing duplicates again would be to semi join your other table using IN or EXISTS:
this.ctx()
.selectFrom(OFFICE_ALL_COMPANY_KMP)
.where(OFFICE_ALL_COMPANY_KMP.ID.`in`(
select(COMPANY_KMP.KMP_ID)
.from(COMPANY_KMP)
.where(COMPANY_KMP.COMPANY_ID.eq(companyId)))
.fetchInto(OfficeAllCompanyKmp::class.java)
Or, alternatively, use jOOQ's synthetic LEFT SEMI JOIN syntax (see also this blog post for an explanation for this syntax, or this one for joins in general, or Wikipedia's nice explanation about semi joins)
this.ctx()
.select()
.from(OFFICE_ALL_COMPANY_KMP)
.leftSemiJoin(COMPANY_KMP)
.on(OFFICE_ALL_COMPANY_KMP.ID.eq(COMPANY_KMP.KMP_ID))
.and(COMPANY_KMP.COMPANY_ID.eq(companyId))
.fetchInto(OfficeAllCompanyKmp::class.java)
Your problem 1) went away by using different jOOQ API, where you don't have to list all columns explicitly in SELECT. Your problem 2) is fixed easily by calling fetchInto() instead.

Changing sql to hql with joins

What seems to be wrong with my hql query?
String queryString = "SELECT A.INITIAL, A.NUMBER, A.OWNR_SCAC , A.INITIAL||A.NUMBER AS CAR," +
"A.LESSEE_SCAC, A.TRUK_CNT, A.EQP_TYP_CD, A.AXL_CNT, B.STABILITY_DEV_EQP," +
"A.C_CNT, A.G_WGT, B.TRUK_AXL_CNT, A.EIN FROM DS.E_UT AS A" +
"LEFT JOIN DS.E_PRIMARY AS B" +
"WHERE A.INITIAL||A.NUMBER IN (:carList) AND A.INITIAL IN {:initList) AND A.NUMBER IN (:numberList)" +
"AND B.TRUK_AXL_CNT > 0";
ERROR:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: A near line 1, column 263
I assume it is talking about the A after FROM DS.E_UT AS A
In HQL you do not give the table and column names. Instead you give the Java class names and member variable names (or getter/setter) names of the classes and member variables which you mapped to the tables and columns.
I think you should add some spaces on each new line.
"A.C_CNT, A.G_WGT, B.TRUK_AXL_CNT, A.EIN FROM DS.E_UT AS A" +
"LEFT JOIN DS.E_PRIMARY AS B"
Would become:
A.C_CNT, A.G_WGT, B.TRUK_AXL_CNT, A.EIN FROM DS.E_UT AS ALEFT JOIN DS.E_PRIMARY AS B
Note the 'ALEFT'
I am not entirely sure of your schema or if this is what you are looking for, but you could just map your joined tables together. This could make things a little easier and you wouldnt need to explicitly join in your query.
Here is a small example
A sample query from that example could look something like:
SELECT p
FROM Person
WHERE p.name like :name
AND p.address.street like :street

Basic - SQL Query to LINQ Query

I have been trying out some LINQ query can someone please show how to convert the following SQL query to LINQ:
SELECT *, firstname+' '+lastname AS FullName FROM Client WHERE age > 25;
Don't worry about the where part (put it in for completeness) more wandering how to achieve that first part.
Now I have come across something like this:
from c in dc.Clients select new {FullName = c.firstname + " "+c.lastname}
But i don't know how to get it to select everything else without specifying it ie:
{firstname = c.firstname, id = c.id ..... etc}
But I was hoping for another way of achieving that.
So I'm just wandering if someone could show me the right or another way of accomplishing this :)
Thanks All :)
You have to select the actual item then refer to its properties. There's no way to expand the individual columns into the anonymous type.
var query = from c in dc.Clients
where c.Age > 25
select new
{
Client = c,
FullName = c.firstname + " " + c.lastname
};
foreach (var item in query)
{
// item.Client.Id
// item.FullName
// item.Client.FirstName
}
Selecting the actual item gives you access to the same properties you were using to construct the anonymous type. It's not a complete waste though if the query had more going on, such as a join with another table and including fields from that result in the anonymous type, along with the entire Client object.
You can can't autogenerate every column with Linq2Sql or EF (you can however find a way to mimic this behavior with micro-orms like Dapper and massive).
More conveniently, you can just select a new anonymous type with 3 fields, firstname, lastname and a client like:
from c in dc.Clients
select new
{
FullName = c.firstname + " "+c.lastname,
Client = c
}
I would however recommend to select just those properties that you really need. This forces you to think about how to compose your query and what the query is intended to do (and hence, select). Alternatively, you can just select the client, and use some extension methods to select full names. like:
public static string GetFullName(this Client client){ return client.firstname + " " + client.lastname; }