Update multiple tables with JOOQ - java

the problem here with jooq is that it doesn't support join and updates, moreover updates on multiple tables.
I find a way to transform this query:
String query = "UPDATE knowCRM.customer_did cd ";
query += " LEFT JOIN knowCRM.know_service ks";
query += " ON ks.id = cd.customer_service_id";
query += " LEFT JOIN knowCRM.customer_flags cf";
query += " ON ks.service_owner_id = cf.account_number";
query += " SET cd.is_cli_number= 1, cf.is_cli_number = '0'";
query += " WHERE ks.service_owner_id = " + accountNumber;
query += " AND cd.did_number= " + cliNumber;
into these two:
int count2 = wrapper.getCreate().update(CUSTOMER_DID)
.set(CUSTOMER_DID.IS_CLI_NUMBER, Byte.parseByte("1"))
.where(CUSTOMER_DID.CUSTOMER_SERVICE_ID.equal(
wrapper.getCreate().select(KNOW_SERVICE.ID)
.from(CUSTOMER_FLAGS, KNOW_SERVICE)
.where(KNOW_SERVICE.ID.equal(CUSTOMER_DID.CUSTOMER_SERVICE_ID))
.and(KNOW_SERVICE.SERVICE_OWNER_ID.equal(CUSTOMER_FLAGS.ACCOUNT_NUMBER))
.and(KNOW_SERVICE.SERVICE_OWNER_ID.equal(accountNumber))
.and(CUSTOMER_DID.DID_NUMBER.equal(cliNumber))
))
.execute();
and
int count3 = wrapper.getCreate().update(CUSTOMER_FLAGS)
.set(CUSTOMER_FLAGS.IS_CLI_NUMBER, Byte.parseByte("0"))
.where(CUSTOMER_FLAGS.ACCOUNT_NUMBER.equal(
wrapper.getCreate().select(KNOW_SERVICE.SERVICE_OWNER_ID)
.from(CUSTOMER_DID, KNOW_SERVICE)
.where(KNOW_SERVICE.ID.equal(CUSTOMER_DID.CUSTOMER_SERVICE_ID))
.and(KNOW_SERVICE.SERVICE_OWNER_ID.equal(CUSTOMER_FLAGS.ACCOUNT_NUMBER))
.and(KNOW_SERVICE.SERVICE_OWNER_ID.equal(accountNumber))
.and(CUSTOMER_DID.DID_NUMBER.equal(cliNumber))
))
.execute();
I would like a more clever way to refactor this query with jooq whithout having to split it into two massive queries.

In principle, the JOIN operations are specified on an org.jooq.Table. There's a pending feature request to add "join convenience methods" also to UPDATE, just as they exist also on SELECT: #3266
Your original query can be written as such in jOOQ:
CustomerDid cd = CUSTOMER_DID.as("cd");
KnowService ks = KNOW_SERVICE.as("ks");
CustomerFlags cf = CUSTOMER_FLAGS.as("cf");
ctx.update(cd.leftJoin(kd)
.on(ks.ID.eq(cd.CUSTOMER_SERVICE_ID))
.leftJoin(cf)
.on(ks.SERVICE_OWNER_ID.eq(cf.ACCOUNT_NUMBER)))
.set(cd.IS_CLI_NUMBER, 1)
.set(cf.IS_CLI_NUMBER, "0")
.where(ks.SERVICE_OWNER_ID.eq(accountNumber))
.and(cd.DID_NUMBER.eq(cliNumber))
.execute();

Related

Problem with query update and select with where and join

select new mvp.backend.finance.dto.projection.SplitShipDto(spl.id, spl.promoVolume, spl.baselineVolumeProportion) from SplitShipment spl inner join DateDay spd on spl.dateDay.id = spd.id " +
"where spl.sku.id =:sku_id and spd.day > cast(:date as string)
skuIdAndDates.parallelStream().forEach(spl -> {
float rcpPromo = priceFromSap.getBasePrice() * spl.getPromoVolume();
float rcpBaseline = priceFromSap.getBasePrice() * spl.getBaselineVolumeProportion();
RequestSplitShipmentRCP requestSplitShipmentRCP = RequestSplitShipmentRCP.builder().id(spl.getId()).rcpPromo(rcpPromo).rcpBaseline(rcpBaseline).build();
splitShipmentRCP.add(requestSplitShipmentRCP);
});
update split_shipments set " +
"rcp_promo =:rcpPromo, rcp_baseline =:rcpBaseline " +
"where id =:id
Guys help me. I must use this 2 queries in one query. In first query i select spl.id, spl.promoVolume, spl.baselineVolumeProportion from table split_shipments. How I can creat this? Sorry for my eng...

