JPQL query - order by count - sql

I need to implement a named query, that returns a list of events sorted by number of friends who go to the event.
For example, this query return a list of events sorted by number of all people who go to event:
SELECT r.event
FROM RSVP AS r
JOIN r.event.rsvpList rr
WHERE r.profile.user.uuid = :userUuid
AND r.rsvpStatus = RSVPStatus.ATTENDING
GROUP BY r.event
ORDER BY COUNT(rr) DESC
Or other example, list of friends events:
SELECT r.event
FROM RSVP AS r
WHERE r.profile IN
( SELECT f.profileTo
FROM Friend f
WHERE f.profileFrom.user.uuid = :userUuid
)
AND r.rsvpStatus = :rsvpStatus
GROUP BY r.event
I tried to do the following:
SELECT r.event
FROM RSVP AS r
JOIN r.event.rsvpList rr
WHERE r.profile.user.uuid = :userUuid
AND r.rsvpStatus = RSVPStatus.ATTENDING
AND rr.profile IN
(
SELECT f.profileTo
FROM Friend f
WHERE f.profileFrom.user.uuid = :userUuid
)
GROUP BY r.event
ORDER BY COUNT(rr) DESC
But this query returned the events that go on friends and skip other events.
This is a simplified diagram of my DB:

You didn't post your entities so i could not try, but i think this should work:
SELECT r.event, (
SELECT count(*)
FROM RSVP rr
WHERE rr.event = r.event
AND rr.profile IN
(
SELECT f.profileTo
FROM Friend f
WHERE f.profileFrom.user.uuid = :userUuid
)
) count
FROM RSVP AS r
WHERE r.profile.user.uuid = :userUuid
AND r.rsvpStatus = RSVPStatus.ATTENDING
ORDER BY 2 DESC
The thing here is HQL does not support subqueries in the ORDER BY clause, so you have to select one more column just for ordering.

Related

How To use Where instead of Group by?

I wrote a query , that gives me this Output :
(This is Just a sample obviously the Output Table contains 300000 rows approximatly)
And This is my Query :
proc sql;
create Table Output as
select ID_User, Division_ID, sum(conta) as Tot_Items, max(Counts) as Max_Item
from (select c.ID_User , c.Div_ID as Division_ID, ro.code as Mat, count(*) as Counts
from Ods.R_Ordini o
inner join DMC.Cust_Dupl c
on User_ID = ID_User
inner join ods.R_Nlines ro
on ro.Orders_Id = o.Id_Orders AND RO.SERVICE = 0
inner join ods.R_Mat m
on ro.Mat_Id = Id_Mat and flag = 0
group by
ID_User,
C.Division_ID,
Ro.Code
Having Counts > 1
)
group by
Id_User,
Division_ID
Order by
Tot_Item DESC
;
quit;
So , What i want is to re-write this Query , but instead of the Group by i want to use the Where Condition , (WHERE=(DIVISION_ID=3)) this is the condition.
I tried several attempts , with some i got errors , and with others i did got an output , but the output was not like the original one.
any help would be much appreciated , thank you.
The SAS data set option (where=(<where-expression>)) can only be coded adjacent to a data set name. So the option would have to be applied to the data set containing the column div_id that is the basis for computed column division_id. That would be table alias c
DMC.Cust_Dupl(where=(div_id=3)) as c
Or just use a normal SQL where clause
…
)
where division_id=3
group by …
Just use WHERE DIVISION_ID=3 before group by.
select ID_User, Division_ID, sum(conta) as Tot_Items, max(Counts) as Max_Item from (select c.ID_User , c.Div_ID as Division_ID, ro.code as Mat, count(*) as Counts from Ods.R_Ordini o inner join DMC.Cust_Dupl c on User_ID = ID_User inner join ods.R_Nlines ro on ro.Orders_Id = o.Id_Orders AND RO.SERVICE = 0 inner join ods.R_Mat m on ro.Mat_Id = Id_Mat and flag = 0 WHERE DIVISION_ID=3 group by ID_User, C.Division_ID, Ro.Code Having Counts > 1 ) group by Id_User, Division_ID Order by Tot_Item DESC

Appending field from sub-query

