i want to count null values in JPQL but count (case when "column" is null then.. end) doesn't work it work only on MYSQL ,i don't want to use count(*) what is the solution ??
String jpql ="select c.commande.user.login ,count(CASE WHEN c.commande.commandeTms is Null THEN 1 else 0 END) AS count1 from Designation c GROUP BY c.commande.user.login";
here my database
Here you go : I have used CriteriaBuilder to count them ... as a result, you get a List of Tuple containing the user login and count elements ... you may want to change names and "count cases" according to your needs :
public List<Tuple> test() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createQuery(Tuple.class);
Root<Designation> designation = cq.from(Designation.class);
Join<Designation, Commande> commande = designation.join("commande");
Join<Commande, User> user = commande.join("user");
Expression expr = commande.get("commandeTms");
cq.multiselect(user.get("login").alias("login"),
cb.sum(cb.<Long>selectCase().when(expr.isNotNull(), 1L).otherwise(0L)).alias("NotNull"),
cb.sum(cb.<Long>selectCase().when(expr.isNull(), 1L).otherwise(0L)).alias("Null"));
cq.groupBy(user.get("login"));
Query query = entityManager.createQuery(cq);
return query.getResultList();
}
You can use SUM aggregate function for this case
String jpql ="SELECT c.commande.user.login, SUM(CASE WHEN c.commande.commandeTms IS NULL THEN 1 ELSE 0 END) AS count1 FROM Designation c GROUP BY c.commande.user.login";
Related
The T-SQL statement is below, essentially I want to return a boolean computed field xmlHasValue
SELECT TOP 10
hrd.pkID
, etc= "etc..."
, xmlHasValue = CASE WHEN hdr.someVeryLongXml IS NULL THEN 0 ELSE 1 END
FROM MyLeftTable hdr
inner JOIN MyRightTable lines ON hdr.pkID = lines.fkID
WHERE hdr.SomeField == 123
ORDER BY hdr.pkID DESC
How can I write this in EntityFramework (Full Fx, not dotnet-core), such that EF produces the Case statement as above?
My attempt:
var query = from hdr in dbCtx.MyLeftTable
join lines in dbCtx.MyRightTable on hdr.pkID equals lines.fkID
where hdr.SomeField == 123
orderby hdr.pkID descending
select new //select into anon C# obj
{
pkID = hdr.pkID,
etc = "etc...",
xmlHasValue = hdr.someVeryLongXml //<== ??? stuck here ???
};
var anonObjList = query.AsNoTracking()
.Take(10)
.ToList(); //exec qry on the SERVER, and fill the anon object.
Is it possible to do orderby expression using linq query expression based on dynamic string parameter? because the query i have is producing weird SQL query
my linq:
var product = from prod in _context.Products
join cat in _context.Categories on prod.CategoryId equals cat.CategoryId
join sup in _context.Suppliers on prod.SupplierId equals sup.SupplierId
orderby sortParam
select new ProductViewModel
{
ProductName = prod.ProductName,
ProductId = prod.ProductId,
QuantityPerUnit = prod.QuantityPerUnit,
ReorderLevel = prod.ReorderLevel,
UnitsOnOrder = prod.UnitsOnOrder,
UnitPrice = prod.UnitPrice,
UnitsInStock = prod.UnitsInStock,
Discontinued = prod.Discontinued,
Category = cat.CategoryName,
Supplier = sup.CompanyName,
CategoryId = cat.CategoryId,
SupplierId = sup.SupplierId
};
where var sortParam = "prod.ProductName"
The code above produces weird sql where order by sortParam is being converted to (SELECT 1). Full query catched by sql profiler below:
exec sp_executesql N'SELECT [prod].[ProductName], [prod].[ProductID], [prod].[QuantityPerUnit], [prod].[ReorderLevel], [prod].[UnitsOnOrder], [prod].[UnitPrice], [prod].[UnitsInStock], [prod].[Discontinued], [cat].[CategoryName] AS [Category], [sup].[CompanyName] AS [Supplier], [cat].[CategoryID], [sup].[SupplierID]
FROM [Products] AS [prod]
INNER JOIN [Categories] AS [cat] ON [prod].[CategoryID] = [cat].[CategoryID]
INNER JOIN [Suppliers] AS [sup] ON [prod].[SupplierID] = [sup].[SupplierID]
ORDER BY (SELECT 1)
OFFSET #__p_1 ROWS FETCH NEXT #__p_2 ROWS ONLY',N'#__p_1 int,#__p_2 int',#__p_1=0,#__p_2=10
I'm seeing a lot of people doing linq order by using dynamic parameter but all of them use lambda not query expression, please enlighten me
As was already mentioned, you are passing a string value instead of an expression that reflects the column name. There are options for what you want however, see for example here.
Given a result set which is in the EAV structure such as :
id | attributeName | stringValue | intValue | BooleanValue
---------------------------------------------------------------
1 stringFoo v1
1 stringFooList v2
1 stringFooList v3
1 intFoo 10
1 intFooList 10
1 intFooList 20
1 booleanFoo true
1 booleanFooList true
1 booleanFooList true
How can I select all the attributes and value pair as a single value in a JSON/JSONB format , which are something likes:
{
"stringFoo" : "v1" ,
"stringFooList" : ["v2","v3"] ,
"intFoo" : 10 ,
"intFooList" : [10,20],
"booleanFoo" : true,
"booleanFooList" : [true,true]
}
If there are multiple attribute value for an attribute such as stringFooList , it will format it as JSON array.
I am using PostgreSQL 9.6
You can do something like this:
select id, jsonb_object_agg(att, value)
from (
select id,
attributename as att,
case
when count(*) > 1 then
jsonb_agg(coalesce(stringvalue,intvalue::text,booleanvalue::text))
else
to_jsonb(min(coalesce(stringvalue,intvalue::text,booleanvalue::text)))
end as value
from eav
group by id, attributename
) t
group by id;
The inner select aggregates multiple values into an JSON array, single values into JSON scalar values. And the outer query then builds a single JSON value of all rows.
Online example: https://rextester.com/TLCRN79815
#a_horse_with_no_name 's answer gives me a good start. I extend his/her answer and come up the following query such that the elements in the JSON array have the same data type of what defined in PostgreSQL.
select id, jsonb_object_agg(att,
case
when strval is not null then strval
when intvalue is not null then intvalue
else boolVal
end
)
from (
select id,
attributename as att,
case when count(*) > 1 then
jsonb_agg(stringvalue) filter (where stringvalue is not null)
else
to_jsonb(min(stringvalue) filter (where stringvalue is not null))
end as strVal,
case when count(*) > 1 then
jsonb_agg(intvalue) filter (where intvalue is not null)
else
to_jsonb(min(intvalue) filter (where intvalue is not null))
end as intvalue,
case when count(*) > 1 then
jsonb_agg(booleanvalue) filter (where booleanvalue is not null)
else
to_jsonb(bool_and(booleanvalue) filter (where booleanvalue is not null))
end as boolVal
from eav
group by id, attributename
) t
group by id;
I have the following criteria query, which retrieves some fields from Anfrage and Sparte entities and also the translated string for the sparte.i18nKey.
This works as expected if I dont use orderBy.
Now I have the requirement to sort by the translated string for sparte.i18nKey and using the orderBy as shown below, results in QuerySyntaxException: unexpected AST node
So the problem must be the subselect in the orderBy clause!
select distinct new
my.domain.model.dto.AnfrageDTO(
anfrage0.id,
anfrage0.name,
anfrage0.sparte.id,
anfrage0.sparte.i18nKey,
-- retrieve translated string for sparte.i18nKey
(select rb0.value from at.luxbau.mis2.domain.model.ResourceBundleEntity as rb0
where (anfrage0.sparte.i18nKey = rb0.key) and (rb0.language = 'de'))
)
from my.domain.model.impl.Anfrage as anfrage0
left join anfrage0.sparte as sparte
order by (
-- sort by translated string for sparte.i18nKey
select rb1.value
from my.domain.model.ResourceBundleEntity as rb1
where (anfrage0.sparte.i18nKey = rb1.key) and (rb1.language = 'de')
) asc
My Java code looks like this:
private List<AnfrageDTO> getAnfragen() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<AnfrageDTO> query = cb.createQuery(AnfrageDTO.class);
Root<Anfrage> anfrage = query.from(Anfrage.class);
anfrage.join(Anfrage_.sparte, JoinType.LEFT);
query.select(cb.construct(AnfrageDTO.class,
anfrage.get(Anfrage_.id),
anfrage.get(Anfrage_.name),
anfrage.get(Anfrage_.sparte).get(Sparte_.id),
anfrage.get(Anfrage_.sparte).get(Sparte_.i18nKey),
// create subquery for translated sparte.i18nKey
createResourceBundleSubQuery(cb, query, anfrage.get(Anfrage_.sparte).get(Sparte_.i18nKey)).getSelection()));
TypedQuery<AnfrageDTO> tq = entityManager
.createQuery(query)
// use subquery to sort by translated sparte.i18nKey
.orderBy(cb.asc(createResourceBundleSubQuery(cb, query, anfrage.get(Anfrage_.sparte).get(Sparte_.i18nKey))));
tq.setMaxResults(10);
List<AnfrageDTO> anfragen = tq.getResultList();
return anfragen;
}
public Subquery<String> createResourceBundleSubQuery(CriteriaBuilder cb, CriteriaQuery<?> query, <String> expr) {
Subquery<String> subquery = query.subquery(String.class);
Root<ResourceBundleEntity> rb = subquery.from(ResourceBundleEntity.class);
subquery
.select(rb.get(ResourceBundleEntity_.value))
.where(cb.and(
cb.equal(expr, rb.get(ResourceBundleEntity_.key)),
cb.equal(rb.get(ResourceBundleEntity_.language), "de")));
return subquery;
}
Using a native SQL query with subselect in orderBy works also as expected.
select distinct
anfrage0_.id,
anfrage0_.name,
anfrage0_.sparte_id,
sparte4_.i18n_key,
(select rb3.i18n_value from resource_bundle rb3 where rb3.language_code = 'de' and rb3.i18n_key = sparte4_.i18n_key) as sparte_i18n_value
from
mis2.anfrage anfrage0_
left outer join mis2.sparte sparte4_ on anfrage0_.sparte_id = sparte4_.id
order by (
select rb.i18n_value
from mis2.resource_bundle rb
where sparte4_.i18n_key = rb.i18n_key and rb.language_code = 'de'
) asc
Also using an alias in the native SQL query works also as expected.
select distinct
anfrage0_.id,
anfrage0_.name,
anfrage0_.sparte_id,
sparte4_.i18n_key,
(select rb3.i18n_value from resource_bundle rb3 where rb3.language_code = 'de' and rb3.i18n_key = sparte4_.i18n_key) as sparte_i18n_value
from
mis2.anfrage anfrage0_
left outer join mis2.sparte sparte4_ on anfrage0_.sparte_id = sparte4_.id
order by sparte_i18n_value
asc
It would be great if JPA Criteria API would support using an alias in orderBy clause!
Any hints welcome - Thank you!
My environment is WildFly 11 and PostgreSQL 9.6.
JPA doesn't support passing parameter in order by clause, your problem has been asked before: Hibernate Named Query Order By parameter
Table1 :
userid name address
1 venkat srinagr
2 venkatesh sainagar
Table2:
id userid lat lon
1 1 14.000 15.000
2 2 14.3526 15.3698
by passing "venkat" as parameter then need to pull all matching records and his userid,name,lat,lon.
in above table1 "venkat" contains in both rows then need to pull 2 records.how to get userid,name,lat,lon for all matching rows..
for sigle record i am able to get.but there are multiple rows how to get please tell me....
var result = from p in cxt.Table2
where p.Table1.Name.Contains(name)
select new
{
p.Users.User_Id,p.Users.Name,p.Latitude,p.Longitude
};
Im sure someone will say this is not the most effective way but this is how i would do it.
string InputString = "venkat";
var tab =(from a in db.tablea
from b in db.tableb
where a.userid == b.userid && a.name == InputString
select new
{
UserID = a.userid,
Username = a.name,
Latitude = b.lat,
Longditude = b.lon
}).FirstOrDefault();
FirstOrDefault() is only if you want to force only one output or null,
if you want a collection of some sort, then just remove it.