Filter rows in DataSet using JPA/Hibernate

I have the following code which is used to retrieve data from multiple tables (using joins) and then mapping every row into a DTOList but I also need to apply filters based on user preferences: per table1.name or table2.name, table3, etc.
So I just want to know what would be the best way to do it in terms of performance and best practices;
retrieving all rows and then apply the filters with lambdas (easier)
change the query to a dynamic query with Criteria or something else?
Any other solution=?
#Repository
public class ArchiveRepository {
#Autowired
EntityManager em;
String queryStr = "select wsr.id as sampleid, s.id as slideid, tb.name as batchname, k.lot_number as kitlot, " +
" 'STRING' as slidetype, tb.worklist_name as worklist, wsr.final_call as results, " +
" wa.final_pattern_ids as patterns, 'edited/yesno' as edited, wsr.last_modified_by as user, wsr.last_modified_date as time " +
" from slide s " +
" left join table2 tb on s.test_batch_id = tb.id " +
" left join table3 k on tb.kit_lot_id = k.id " +
" left join table4 w on s.id = w.slide_id " +
" left join tabl5 pw on pw.well_id = w.id " +
" left join tabl6 cw on cw.well_id = w.id " +
" left join tabl7 wsr on wsr.patient_well_sample_id = pw.id or wsr.control_sample_id = cw.id " +
" left join (select * from *** (other subselect)) wa on wa.well_sample_id = wsr.**id or wa.well_sample_id = wsr.**id " +
"where tb.state = 'STATENEEDED'";
public ArchiveDataListDTO getArchiveData(){
Query query = em.createNativeQuery(queryStr);
ArchiveDataListDTO archiveDataListDTO = new ArchiveDataListDTO();
List<Object[]> resultL = (List<Object[]>)query.getResultList();
for( Object[] o : resultL){
archiveDataListDTO.addArchiveDataRow(
new ArchiveDataDTO((String)o[0], String.valueOf(o[1]), (String) o[2], (String) o[3], (String) o[4], (String) o[5],
(String) o[6], (String) o[7], (String) o[8], (String) o[9], (String) o[10]));
}
return archiveDataListDTO;
}
}
**
note I struggled some with the code cause I wanted to apply #sqlresultsetmapping to avoid manual results mapping but it just didn´t work, most of the examples out there are when you have an entity in the DB but in this case I retrieve from many tables.**
Thanks so much
2 .- change the query to a dynamic query with Criteria or something else?
I ended up creating the query on the fly; depending on the filters I get from UI i assemble the query with Java and send it to DB, it´s easier since this required many tables...

Spring JPA filter optional criteria in Query method

I want to filter out data from a database with few criteria (let's assume it is 8).
And below query method do this in a good way. But in fact, this criterias passed to the query method can be null (it means that should not be included to select query).
How I should handle this situation?
I really don't want to make n-methods to handle each case - it is not a good way.
#Query("SELECT NEW api.model.GeneralAnnouncementInfo(" +
"an.id, an.title, po.price, SUBSTRING(an.description, 1, 100), an.provider, an.creationDate, an.url, l.lessorType, concat(loc.city, ' ', loc.district)) " +
"FROM Announcement as an " +
"LEFT JOIN an.priceOffer as po " +
"LEFT JOIN an.lessor as l " +
"LEFT JOIN an.location as loc " +
"LEFT JOIN an.propertyData as pd " +
"WHERE l.lessorType = (:lessor) " +
"AND pd.roomNumber = (:rooms) " +
"AND pd.bathroomNumber = (:baths) " +
"AND pd.parkingAvailability = (:parking) " +
"AND pd.isSmokingAllowed = (:smokers) " +
"AND pd.isPetFriendly = (:pets) " +
"AND pd.area = (:realPrice) " +
"AND po.price = (:area) ")
Page<GeneralAnnouncementInfo> getAnnouncementsBySearchCriteria(Pageable pageable,
String lessor,
String rooms,
String baths,
String parking,
String smokers,
String pets,
String realPrice,
String area
);
I would recommend switching to the JPA Criteria API. It will give you the extra flexibility you are seeking (and which JPQL seems to be maxing out for your case). You can build your queries programmatically without any limitations and the best thing is that they get compiled; which means that no typos will survive (which are a nightmare to track in JPQL queries). Additionally you may want to use JPA metamodel classes; which add more robustness to your queries. At the end, your repository method would look something like this:
private EntityManager em;
private Page<GeneralAnnouncementInfo> getAnnouncementsBySearchCriteria(QueryParameters qParams) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SampleEntity> criteria = cb.createQuery(GeneralAnnouncementInfo.class);
Root<GeneralAnnouncementInfo> root = criteria.from(GeneralAnnouncementInfo.class);
// Programmatically build query details (conditions, joins, aggregations, translation, etc)
// ...
// ...
// ...
return em.createQuery(criteria).getResultList();
}