I have a rather complex query that orders the results based on a sub-query. This works fine. The query is below.
SELECT enrollments.*, users.*
FROM enrollments
INNER JOIN users
ON enrollments.user_id = users.id
WHERE enrollments.preview = FALSE
ORDER BY (
SELECT COUNT(progress_tracker)
FROM progress_tracker
WHERE progress_tracker.enrollment_id = enrollments.id
AND progress_tracker.completed = TRUE
)
Here I'm selecting the fields from the User and Enrollment table. I ideally want one more field in the sql results. This field represents the results from the ORDER BY sql:
SELECT COUNT(progress_tracker)
FROM progress_tracker
WHERE progress_tracker.enrollment_id = enrollments.id
AND progress_tracker.completed = TRUE
Is it possible to create a field from this query and append it to the results for each row? The name of the row would be appropriately termed as enrollment_progress_tracker_completed_count. If so, how can I do this?
Add the subquery to the select and then use it for ordering:
SELECT e.*, u.*,
(SELECT COUNT(*)
FROM progress_tracker pt
WHERE pt.enrollment_id = e.id AND pt.completed = TRUE
) as newcol
FROM enrollments e INNER JOIN
users u
ON e.user_id = u.id
WHERE e.preview = FALSE
ORDER BY newcol;
Use a temporary table
with tempCounts as(
SELECT enrollment_id, COUNT(progress_tracker) as countValue
FROM progress_tracker
WHERE progress_tracker.completed = TRUE
group by enrollment_id)
SELECT enrollments.*, users.*,tempCounts.countValue
FROM enrollments, users.*,tempCounts
INNER JOIN users
ON enrollments.user_id = users.id
WHERE enrollments.preview = FALSE
and enrollments.id = tempCounts.enrollment_id
ORDER BY tempCounts.countValue

How to remove data from table if the ID is in the column

I have to write the script that will pull IDs of all members that email has been hard bounced. In order to do it I wrote this
Select id FROM Members m
Join tbl_memberlanguageid mli on m.ID = mli.MLI_MemberID
Where Cast(dateCreated as date) >= '01-Dec-2014'
and mli.MLI_LanguageID = 3
and EmailHardBounces = 1
Then I need to use this list of IDs to remove them from the table Members. How can I write this script so that it removes everything related to ID from Members if the ID is in that list ?
You can just change the Select id to Delete m:
BEGIN TRAN
DELETE m
FROM Members m
JOIN tbl_memberlanguageid mli ON m.ID = mli.MLI_MemberID
WHERE CAST(dateCreated AS DATE) >= '01-Dec-2014'
AND mli.MLI_LanguageID = 3
AND EmailHardBounces = 1
ROLLBACK
COMMIT
Just confirm the record count is correct before committing the delete.
I like CTE's since they allow to see what i'm going to delete:
WITH MemberIdsToDelete AS
(
Select id FROM Members m
Join tbl_memberlanguageid mli on m.ID = mli.MLI_MemberID
Where Cast(dateCreated as date) >= '01-Dec-2014'
and mli.MLI_LanguageID = 3
and EmailHardBounces = 1
)
SELECT id FROM MemberIdsToDelete
If you finally want to delete them replace
SELECT id FROM MemberIdsToDelete
with
DELETE FROM Members WHERE id IN (SELECT id FROM MemberIdsToDelete).
Another way:
DELETE FROM Members WHERE ID IN(Select id FROM Members m
Join tbl_memberlanguageid mli on m.ID = mli.MLI_MemberID
Where Cast(dateCreated as date) >= '01-Dec-2014'
and mli.MLI_LanguageID = 3
and EmailHardBounces = 1)

How to rewrite long query?

