Linq to Entities nested subqueries - entity-framework

I am fairly new to linq and am having a problem translating the following sql to linq:
select
c3.COURSE, c3.DESCR
from
(select c.courseprefix, MAX(c.coursesuffix) [coursesuffix]
from
(select distinct SUBSTRING(course,1,3)[courseprefix], RIGHT(course, LEN(course) - 3) [coursesuffix]
from PsCourses where LEN(course) >= 3 ) c
group by c.courseprefix
) c2 inner join PsCourses c3 on (c2.courseprefix + c2.coursesuffix) = c3.COURSE
where
c3.COURSE_STATUS = 'A'
order by
c3.course

Well, you can use http://www.sqltolinq.com/downloads
or you can make a IQueryable, but in my personal criteria the complex queries I prefer to write in native sql

Related

How to apply distinct to perticular column and fetch all values from table in JPA(Criteria Builder)

I have written JPA query in that I want to apply distinct to only one column but here it is applying to all columns in table.
CriteriaBuilder cb = entityManager_gbl.getCriteriaBuilder();
CriteriaQuery<sourceTracking> cq = cb.createQuery(sourceTracking.class);
Root<sourceTracking> data1 = cq.from(sourceTracking.class);
Join<sourceTracking,status> joinobj=data1.join("sts");
Subquery<Number> subq=cq.subquery(Number.class);
Root<sourceTracking> sbf=subq.from(sourceTracking.class);
subq.select(cb.min(sbf.<Number>get("hopcount"))).groupBy(sbf.<String>get("message_id"));
cq.multiselect(cq.from(sourceTracking.class).get("message_id"));
cq.distinct(true);
cq.select(data1).orderBy(cb.asc(data1.get("message_id")));;
TypedQuery<sourceTracking> tquery = entityManager_gbl.createQuery(cq);
Here is my Hibernate query
select distinct sourcetrac0_.tablekey as tablekey1_2_, sourcetrac0_.alt_recipient_addr as alt_reci2_2_,
sourcetrac0_.alt_recipient_tried as alt_reci3_2_,sourcetrac0_.arrival_time as arrival_4_2_, sourcetrac0_.delivery_status as delivery5_2_, sourcetrac0_.dispatch_time as dispatch6_2_,
sourcetrac0_.hopcount as hopcount7_2_, sourcetrac0_.id as id8_2_, sourcetrac0_.id1 as id9_2_, sourcetrac0_.mail_orig_time as mail_or10_2_,
sourcetrac0_.mail_server as mail_se11_2_, sourcetrac0_.mailtype as mailtyp12_2_, sourcetrac0_.message_id as message13_2_, sourcetrac0_.nexthop as nexthop14_2_,
sourcetrac0_.precedence as precede15_2_, sourcetrac0_.receiver as receive16_2_, sourcetrac0_.securityclassification as securit17_2_, sourcetrac0_.sender as sender18_2_,
sourcetrac0_.subject as subject19_2_ from source_tracking sourcetrac0_ inner join status_table status2_ on sourcetrac0_.message_id=status2_.message_id
cross join source_tracking sourcetrac1_ order by sourcetrac0_.message_id asc,sourcetrac0_.hopcount asc.
I want to apply distinct to only one column here is what needed query
select distinct on(sourcetrac0_.message_id) sourcetrac0_.message_id,sourcetrac0_.tablekey as tablekey1_2_, sourcetrac0_.alt_recipient_addr as alt_reci2_2_,
sourcetrac0_.alt_recipient_tried as alt_reci3_2_,sourcetrac0_.arrival_time as arrival_4_2_, sourcetrac0_.delivery_status as delivery5_2_, sourcetrac0_.dispatch_time as dispatch6_2_,
sourcetrac0_.hopcount as hopcount7_2_, sourcetrac0_.id as id8_2_, sourcetrac0_.id1 as id9_2_, sourcetrac0_.mail_orig_time as mail_or10_2_,
sourcetrac0_.mail_server as mail_se11_2_, sourcetrac0_.mailtype as mailtyp12_2_, sourcetrac0_.message_id as message13_2_, sourcetrac0_.nexthop as nexthop14_2_,
sourcetrac0_.precedence as precede15_2_, sourcetrac0_.receiver as receive16_2_, sourcetrac0_.securityclassification as securit17_2_, sourcetrac0_.sender as sender18_2_,
sourcetrac0_.subject as subject19_2_ from source_tracking sourcetrac0_ inner join status_table status2_ on sourcetrac0_.message_id=status2_.message_id
cross join source_tracking sourcetrac1_ order by sourcetrac0_.message_id asc,sourcetrac0_.hopcount asc
That's no possible because DISTINCT is done on the result of the query. Read more here:
DISTINCT for only one Column

