I have 2 tables:
CATEGORY (id)
POSTING (id, categoryId)
I am trying to write an HQL or SQL query to find top 10 Categories which have the most number of Postings.
Help is appreciated.
SQL query:
SELECT c.Id, sub.POSTINGCOUNT
FROM CATEGORY c where c.Id IN
(
SELECT TOP 10 p.categoryId
FROM POSTING p
GROUP BY p.categoryId
order by count(1) desc
)
HQL:
Session.CreateQuery("select c.Id
FROM CATEGORY c where c.Id IN
(
SELECT p.categoryId
FROM POSTING p
GROUP BY p.categoryId
order by count(1) desc
)").SetMaxResults(10).List();
http://sqlinthewild.co.za/index.php/2010/01/12/in-vs-inner-join/
In SQL you can do this:
SELECT c.Id, sub.POSTINGCOUNT
FROM CATEGORY c
INNER JOIN
(
SELECT p.categoryId, COUNT(id) AS 'POSTINGCOUNT'
FROM POSTING p
GROUP BY p.categoryId
) sub ON c.Id = sub.categoryId
ORDER BY POSTINGCOUNT DESC
LIMIT 10
SQL can be like :
SELECT c.* from CATEGORY c, (SELECT count(id) as postings_count,categoryId
FROM POSTING
GROUP BY categoryId ORDER BY postings_count
LIMIT 10) d where c.id=d.categoryId
This output can be mapped to the Category entity.
I know that is an old question, but i reached a satisfatory answer.
JPQL:
//the join clause is necessary, because you cannot use p.category in group by clause directly
#NamedQuery(name="Category.topN",
query="select c, count(p.id) as uses
from Posting p
join p.category c
group by c order by uses desc ")
Java:
List<Object[]> list = getEntityManager().createNamedQuery("Category.topN", Object[].class)
.setMaxResults(10)
.getResultList();
//here we must made a conversion, because the JPA cannot order using a non select field (used stream API, but you can do it in old way)
List<Category> cats = list.stream().map(oa -> (Category) oa[0]).collect(Collectors.toList());
Related
I am trying to make a query to fetch the newest car for each user:
select * from users
left join
(select cars.* from cars
where cars.userid=users.userid
order by cars.year desc limit 1) as cars
on cars.userid=users.userid
It looks like it says Unknown column "users.userid" in where clause
I tried to remove cars.userid=users.userid part, but then it only fetches 1 newest car, and sticks it on to each user.
Is there any way to accomplish what I'm after? thanks!!
For this purpose, I usually use row_number():
select *
from users u left join
(select c.* , row_number() over (partition by c.userid order by c.year desc) as seqnum
from cars c
) c
on c.userid = u.userid and c.seqnum = 1;
One option is to filter the left join with a subquery:
select * -- better enumerate the columns here
from users u
left join cars c
on c.userid = u.userid
and c.year = (select max(c1.year) from cars c1 where c1.userid = c.userid)
For performance, consider an index on car(userid, year).
Note that this might return multiple cars per user if you have duplicate (userid, year) in cars. It would be better to have a real date rather than just the year.
Maybe there are better and more efficient way to query this. Here is my solution;
select users.userid, cars.*
from users
left join cars on cars.userid = users.userid
join (SELECT userid, MAX(year) AS maxDate
FROM cars
GROUP BY userid) as sub on cars.year = sub.maxDate;
I have three tables: Post, Community, and Community Moderator. I created an SQL query to show the communities a user moderates, including date created, and date updated. Date updated is calculated according to the MAX created date of a post in that community.
Here is the code that works for communities that have posts:
SELECT c.id, c.title, c.created, p.created as 'postdate'
FROM Post p, Community c, CommunityMod cm
WHERE p.created in
(
SELECT MAX(created)
FROM Post
GROUP BY community
)
AND cm.moderator=$id AND p.community=c.id AND cm.community=c.id
ORDER by c.created DESC
The problem is that this query will not select communities without any posts since there is no data in p.community.
I would like it to also show the communities without any posts, but instead of p.created for the updated information, it would show nothing or the date the community was created (c.created) instead.
How would I do that?
You need to use a LEFT JOIN for the Post table. Note that all conditions on columns from the Post table should be placed into the ON clause.
SELECT ...
FROM Community c
JOIN CommunityMod cm ON cm.community = c.id
LEFT JOIN Post p
ON p.community = c.id
AND p.created in
(
SELECT MAX(created)
FROM Post
GROUP BY community
)
WHERE cm.moderator = $id
ORDER by c.created DESC
Note that your subquery might not work as expected, ff Post.created is not UNIQUE. You should change it to a correlated subquery:
SELECT ...
FROM Community c
JOIN CommunityMod cm ON cm.community = c.id
LEFT JOIN Post p
ON p.community = c.id
AND p.created in
(
SELECT MAX(p1.created)
FROM Post p1
WHERE p1.community = c.id
)
WHERE cm.moderator = $id
ORDER by c.created DESC
However - If you only need the created value from the Post table, then you don't need a subquery at all.
SELECT c.id, c.title, c.created, MAX(p.created) as 'postdate'
FROM Community c
JOIN CommunityMod cm ON cm.community = c.id
LEFT JOIN Post p ON p.community = c.id
WHERE cm.moderator = $id
GROUP BY c.id
ORDER by c.created DESC
Basically, I have a coppermine gallery and I want to show the last 4 updated albums on the homepage. Here's the query that I've got so far. It basically gets the latest pictures. The subquery works fine on it's own but when it comes time to grouping them to get each album on its own, it doesn't seem to be getting the most recent one from the list.
SELECT *
FROM (
SELECT c.cid, c.name AS catname, a.aid, a.title AS albumtitle, a.category, p.aid AS albumid,p.filepath,p.filename,p.ctime AS creationtime,p.title AS pictitle,p.approved
FROM cpg145_pictures AS p LEFT JOIN `cpg145_albums` AS a ON p.aid = a.aid LEFT JOIN `cpg145_categories` AS c ON a.category = c.cid
WHERE p.approved='YES' AND a.category IN (47,48)
ORDER BY p.ctime DESC) AS T
GROUP BY albumid
ORDER BY creationtime DESC
LIMIT 4
I figured out the answer. Apparently, in MariaDB you have to give the subquery a limit for it to be sorted correctly. So:
SELECT *
FROM (
SELECT c.cid, c.name AS catname, a.aid, a.title AS albumtitle, a.category, p.aid AS albumid,p.filepath,p.filename,p.ctime AS creationtime,p.title AS pictitle,p.approved
FROM cpg145_pictures AS p LEFT JOIN `cpg145_albums` AS a ON p.aid = a.aid LEFT JOIN `cpg145_categories` AS c ON a.category = c.cid
WHERE p.approved='YES' AND a.category IN (47,48)
ORDER BY p.ctime DESC
LIMIT 200) AS T
GROUP BY albumid
ORDER BY creationtime DESC
LIMIT 4
I have one table of client details identified by an ID that looks like this:
ID (the clientcode), Name, Details
I would like to reference the ID from another table with sales information and pick up the name of the client in the query.
My original query string that picked up just the ID (clientcode) is this:
SELECT clientcode, SUM(sales) FROM inventory WHERE manufacturer='1'
GROUP BY client code ORDER BY SUM(sales) DESC
I would like to also pick up the Name of the client referenced by clientcode.
I tried a few LEFT JOINs but couldn't get the queries working.
SELECT i.clientcode
, c.name
, SUM(i.sales)
FROM inventory i
LEFT
JOIN clientdetails c
ON c.id = i.clientcode
WHERE i.manufacturer='1'
GROUP BY i.clientcode, c.name
ORDER BY SUM(i.sales) DESC
This should do it
SELECT c.ID, c.name, SUM(i.sales)
FROM inventory i
JOIN clients c ON c.ID = i.clientcode
WHERE i.manufacturer='1'
GROUP BY c.ID, ORDER BY SUM(i.sales) DESC
A simple query to achieve this is:
SELECT i.clientcode, d.name, SUM(i.sales) FROM inventory i, details d
WHERE i.manufacturer='1'
AND d.clientcode = i.clientcode
GROUP BY i.clientcode ORDER BY SUM(i.sales) DESC
Here, try thisone out.
SELECT inventory.clientcode,
SUM(inventory.sales),
clientdetails.Name
FROM inventory
INNER JOIN clientdetails
ON inventory.clientcode = clientdetails.clientcode
WHERE inventory.manufacturer='1'
GROUP BY inventory.clientcode, clientdetails.Name
ORDER BY SUM(inventory.sales) DESC
SELECT a.clientcode,
SUM(a.sales),
b.Name
FROM inventory a
INNER JOIN clientdetails b
ON a.clientcode = b.clientcode
WHERE a.manufacturer='1'
GROUP BY a.clientcode, b.Name
ORDER BY SUM(a.sales) DESC
SELECT
(SELECT date FROM forums WHERE topic_id=f.id OR id=f.id ORDER BY id DESC LIMIT 1) as last_reply,
f.*, p.id as pid, p.name FROM forums f
INNER JOIN players p ON p.id = f.author
WHERE f.topic_id=0 ORDER BY f.id DESC
In the subquery, I'd like to return not only the date field, but also the author field as well. how can I do this?
looked at a similar post but can't apply it to mine.
I would do it something like this:
SELECT
(SELECT date FROM forums WHERE topic_id=f.id OR id=f.id ORDER BY id DESC LIMIT 1) as last_reply,
(SELECT author FROM forums WHERE topic_id=f.id OR id=f.id ORDER BY id DESC LIMIT 1) as last_author,
f.*, p.id as pid, p.name FROM forums f
INNER JOIN players p ON p.id = f.author
WHERE f.topic_id=0 ORDER BY f.id DESC
I would actually repeat the subquery again
Maybe something like this can help you :
SELECT MAX(f.date), f.author
FROM forums f
INNER JOIN players p ON
p.id = f.author
WHERE f.tpoic_id = 0
GROUP BY f.author
ORDER BY f.id DESC
But it's difficult with no structure of tables.
Good luck.