I have the following 2 tables:
items:
id int primary key
bla text
events:
id_items int
num int
when timestamp without time zone
ble text
composite primary key: id_items, num
and want to select to each item the most recent event (the newest 'when').
I wrote an request, but I don't know if it could be written more efficiently.
Also on PostgreSQL there is a issue with comparing Timestamp objects:
2010-05-08T10:00:00.123 == 2010-05-08T10:00:00.321
so I select with 'MAX(num)'
Any thoughts how to make it better? Thanks.
SELECT i.*, ea.* FROM items AS i JOIN
( SELECT t.s AS t_s, t.c AS t_c, max(e.num) AS o FROM events AS e JOIN
( SELECT DISTINCT id_item AS s, MAX(when) AS c FROM events GROUP BY s ORDER BY c ) AS t
ON t.s = e.id_item AND e.when = t.c GROUP BY t.s, t.c ) AS tt
ON tt.t_s = i.id JOIN events AS ea ON ea.id_item = tt.t_s AND ea.cas = tt.t_c AND ea.num = tt.o;
EDIT: had bad data, sorry, my bad, however thanks for finding better SQL query
SELECT (i).*, (e).*
FROM (
SELECT i,
(
SELECT e
FROM events e
WHERE e.id_items = i.id
ORDER BY
when DESC
LIMIT 1
) e
FROM items i
) q
If you're using 8.4:
select * from (
select item.*, event.*,
row_number() over(partition by item.id order by event."when" desc) as row_number
from items item
join events event on event.id_items = item.id
) x where row_number = 1
For this kind of joins, I prefer the DISTINCT ON syntax (example).
It's a Postgresql extension (not SQL standard syntax), but it comes very handy:
SELECT DISTINCT ON (it.id)
it.*, ev.*
FROM items it, events ev
WHERE ev.id_items = it.id
ORDER by it.id, ev.when DESC;
You can't beat that, on terms of simplicity and readability.
That query assumes that every item has at least one event. If not, and if you want all
events, you'll need an outer join:
SELECT DISTINCT ON (it.id)
it.*, ev.*
FROM items it LEFT JOIN events ev
ON ev.id_items = it.id
ORDER BY it.id, ev.when DESC;
BTW: There is no "timestamp issue" in Postgresql, perhaps you should change the title.

Multiple MAX values select using inner join

I have query that work for me only when values in the StakeValue don't repeat.
Basically, I need to select maximum values from SI_STAKES table with their relations from two other tables grouped by internal type.
SELECT a.StakeValue, b.[StakeName], c.[ProviderName]
FROM SI_STAKES AS a
INNER JOIN SI_STAKESTYPES AS b ON a.[StakeTypeID] = b.[ID]
INNER JOIN SI_PROVIDERS AS c ON a.[ProviderID] = c.[ID] WHERE a.[EventID]=6
AND a.[StakeGroupTypeID]=1
AND a.StakeValue IN
(SELECT MAX(d.StakeValue) FROM SI_STAKES AS d
WHERE d.[EventID]=a.[EventID] AND d.[StakeGroupTypeID]=a.[StakeGroupTypeID]
GROUP BY d.[StakeTypeID])
ORDER BY b.[StakeName], a.[StakeValue] DESC
Results for example must be:
[ID] [MaxValue] [StakeTypeID] [ProviderName]
1 1,5 6 provider1
2 3,75 7 provider2
3 7,6 8 provider3
Thank you for your help
There are two problems to solve here.
1) Finding the max values per type. This will get the Max value per StakeType and make sure that we do the exercise only for the wanted events and group type.
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
2) Then we need to get only one return back for that value since it may be present more then once.
Using the Max Value, we must find a unique row for each I usually do this by getting the Max ID is has the added advantage of getting me the most recent entry.
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
3) Now that we have the ID's of the rows that we want, we can just get that information.
SELECT Stakes.ID, Stakes.StakeValue, SType.StakeName, SProv.ProviderName
FROM SI_STAKES AS Stakes
INNER JOIN SI_STAKESTYPES AS SType ON Stake.[StakeTypeID] = SType.[ID]
INNER JOIN SI_PROVIDERS AS SProv ON Stake.[ProviderID] = SProv.[ID]
WHERE Stake.ID IN (
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
)
You can use the over clause since you're using T-SQL (hopefully 2005+):
select distinct
a.stakevalue,
max(a.stakevalue) over (partition by a.staketypeid) as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
Essentially, this will find the max a.stakevalue for each a.staketypeid. Using a distinct will return one and only one row. Now, if you wanted to include the min a.id along with it, you could use row_number to accomplish this:
select
s.id,
s.maxvalue,
s.staketypeid,
s.providername
from (
select
row_number() over (order by a.stakevalue desc
partition by a.staketypeid) as rownum,
a.id,
a.stakevalue as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
) s
where
s.rownum = 1