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 ...
I have just switched from mysql to postgresql and my working dql queries stopped working.
Here is my dql
SELECT p
FROM AppBundle:Photo p
JOIN AppBundle:Like l WITH p = l.photo
WHERE p.isModerated = :isModerated
AND p.isActive = :isActive
AND p.category IN(:categories)
AND p.creationDate <= :begin
AND p.creationDate >= :end
GROUP BY p.id
ORDER BY l.creationDate DESC
Getting the next error
SQLSTATE[42803]: Grouping error: 7 ERROR: column "l1_.creation_date" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: ... p0_.creation_date >= $4 GROUP BY p0_.id ORDER BY l1_.creati...
As i can understand, it says that group by column should be in SELECT. I dont it to be there. I need to select just p (AppBundle:Photo) and nothing more. What should be edited in dql to get it working properly?
Thank you.
I just replaced ORDER BY l.creationDate DESC to ORDER BY p.creationDate DESC
It will work for me. As i understood, ORDER BY column should be SELECTed
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
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));
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