ALL query in Ecto

I need to translate the following SQL to Ecto Query DSL.
SELECT otc.*
FROM users u
INNER JOIN one_time_codes otc ON u.id = otc.user_id
LEFT OUTER JOIN one_time_code_invalidations otci ON otci.one_time_code_id = otc.id
WHERE u.id = 3 AND
otc.code = 482693 AND
otci.inserted_at IS NULL AND
otc.inserted_at > all(SELECT otc.inserted_at
FROM one_time_codes otc2
WHERE otc2.user_id = 3) AND
otc.inserted_at > (now() - '180 seconds'::interval);
In the third AND statement of WHERE clause, notice there is an ALL query. Ecto seems to not have corresponding function in Ecto.Query.API.
How to apply such aggregate? What is the correct way to implement this, though it could be implemented by having a lookup on debug logs of the Ecto, do you have another idea (or suggestion)?
Thank you.
Ecto does not allow subqueries in expressions, and you're right that there's no all in Ecto's Query API, but you can use fragment like this:
where: ...
and otc.inserted_at > fragment("all(SELECT otc.inserted_at FROM one_time_codes otc2 WHERE otc2.user_id = ?", 3)
and ...

Need help in creating CriteriaQuery

First of all, I would like to know if it is possible to do?
Below is my query and I am trying to build using criteria.
SELECT CONCAT('record-', rl.record_id) AS tempId,
'sloka' AS type,
rl.record_id AS recordId,
rl.title AS title,
rl.locale as locale,
rl.intro AS intro,
rl.title AS localetitle,
NULL AS audioUrl,
lp.name AS byName,
lp.person_id AS byId,
lp.name AS onName,
lp.person_id AS onId
FROM record_locale rl
LEFT JOIN record r ON rl.record_id = r.record_id
LEFT JOIN locale_person lp ON r.written_on = lp.person_id
WHERE rl.title LIKE :title
AND rl.locale = :locale
AND lp.locale = :locale
UNION
SELECT CONCAT('lyric-', s.song_id) AS tempId,
'bhajan' AS type,
s.song_id AS recordId,
s.title,
l.locale as locale,
NULL AS intro,
l.title AS localetitle,
s.audio_url AS audioUrl,
lpb.name AS byName,
lpb.person_id AS byId,
lpo.name AS onName,
lpo.person_id AS onId
FROM song s
LEFT JOIN locale_person lpb
ON (s.written_by = lpb.person_id AND lpb.locale = :locale)
LEFT JOIN locale_person lpo
ON (s.written_on = lpo.person_id AND lpo.locale = lpb.locale)
INNER JOIN lyric l
ON (l.locale = lpb.locale AND l.song_id = s.song_id)
WHERE s.title LIKE :title AND s.approved_by IS NOT NULL
ORDER BY localeTitle ASC
// END
Based on few conditions, I might need to have union of both queries or just individual query without union.
Converting the SQL to JPQL is usually a good first step, as we can't quite tell what these tables map to, or what you are expecting to get back. If it is possible to do in JPQL, it should be possible with a criteria query. Except in this case: JPA/JPQL does not have the union operator so it won't work in straight JPA, but some providers such as EclipseLink have support. See:
UNION to JPA Query
and
http://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/j_union.htm

