int4range, NOT IN (VALUES), ON NOT (with LEFT JOIN) in QueryDSL 4 - postgresql

I would like to know, how to make a int4range / NOT IN (VALUES) / ON NOT (with LEFT JOIN) in QueryDSL 4.
I've writte this SQL request :
SELECT DISTINCT ON (numero_semaine, jour_semaine)
numero_semaine, jour_semaine, heure_debut, heure_fin, id_box
FROM (
SELECT po.* FROM (
(SELECT DISTINCT ON (numero_semaine, jour_semaine)
numero_semaine, jour_semaine, heure_debut, heure_fin, id_box
FROM accueil.semaine_type_box
INNER JOIN accueil.plage_ouverture
ON accueil.plage_ouverture.id_semaine_type = accueil.semaine_type_box.id_semaine_type
INNER JOIN accueil.semaine_type
ON accueil.semaine_type.id = accueil.semaine_type_box.id_semaine_type
INNER JOIN accueil.box
ON accueil.box.id = accueil.semaine_type_box.id_box
WHERE semaine_type_box.numero_semaine >= 48
AND semaine_type_box.numero_semaine <= 52
AND (numero_semaine, jour_semaine)
---->NOT IN (VALUES (48,1), (48,2), (48,3), (48,4), (52,6), (52,7))<----
AND semaine_type.site = 'UR130'
AND box.ouvert_cotisant = TRUE
ORDER BY numero_semaine, jour_semaine, heure_debut
)
UNION ALL
(SELECT DISTINCT ON (numero_semaine, jour_semaine)
extract(week from plage_exceptionnelle.date) as numero_semaine,
extract(isodow from plage_exceptionnelle.date) as jour_semaine,
heure_debut, heure_fin, id_box
FROM accueil.plage_exceptionnelle
INNER JOIN accueil.box ON
accueil.box.id= accueil.plage_exceptionnelle.id_box
WHERE plage_exceptionnelle.date >= '2018-11-30'
AND plage_exceptionnelle.date <= '2018-12-28'
AND ouverte = TRUE
AND box.site = 'UR130'
AND box.ouvert_cotisant = TRUE
ORDER BY numero_semaine, jour_semaine, heure_debut
)
) po
LEFT JOIN (
SELECT
extract(week from plage_bloquee.date) as numero_semaine,
extract(isodow from plage_bloquee.date) as jour_semaine,
heure_debut, heure_fin, id_box
FROM accueil.plage_bloquee
INNER JOIN accueil.box ON accueil.box.id = accueil.plage_bloquee.id_box
WHERE box.site = 'UR130'
AND box.ouvert_cotisant = TRUE
) pb
---->ON NOT(po.jour_semaine = pb.jour_semaine<----
---->AND int4range(po.heure_debut, po.heure_fin) && int4range(pb.heure_debut, pb.heure_fin)<----
AND po.id_box = pb.id_box
AND po.numero_semaine = pb.numero_semaine
)
WHERE pb.id_box IS NOT NULL
) end_table
ORDER BY numero_semaine,jour_semaine,heure_debut
What is the way to do this SQL request ?
I've writte this, but I don't find the way to writte a not in, on not with left join, and int4range doesn't exist with QueryDSL 4 :
public List<PlageDisponibleWS> findDayAvailableDao(String organisme, String site, MediaEnum media) {
final LocalDate startDate = LocalDate.now();
final short startWeekOfWeekYear = (short) startDate.getWeekOfWeekyear();
final short startDay = (short) startDate.getDayOfWeek();
final LocalDate endDate = startDate.plusMonths(1);
final short endWeekOfWeekYear = (short) endDate.getWeekOfWeekyear();
final int MONDAY_START_DAY = 1;
final int TUESDAY_START_DAY = 2;
final int WEDNESDAY_START_DAY = 3;
final int THURSDAY_START_DAY = 4;
final int FRIDAY_START_DAY = 5;
final int SATURDAY_START_DAY = 6;
final int SUNDAY_START_DAY = 7;
PostgreSQLQuery<Tuple> plagesOuvertes = queryFactory
.select(qSemaineTypeBox.numeroSemaine, qSemaineTypeBox.idBox, qPlageOuverture.jourSemaine,
qPlageOuverture.heureDebut, qPlageOuverture.heureFin)
.distinctOn(qSemaineTypeBox.numeroSemaine, qPlageOuverture.jourSemaine).from(qSemaineTypeBox)
.innerJoin(qPlageOuverture).on(qPlageOuverture.idSemaineType.eq(qSemaineTypeBox.idSemaineType))
.innerJoin(qSemaineType).on(qSemaineType.id.eq(qSemaineTypeBox.idSemaineType)).innerJoin(qBox)
.on(qBox.id.eq(qSemaineTypeBox.idBox)).where(qSemaineTypeBox.numeroSemaine.goe(startWeekOfWeekYear))
.where(qSemaineTypeBox.numeroSemaine.loe(endWeekOfWeekYear))
// NOT IN (VALUES (startWeekOfWeekYear,MONDAY_START_DAY), (startWeekOfWeekYear,TUESDAY_START_DAY),
// (startWeekOfWeekYear,WEDNESDAY_START_DAY), (startWeekOfWeekYear,THURSDAY_START_DAY),
// (endWeekOfWeekYear,SATURDAY_START_DAY), (endWeekOfWeekYear,SUNDAY_START_DAY)) ??
.where(qSemaineType.site.eq(site)).where(qBox.ouvertCotisant.eq(true))
.orderBy(qSemaineTypeBox.numeroSemaine.asc(), qPlageOuverture.jourSemaine.asc(),
qPlageOuverture.heureDebut.asc());
PostgreSQLQuery<Tuple> plagesExceptionnelles = queryFactory
.select(qPlageExceptionnelle.date.week().as("numero_semaine"),
qPlageExceptionnelle.date.dayOfWeek().as("jour_semaine"), qPlageExceptionnelle.heureDebut,
qPlageExceptionnelle.heureFin, qPlageExceptionnelle.idBox)
.distinctOn(qSemaineTypeBox.numeroSemaine, qPlageOuverture.jourSemaine).from(qPlageExceptionnelle)
.innerJoin(qBox).on(qBox.id.eq(qPlageExceptionnelle.idBox))
.where(qPlageExceptionnelle.date.goe(startDate)).where(qPlageExceptionnelle.date.loe(endDate))
.where(qPlageExceptionnelle.ouverte.eq(true)).where(qBox.site.eq(site))
.where(qBox.ouvertCotisant.eq(true)).orderBy(qSemaineTypeBox.numeroSemaine.asc(),
qPlageOuverture.jourSemaine.asc(), qPlageOuverture.heureDebut.asc());
PostgreSQLQuery<Tuple> plagesBloquees = queryFactory
.select(qPlageBloquee.date.week().as("numero_semaine"),
qPlageBloquee.date.dayOfWeek().as("jour_semaine"), qPlageBloquee.heureDebut,
qPlageBloquee.heureFin, qPlageBloquee.idBox)
.from(qPlageBloquee).innerJoin(qBox).on(qBox.id.eq(qPlageBloquee.idBox)).where(qBox.site.eq(site))
.where(qBox.ouvertCotisant.eq(true));
#SuppressWarnings("unchecked")
Expression<Tuple> unionSubQuery = queryFactory.query().unionAll(plagesOuvertes, plagesExceptionnelles)
.as("po");
final PathBuilder<Object> aliasPb = new PathBuilder<>(Object.class, "pb");
PostgreSQLQuery<Tuple> leftJoinSubQuery = queryFactory.select(unionSubQuery)
.leftJoin(plagesBloquees, aliasPb)
// ON NOT
// INT4RANGE
;
final PathBuilder<Object> aliasEnd = new PathBuilder<>(Object.class, "end_table");
query = queryFactory
.select(Projections.constructor(PlageDisponibleWS.class, qSemaineTypeBox.numeroSemaine,
qSemaineTypeBox.idBox, qPlageOuverture.jourSemaine, qPlageOuverture.heureDebut,
qPlageOuverture.heureFin))
.distinctOn(qSemaineTypeBox.numeroSemaine, qPlageOuverture.jourSemaine)
.from(leftJoinSubQuery, aliasEnd).orderBy(qSemaineTypeBox.numeroSemaine.asc(),
qPlageOuverture.jourSemaine.asc(), qPlageOuverture.heureDebut.asc())
.fetch();
return query;
}
So please have you any idea to solve my problems ?
Thanks a lot in advance.