MySQL JDBC Fail calculating row number

I have this select that works every time running in workbench but fails sometimes for the same arguments over jdbc. The problem is that sometimes, over JDBC, 'pos' value returns null. I Think that, for some reason, the #p as not started, but dont know how to fix.
SELECT t1.wId, t1.twId, t1.name, t1.timeout, t1.pos
FROM (
SELECT w.id AS wId, tw2.id AS twId, w.name AS name, tw2.timeout AS timeout, #p:=#p+1 AS pos
FROM timeout_workqueue tw1
INNER JOIN timeout_workqueue tw2
ON tw1.workqueue_id = tw2.workqueue_id
INNER JOIN workqueue w
ON tw1.workqueue_id = w.id
WHERE tw1.id = ?
ORDER BY tw2.id) t1, (SELECT #p:=1) c
WHERE t1.twId = ?;
The whole Java Code Are:
public TimeoutWorkqueueView getTimeoutWorkqueueView(Integer id) {
String sql = "SELECT t1.wId, t1.twId, t1.name, t1.timeout, t1.pos"
+ " FROM ("
+ " SELECT w.id AS wId, tw2.id AS twId, w.name AS name, tw2.timeout AS timeout, #p:=#p+1 AS pos"
+ " FROM timeout_workqueue tw1"
+ " INNER JOIN timeout_workqueue tw2"
+ " ON tw1.workqueue_id = tw2.workqueue_id"
+ " INNER JOIN workqueue w"
+ " ON tw1.workqueue_id = w.id"
+ " WHERE tw1.id = ?"
+ " ORDER BY tw2.id) t1, (SELECT #p:=1) c"
+ " WHERE t1.twId = ?";
return (TimeoutWorkqueueView) getJdbcTemplate().queryForObject(sql, new BeanPropertyRowMapper(TimeoutWorkqueueView.class), id, id);
}
Ok so the problem i can see here (please verify) is that you think you are running the query with parameter set to 1 to begin with.
However if you set #p = 1 -> this #p:=#p+1 will not evaluate to 1 any more.
Also assuming you have 20 rows, you run this query 20 times but on the last run it will return null because pos will be 21 and this does not exists.

How can I get the alias name for my ResultSet from a Subquery?

I have a problem with getting the alias of the columnnames for my ResultSet.
I made a subquery, where i use the alias function(MAX(...) in SQL) but everytime I execute the Statement, I get java.sql.SQLException because the column name is not valid. And I use the current alias where I call the getString - Function of my ResultSet.
This is my SQL-Statement in Eclipse:
String sql = "SELECT a.steelgrade, a.prod_order_id, a.prod_order_item_pos, "
+"a.prod_order_version, a.strip_thickn_aim, a.strip_width_aim, "
+"a.customer, a.order_weight_plan, b.grund_kommlos, b.coil_weight "
+"FROM (SELECT prod_order_id, prod_order_item_pos, "
+ "MAX (prod_order_version) AS max_version "
+ "FROM production_order "
And in the ResultSet while.next()-Loop:
prod_order_version = AuftraegeProduction.getString("max_version");
This is the whole SQL-Statement( in the Database it works fine!):
SELECT a.steelgrade, a.prod_order_id, a.prod_order_item_pos,
a.prod_order_version, a.strip_thickn_aim, a.strip_width_aim,
a.customer, a.order_weight_plan, b.grund_kommlos, b.coil_weight
FROM (SELECT prod_order_id, prod_order_item_pos,
MAX (prod_order_version) AS max_version
FROM production_order
GROUP BY prod_order_id, prod_order_item_pos) c
JOIN
production_order a
ON a.prod_order_id = c.prod_order_id
AND a.prod_order_item_pos = c.prod_order_item_pos
AND a.prod_order_version = c.max_version
JOIN pps_plan_slab b
ON b.prod_order_id = c.prod_order_id
AND b.prod_order_item_pos = c.prod_order_item_pos
AND b.prod_order_version = c.max_version
WHERE a.strip_thickn_aim > 1.78
AND a.strip_thickn_aim < 3.26
AND a.steelgrade = 'M4R51'
AND a.prod_order_id NOT BETWEEN '0999551' AND '0999599'
AND a.strip_width_aim BETWEEN 1126 AND 1166
AND NVL (a.order_weight_plan, 0) > 0
AND a.order_weight_plan >= b.coil_weight
ORDER BY prod_order_id ASC
Anyone have a suggestion?
Maurice
when using aggregate functions max(),min(),sum(),... you must use group by clause clause.

Categories

Resources