JPA Criteria Equivalent Query Subquery greatest or max

This SQL query does exactly what is needed when executed. I am looking for the JPA Criteria equivalent? Basically gets the Device entity and the LATEST(greatest) GPS coord from a One-To-Many relationship
SELECT DISTINCT t0.DEVICE_I, t0.ACTIVE_S, t0.APP_CONFIG_I, t0.PREV_APP_CONFIG_I,
t0.APP_CONFIG_CONFIRMED_S, t0.APP_CONFIG_RECEIPT_D, t0.APP_CONFIG_SENT_S, t0.CHANNEL_X,
t0.CREATION_TS, t0.CREATION_USER_I, t0.DEST_QUEUE_C, t0.DIVISION_C, t0.LAN_IP_X,
t0.LAST_UPDATE_TS, t0.LAST_UPDATE_USER_I, t0.MOBILE_IP_X, t0.ORIGIN_MP_I,
t0.PREV_CHANNEL_X, t0.TELEPHONE_NUMBER_X, t0.VERSION_X, t1.DEVICE_I, t1.COORDINATE_I,
t1.CREATION_TS, t1.CREATION_USER_I, t1.GENERATED_TS, t1.GPGGA_X, t1.GPGSA_X,
t1.GPGSV_X, t1.GPRMC_X, t1.GPVTG_X, t1.LAST_UPDATE_TS, t1.LAST_UPDATE_USER_I,
t1.WORK_ORDER_NUMBER_I
FROM DEVICE t0, GPS_COORD t1
WHERE t0.DEVICE_I = t1.DEVICE_I AND
t1.GENERATED_TS IN ( select max(GENERATED_TS)
from GPS_COORD
group by DEVICE_I )
ORDER BY t1.DEVICE_I ASC, t1.GENERATED_TS DESC
The java code below is almost there and generates the following query which is missing joined fields needed from GpsCoord. These fields are included if a fetch is done, but the Join is necessary later in the where clause of the Subquery:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Device> cq = criteriaBuilder.createQuery(Device.class);
Root<Device> device = cq.from(Device.class);
cq.distinct(true);
Join<Device, GpsCoord> j = device.join(Device_.gpsCoords, JoinType.LEFT);
//Fetch<Device,GpsCoord> f = device.fetch(Device_.gpsCoords);
CriteriaQuery<Device> select = cq.select(device);
Subquery<Timestamp> sq = cq.subquery(Timestamp.class);
Root<GpsCoord> gpsCoord = sq.from(GpsCoord.class);
sq.select(criteriaBuilder.greatest(gpsCoord.get(GpsCoord_.generatedTs)));
sq.groupBy(gpsCoord.get(GpsCoord_.device).get(Device_.deviceI));
select.where(j.get(GpsCoord_.generatedTs).in(sq));
TypedQuery<Device> query = this.getEntityManager().createQuery(cq);
Query that is generated is missing the GpsCoord fileds from the Join oepration
SELECT DISTINCT t0.DEVICE_I, t0.ACTIVE_S, t0.APP_CONFIG_I, t0.PREV_APP_CONFIG_I,
t0.APP_CONFIG_CONFIRMED_S, t0.APP_CONFIG_RECEIPT_D, t0.APP_CONFIG_SENT_S,
t0.CHANNEL_X, t0.CREATION_TS, t0.CREATION_USER_I, t0.DEST_QUEUE_C, t0.DIVISION_C,
t0.LAN_IP_X, t0.LAST_UPDATE_TS, t0.LAST_UPDATE_USER_I, t0.MOBILE_IP_X, t0.ORIGIN_MP_I,
t0.PREV_CHANNEL_X, t0.TELEPHONE_NUMBER_X, t0.VERSION_X
FROM SPW_OWN.DEVICE t0, SPW_OWN.GPS_COORD t1
WHERE (t1.GENERATED_TS IN (SELECT MAX(t2.GENERATED_TS) FROM SPW_OWN.GPS_COORD t2,
SPW_OWN.DEVICE t3 WHERE t2.DEVICE_I = t3.DEVICE_I GROUP BY t3.DEVICE_I))
AND t0.DEVICE_I = t1.DEVICE_I(+)
Using a multiselect from the CriteriaQuery like this generates the proper SQL when executed, but the following exception
Caused by: java.lang.Exception: java.lang.RuntimeException: Can not find constructor for "class Device" with argument types "[class java.lang.String ... java.sql.Timestamp]" to fill data.
gets thrown after the call:
CriteriaQuery<Device> select = cq.multiselect(
//"deviceI",
device.get(Device_.deviceI),
//"activeS",
device.get(Device_.activeS),
//"appConfigConfirmedS",
device.get(Device_.appConfigConfirmedS),
//"appConfigReceiptD",
device.get(Device_.appConfigReceiptD),
//"appConfigSentS",
device.get(Device_.appConfigSentS),
//"channelX",
device.get(Device_.channelX),
//"destQueueC",
device.get(Device_.destQueueC),
//"lanIpX",
device.get(Device_.lanIpX),
//"mobileIpX",
device.get(Device_.mobileIpX),
//"prevChannelX",
device.get(Device_.prevChannelX),
//"telephoneNumberX",
device.get(Device_.telephoneNumberX),
//"versionX"
device.get(Device_.versionX),
//"device",
j.get(GpsCoord_.device),
//"gpggaX",
j.get(GpsCoord_.gpggaX),
//"gprmcX",
j.get(GpsCoord_.gprmcX),
//"gpgsaX",
j.get(GpsCoord_.gpgsaX),
//"gpgsvX",
j.get(GpsCoord_.gpgsvX),
//"gpvtgX"
j.get(GpsCoord_.gpvtgX),
j.get(GpsCoord_.generatedTs)
);
A few issues,
you call, sq.from(GpsCoord.class); twice
using device.fetch(Device_.gpsCoords); will also fetch the object, and will join it twice
you IN is incorrect it should be,
select.where(criteriaBuilder.get(path).in(sq));

