I'd like to do a query than in sql it's:
SELECT users.id, SUM(total), SUM(total*price) FROM sales INNER JOIN users ON sales.id_user=users.id GROUP BY users.id
I tried searching for the solution, but the closest I get was:
QSales sales = QSales.sales;
JPAQuery query = from(sales);
QUsers users = QUsers.users;
query.innerJoin(sales.users, users);
List<Object[]> response = query.groupBy(sales.user).list(sales.user, sales.total.sum());
but i don't know how to get this:
SUM(total*price)
SUM(total*price)
can be expressed as
total.multiply(price).sum()
you can use NumberExpression
NumberExpression totalPrice = sales.total.multiply(sales.price);
then use totalPrice.sum()
Related
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.
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
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
I am using moodle2.4.6. I want a list of user with their groups and their courses.
You will need to do an SQL query to get this information.
Assuming you are using the default 'mdl_' prefix for tables, you will need to join together the following tables:
mdl_user - the details of the users
mdl_user_enrolments - (user_enrolments.userid = user.id) which course enrolments the user
has
mdl_enrol - (enrol.id = user_enrolments.enrolid) details of which
enrolment instances these are
mdl_course - (course.id = enrol.courseid) details of the courses these users are enroled in
mdl_groups_members - (groups_members.userid = user.id) details of the
groups these users are in
mdl_groups - (groups.id =
groups_members.groupid AND groups.courseid = course.id) name and
description of the groups the user is in (for each course)
Please comment if you need help turning that pseudo code into actual SQL, or if you need help with the Moodle database access API ( http://docs.moodle.org/dev/Data_manipulation_API )
SELECT
mdl_user.username,
mdl_user.firstname,
mdl_user.lastname,
mdl_course.fullname,
mdl_course.idnumber,
mdl_groups_members.groupid,
mdl_groups.name
FROM (mdl_groups_members
INNER JOIN ((mdl_course
INNER JOIN (mdl_user_enrolments
INNER JOIN mdl_enrol ON mdl_user_enrolments.enrolid = mdl_enrol.id)
ON mdl_course.id = mdl_enrol.courseid) INNER JOIN mdl_user ON mdl_user_enrolments.userid = mdl_user.id)
ON mdl_groups_members.userid = mdl_user.id) INNER JOIN mdl_groups
ON (mdl_groups.courseid = mdl_course.id) AND (mdl_groups_members.groupid = mdl_groups.id)
WHERE (((mdl_user.username) = "102993") AND ((mdl_course.category) = "36"))
I have an UPDATE query in SQL Server Management Studio 2012 that is not giving me the expected results. I believe it is because I had to add the IJDATE field to the SELECT and GROUP BY and therefore it is not summing correctly. I am trying to update the current month/year for each vendor. Is there a better way to write this UPDATE query?
UPDATE S
SET S.PurchaseDlr = I.PurchaseDlr
FROM (SELECT
IJVEND,
IJDATE,
SUM(IJQTY * IJCOST) AS PurchaseDlr
FROM
dbo.S2K_IJ
WHERE
IJTYPE IN ('I','ID')
GROUP BY
IJVEND,
IJDATE) I
INNER JOIN PurchaseDollars S on I.IJVEND = S.Vendor AND S.MonthNum = MONTH(I.IJDATE) AND S.Year = YEAR(I.IJDATE)
You are grouping by date, but it looks like you want to group by month and year:
UPDATE S
SET S.PurchaseDlr = I.PurchaseDlr
FROM (SELECT
IJVEND,
MONTH(IJDATE) AS Month,
YEAR(IJDATE) AS Year,
SUM(IJQTY * IJCOST) AS PurchaseDlr
FROM
dbo.S2K_IJ
WHERE
IJTYPE IN ('I','ID')
GROUP BY
IJVEND,
MONTH(IJDATE),
YEAR(IJDATE)) I
INNER JOIN PurchaseDollars S
ON I.IJVEND = S.Vendor
AND S.MonthNum = I.Month
AND S.Year = I.Year