For "in values" construction with multiple columns you can try this:
.where(list(table.column1, table.column2).
in(list(select(constant("aaa"), constant("bbb")),
select(constant("ccc"), constant("ddd")),
select(constant("eee"), constant("fff")))))
Function "list" and "select comes from these imports:
import static com.querydsl.core.types.dsl.Expressions.*;
import static com.querydsl.sql.SQLExpressions.*;
For "left join + not", try this:
.from(table1)
.leftJoin(table2)
.on(table1.id.ne(table2.id))
Unfortunatly I am not familar with int4range function, hovewer you can try to use template expression for custom database functions:
Expressions.template(Integer.class, "custom_db_function({0}, {1})", 10, 20);

Related

criteria api sub-select with sub-select and custom fields

I'd like to rewrite following sql query to criteria api:
select * from demands d
where exists (
select * from (
select a.demandid,
min(coalesce(a.securitylevel, a.securitylevel, -1)) themin,
max(coalesce(a.securitylevel, -1)) themax
from allocations a
group by demandid)
where demandid = d.id
and (themin = -1 and themax = -1
or themax >= 5)
);
The problem is that I'm not able to figure out how to write select clause for sub-queries, my current implementation produces CompoundSelection however subQyer.select accepts only Expression (DemandSecLevel is custom POJO/DTO).
public static Specification<Demand> bySecurityLevel(
final Integer securityLevel) {
return (root, query, cb) -> {
final Subquery<DemandSecLevel> subQuery = query.subquery(DemandSecLevel.class);
final Root<AllocationEntry> allocationEntryRoot = subQuery.from(AllocationEntry.class);
subQuery.select(cb.construct(
DemandSecLevel.class,
allocationEntryRoot.get(AllocationEntry_.incidentDemandId),
cb.min(cb.coalesce(allocationEntryRoot.get(AllocationEntry_.securityLevel), -1))
.alias("minSecLevel"),
cb.max(cb.coalesce(allocationEntryRoot.get(AllocationEntry_.securityLevel), -1))
.alias("maxSecLevel")
));

How to select from subquery if column contains a specific value in postgre

I would like to ask if it is possible to select again from a result set if a column contains a specific value?
For example, from the below query I want to select it as subquery and check if that subquery's first column contains both 2 and 3 result. Otherwise, no values should be return.
select e.evaluator_id, ROUND(avg(cast(e.rating_score as int))::numeric,1)::varchar, c.q_category_name
from tms.t_evaluation e
inner join tms.m_q_category c
on e.nendo=c.nendo
and e.q_category_id = c.q_category_id
and c.delete_flg = '0'
inner join tms.m_q_subcategory qs
on e.q_category_id = qs.q_category_id
and e.q_subcategory_id = qs.q_subcategory_id
and c.nendo = qs.nendo
and qs.delete_flg = '0'
where e.nendo = '2018'
and e.empl_id = 'empl05'
and e.delete_flg = '0'
and e.evaluator_id in ('2' , '3')
group by e.empl_id, e.nendo, e.q_category_id,
c.q_category_name, e.evaluator_id, e.history_no
Result contains both 2 and 3 in first column. Is this possible?
select e.evaluator_id, ROUND(avg(cast(e.rating_score as int))::numeric,1)::varchar, c.q_category_name
from tms.t_evaluation e
inner join tms.m_q_category c
on e.nendo=c.nendo
and e.q_category_id = c.q_category_id
and c.delete_flg = '0'
inner join tms.m_q_subcategory qs
on e.q_category_id = qs.q_category_id
and e.q_subcategory_id = qs.q_subcategory_id
and c.nendo = qs.nendo
and qs.delete_flg = '0'
where e.nendo = '2018'
and e.empl_id = 'empl05'
and e.delete_flg = '0'
and e.evaluator_id in (select case when evaluator_id=2 or evaluator_id=3 then evaluator_id else null from t_evaluation order by evaluator_id asc)
group by e.empl_id, e.nendo, e.q_category_id,
c.q_category_name, e.evaluator_id, e.history_no

Can I JOIN table on the basis of the case statement in PostgreSQL

Can I JOIN the table on the basis of the case statement in PostgreSQL. I have written the one SQL in stored procedure into that I'm passing the one flag on that basis I want to jon the table. Please see the case statement,
JOIN lease_intervals li_active
ON ( li_active.cid = l.cid AND l.id = li_active.lease_id AND
l.active_lease_interval_id = li_active.id )
LEFT JOIN applications a
ON ( a.cid = li.cid AND li.lease_id = a.lease_id AND
a.lease_interval_id = li.id )
**CASE
WHEN pIsFromUI = TRUE
THEN JOIN property_integration_databases pid ON ( pid.cid = l.cid AND pid.property_id == l.property_id )
JOIN integration_databases id ON ( id.id = pid.integration_database_id AND id.cid = pid.cid )
ELSE
1
END**
Please let me know is there any alternate solution for above.
join
lease_intervals li_active on
li_active.cid = l.cid and l.id = li_active.lease_id and
l.active_lease_interval_id = li_active.id
left join
applications a on
a.cid = li.cid and li.lease_id = a.lease_id and
a.lease_interval_id = li.id
left join
property_integration_databases pid on
pid.cid = l.cid and pid.property_id = l.property_id and pisfromui
left join
integration_databases id on
id.id = pid.integration_database_id and id.cid = pid.cid and pisfromui

Does Not Exist using Multiple Columns

I am trying to find all records in my #TempTable that are not in the staging table.
Its important to note that the comparison needs to take place over 16 fields.
I have tried several combinations and nothing seems to work.
SELECT CustomerAccountNo FROM #TempTable
WHERE NOT EXISTS
(SELECT e.[CustomerAccountNo] ,
e.[MeterNo] ,
e.[CustomerName1] ,
e.[ServiceAddress1] ,
e.[ServiceAddress2] ,
e.[ServiceCity] ,
e.[ServiceState] ,
e.[ServiceZip] ,
e.[BillingAddress1] ,
e.[BillingAddress2] ,
e.[BillingAddress3] ,
e.[BillingCity] ,
e.[BillingState] ,
e.[BillingZip] ,
e.[BillingZip4] ,
e.[PrimaryPhoneNumber] FROM #TempTable e
JOIN dbo.Staging s
ON e.CustomerAccountNo = s.CustomerAccountNo AND
e.MeterNo = s.MeterNo AND
e.CustomerName1 = s.CustomerName1 AND
e.ServiceAddress1 = s.ServiceAddress1 AND
e.ServiceAddress2 = s.ServiceAddress2 AND
e.ServiceCity = s.ServiceCity AND
e.ServiceState = s.ServiceState AND
e.ServiceZip = s.ServiceZip AND
e.BillingAddress1 = s.BillingAddress1 AND
e.BillingAddress2 = s.BillingAddress2 AND
e.BillingAddress3 = s.BillingAddress3 AND
e.BillingCity = s.BillingCity AND
e.BillingState = s.BillingState AND
e.BillingZip = s.BillingZip AND
e.BillingZip4 = s.BillingZip4 AND
e.PrimaryPhoneNumber= s.PrimaryPhoneNumber
)
Instead of a JOIN, try using Except.
SELECT CustomerAccountNo, MeterNo -- and so on
FROM #TempTable
EXCEPT
SELECT CustomerAccountNo, MeterNo -- and so on
FROM Staging
Just do a join and look for null. Like this
SELECT e.*
FROM #TempTable e
LEFT JOIN dbo.Staging s
ON e.CustomerAccountNo = s.CustomerAccountNo AND
e.MeterNo = s.MeterNo AND
e.CustomerName1 = s.CustomerName1 AND
e.ServiceAddress1 = s.ServiceAddress1 AND
e.ServiceAddress2 = s.ServiceAddress2 AND
e.ServiceCity = s.ServiceCity AND
e.ServiceState = s.ServiceState AND
e.ServiceZip = s.ServiceZip AND
e.BillingAddress1 = s.BillingAddress1 AND
e.BillingAddress2 = s.BillingAddress2 AND
e.BillingAddress3 = s.BillingAddress3 AND
e.BillingCity = s.BillingCity AND
e.BillingState = s.BillingState AND
e.BillingZip = s.BillingZip AND
e.BillingZip4 = s.BillingZip4 AND
e.PrimaryPhoneNumber= s.PrimaryPhoneNumb
WHERE s.CustomerAccountNo is null
You should provide more detailed circumstance to get correct answer.
Clearly, you don't have any connection between your FROM clause and WHERE clause so the query will return all.
Try this one:
SELECT CustomerAccountNo FROM #TempTable t
WHERE NOT EXISTS
(SELECT 1 FROM dbo.Staging s WHERE
t.CustomerAccountNo = s.CustomerAccountNo AND
t.MeterNo = s.MeterNo AND
t.CustomerName1 = s.CustomerName1 AND
t.ServiceAddress1 = s.ServiceAddress1 AND
t.ServiceAddress2 = s.ServiceAddress2 AND
t.ServiceCity = s.ServiceCity AND
t.ServiceState = s.ServiceState AND
t.ServiceZip = s.ServiceZip AND
t.BillingAddress1 = s.BillingAddress1 AND
t.BillingAddress2 = s.BillingAddress2 AND
t.BillingAddress3 = s.BillingAddress3 AND
t.BillingCity = s.BillingCity AND
t.BillingState = s.BillingState AND
t.BillingZip = s.BillingZip AND
t.BillingZip4 = s.BillingZip4 AND
t.PrimaryPhoneNumber= s.PrimaryPhoneNumber
)

Can some one help me to conver it into LINQ i m using Entity Framework

select ForumCategories.ID , ForumCategories.Title , ForumCategories.DateCreated,
CO = ( select COUNT(*) from ForumSubCategories where ForumSubCategories.CategoryID_FK = ForumCategories.ID)
from ForumCategories
var q = from fc in Context.ForumCategories
select new
{
Id = fc.ID,
Title = fc.Title,
DateCreated = fc.DateCreated
CO = fc.ForumSubCategories.Count()
};
return q;
The "join" (subquery) is implicit; it's defined in the relationship between ForumCategories and ForumSubCategories in your model. Using this syntax, the call to Count() will be done on the DB server.