Forming JPQL query from native SQL query for multiple views with CASE condition and join statements

Kindly helping in converting native query ti JPQL query for multiple views with CASE condition and join statements.Table c1 and c3 are views. I am trying the get the current and pending information from c1.
Please find the query mentioned below
SELECT c3.eqip_id AS EQIP_ID,
CASE WHEN c1.inst_ts IS NULL OR c1.sent_ts > c1.inst_ts THEN c1.ver_nm END AS PEND,
CASE WHEN c1.sent_ts IS NULL OR c1.sent_ts > c1.inst_ts THEN c1.ver_nm END AS CURRENT,
c1.trm_ver_hist_id AS TRM_VER_HIST_ID
FROM trm_ver_hist_vw c1
JOIN(SELECT Max(trm_ver_hist_id) AS TRM_VER_HIST_ID, dvc_id, status
FROM trm_ver_hist_vw
WHERE ver_typ_id = 1 AND status IN( 'C', 'P' )
GROUP BY dvc_id, status) c2
ON c1.trm_ver_hist_id = c2.trm_ver_hist_id
JOIN trm_dtl_vw c3 ON c1.dvc_id = c3.trm_id
WHERE c3.co_actv_ind = 'Y' AND c3.mach_hdwr_asscn_ind = 'Y' AND pin = 'ABC'
Can anyone please help me to make this query in JPA/JPQL?
It seems very complex and data specific. I would recommend using a native SQL query.
The JPA spec does not allow selects in the FROM clause, although EclipseLink does have some support for this.
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Sub-selects_in_FROM_clause