Sql group by max column value after CTE - sql

I have this query:
WITH messages_ranked
AS (
SELECT p.Date, p.RecipientId, p.RecipientType, p.Id, p.text, p.userId,
ROW_NUMBER() OVER(PARTITION BY p.RecipientId, p.userId
ORDER BY p.Id DESC)
AS rk
FROM ChatMessages p
JOIN ChatGroupMemberships as g
ON p.recipientId = g.groupId
WHERE g.userId = XXX <-- user id
)
SELECT date, recipientId as groupId, recipientType as groupType, id, text, userId, rk
FROM messages_ranked s
where rk = 1
Order BY s.date DESC
Which yields me this:
What I'd need is to reduce result rows of this query so that for every unique groupId only the row with highest value of date would be returned.
So for example from the first three rows only the first would be returned, as they share the same groupId and the first row has the newest date.
I tried to follow example here How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL? as my question is closely related but I can't seem to do it right.

I am guessing that this does what you want:
WITH messages_ranked AS (
SELECT p.Date, p.RecipientId, p.RecipientType, p.Id, p.text, p.userId,
ROW_NUMBER() OVER (PARTITION BY p.RecipientId ORDER BY p.dATE DESC) AS seqnum
FROM ChatMessages p JOIN
ChatGroupMemberships as g
ON p.recipientId = g.groupId
WHERE g.userId = XXX <-- user id
)
SELECT date, recipientId as groupId, recipientType as groupType, id, text,
userId, seqnum
FROM messages_ranked s
WHERE seqnum = 1
ORDER BY s.date DESC ;
I don't think you need to use row_number() twice.

Related

How to get last date on max count transaction_id by branch in sql

I would like to get last date on max count txn_id base on branch_name.
This is the data
I want the result like this
here is my script. but I get only one row.
select max(date),
account,
branch_name,
province,
district
from
(select date,
account,
branch_name,
province,
district,
RANK() OVER (ODER BY txn_no desc) rnk
from
(select count(tr.txn_id) txn_no,
tr.date,
u.account,
b.branch_name,
b.province,
b.district
from transaction tr
inner join users u
on u.user_id = tr.user_id
inner join branch b
on b.user_id = u.user_id
where 1=1
and tr.date >= to_date('01/04/2021','dd/mm/yyyy') and tr.date < to_date('30/04/2021','dd/mm/yyyy')
group by tr.date,
u.account,
b.branch_name,
b.province,
b.district
))
where rnk = 1
group by tr.date,
u.account,
b.branch_name,
b.province,
b.district
WITH
cte1 AS ( SELECT *, COUNT(*) OVER (PARTITION user, branch) cnt
FROM source_table ),
cte2 AS ( SELECT *, RANK() OVER (PARTITION BY user ORDER BY cnt DESC) rnk
FROM cte1 )
SELECT *
FROM cte2
WHERE rnk = 1
If more than one branch have the same amount of rows then all of them will be returned. If only one of them must be returned in this case then according additional criteria must be used and ORDER BY expression clause in cte2 must be accordingly expanded. If any (random) must be returned in this case then RANK() in cte2 must be replaced with ROW_NUMBER().
I would do it with SELECT TOP 1 ... instead of RANK(), something like:
SELECT date,
txn_id,
account,
branch_name,
province,
district
FROM transaction t
WHERE branch_name = (
SELECT TOP 1 branch_name
FROM (
SELECT branch_name, count(*) as cnt
FROM transaction
WHERE account = t.account
GROUP BY branch_name
ORDER BY 2 DESC
) s
AND date = (
SELECT TOP 1 date
FROM (
SELECT date, count(*) as cnt
FROM transaction
WHERE account = t.account
AND branch_name = (
SELECT TOP 1 branch_name
FROM (
SELECT branch_name, count(*) as cnt
FROM transaction
WHERE account = t.account
GROUP BY branch_name
ORDER BY 2 DESC
) s2
GROUP BY branch_name
ORDER BY 2 DESC
) s2
)
If there are multiple transactions on the last date, they all are going to be returned though.
You want the most recent transaction from the account/branch with the most transactions. If so, you can do this as:
select t.*
from (select t.*,
max(cnt) over (partition by account) as max_cnt
from (select t.*,
count(*) over (partition by account, branch_name) as cnt,
row_number() over (partition by account, branch_name order by date desc) as seqnum
from t
) t
) t
where max_cnt = cnt and seqnum = 1;
Note: If there are multiple branches that have the same count, then they are all returned. Your question does not specify how to deal with such duplicates.

SQL select row with max value or distinct value and sum all

I have the following data that is returned to me. I need to get a distinct or max sum of all the commission by taxid for a single repnbr. The 'qtrlycommrep' column is the value I'm trying to get to, but not able to. For repnbr c590, I need to get the 854.66 commission amount, which is the max for each taxid.
What am I doing wrong?
Any help would be much appreciated!
Here's what I've tried so far. Using the Row_number
select distinct
sub.Repnbr
, (sub.QtrLYComm) as qtrlycommrep
from (
select distinct repnbr, QtrLYComm
, rn = row_number() over(partition by repnbr order by QtrLYComm desc)
from #qtrly
) sub
where sub.rn = 1
Cross Apply
select distinct
#qtrly.repnbr
, x.QtrLYComm as qtrlycommrep
from #qtrly
cross apply (
select top 1
*
from #qtrly as i
where i.repnbr = Repnbr
order by i.qtrlycomm desc
) as x;
inner join
select
#qtrly.repnbr, #qtrly.qtrlycomm as qtrlycommrep
from #qtrly
inner join (
select maxvalue = max(qtrlycomm), repnbr
from #qtrly
group by repnbr
) as m
on #qtrly.repnbr = m.repnbr
and #qtrly.qtrlycomm = m.maxvalue;
order by row_number
select top 1 with ties
#qtrly.repnbr, #qtrly.qtrlycomm as qtrlycommrep
from #qtrly
order by
row_number() over(partition by repnbr
order by qtrlycomm desc)
You want one value per tax id. You need to include that. For instance:
select q.Repnbr, sum(q.QtrLYComm) as qtrlycommrep
from (select q.*,
row_number() over(partition by repnbr, taxid order by QtrLYComm desc) as seqnum
from #qtrly q
) q
where seqnum = 1
group by q.Repnbr;
However, I would be inclined to use two levels of aggregation:
select q.Repnbr, sum(q.QtrLYComm) as qtrlycommrep
from (select distinct repnbr, taxid, QtrLYComm
from #qtrly q
) q
group by q.Repnbr;

Get highest value from every group

I have table:
Id, Name, Account, Date, ItemsToSend
I want to group rows by Name and Account
From each group I want to get elements with latest Date
And display element's Name, Account and ItemsToSend
I managed something like this:
select
Name,
Account,
max(Date),
max(CountItemsSend)
from History
where
Date = (
select max(Date)
from History as p
where
p.Account = History.Account
and p.Name = History.Name
)
group by
Name,
Account
I am afraid of max(Date), max(CountItemsSend). I dont think it is ok. After where there is only 1 result for each group, so what is the point of max use there?
A CTE can make this neater.
WITH maxDates as
(
SELECT Name, Account, MAX(Date) as LatestDate
FROM History
GROUP BY Name, Account
)
SELECT h.Name, h.Account, h.Date, h.CountItemsSend
FROM History h
INNER JOIN maxDates m
on m.Name = h.Name and m.Account = h.Account and m.LatestDate = h.Date
Another possible approach is to use ROW_NUMBER() to number rows grouped by name and account and ordered by date descending and then select the rows with number equal to 1. These rows are with max Date per group and CountItemsSend from the same row.
SELECT
t.[Name],
t.[Account],
t.[Date],
t.[CountItemsSend]
FROM (
SELECT
[Name],
[Account],
[Date],
[CountItemsSend],
ROW_NUMBER() OVER (PARTITION BY [Name], [Acount] ORDER BY [Date] DESC) AS Rn
FROM History
) t
WHERE t.Rn = 1
You don't need aggregation. Just:
select h.*
from History h
where h.Date = (select max(h2.Date)
from History h2
where h2.Account = h.Account and
h2.Name = h.Name
);

SQL Return MAX Values from Multiple Rows

I have tried many solutions and nothing seems to work. I am trying to return the MAX status date for a project. If that project has multiple items on the same date, then I need to return the MAX ID. So far I have tried this:
SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE
From Project_Status
JOIN
(SELECT MAX(PRJSTAT_PRJA_ID) as MaxID, MAX(PRJSTAT_DATE) as MaxDate
FROM Project_Status
Group by PRJSTAT_PRJA_ID)
On
PRJSTAT_PRJA_ID = MaxID and PRJSTAT_DATE = MaxDate
Order by PRJSTAT_PRJA_ID
It returns the following:
I am getting multiple records for PRJSTAT_PRJA_ID, but I only want to return the row with the MAX PRJSTAT_ID. Any thoughts?
Take out the MAX on the ID on the subquery:
SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE
From Project_Status
JOIN
(SELECT PRJSTAT_PRJA_ID as ID, MAX(PRJSTAT_DATE) as MaxDate
FROM Project_Status
Group by PRJSTAT_PRJA_ID)
On
PRJSTAT_PRJA_ID = ID and PRJSTAT_DATE = MaxDate
Order by PRJSTAT_PRJA_ID
Or remove the need to join:
SELECT * FROM
(SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE,
ROW_NUMBER() OVER (PARTITION BY PRJSTAT_PRJA_ID ORDER BY PRJSTAT_DATE DESC)
AS SEQ,
ROW_NUMBER() OVER (PARTITION BY PRJSTAT_PRJA_ID ORDER BY PRJSTAT_PRJA_ID
DESC) AS IDSEQ
From Project_Status
)PR
WHERE SEQ = 1
AND IDSEQ = 1
Your problem is ties. You want the record with the maximum date per PRJSTAT_PRJA_ID and in case of a tie the record with the highest ID. The easiest way to rank records per group and only keep the best record is ROW_NUMBER:
select prjstat_id, prjstat_prja_id, prjstat_status, prjstat_date
from
(
select
project_status.*,
row_number() over (partition by prjstat_prja_id
order by prjstat_date desc, prjstat_id desc) as rn
from project_status
)
where rn = 1
order by prjstat_prja_id;

Sql Server - top 1 post per member ordered by createdDate

I have a table Posts which has a memberID and createdDate.
I need to return the most recent post per member and the posts must be order with most recent at the top.
I am not sure how to do this with Sql Server, can anyone help?
WITH PostsRanked AS (
SELECT
memberID, postTitle, createdDate,
RANK() OVER (
PARTITION BY memberID
ORDER BY createdDate DESC
) AS rk
FROM Posts
)
SELECT
memberID, postTitle, createdDate
FROM PostsRanked
WHERE rk = 1
ORDER BY createdDate DESC
select p.*
from post p
join (select memberId,
max(createdDate) as maxd
from post
group by memberId) as p2 on p.member_id=p2.member_id
and p.createdDate=p2.maxd
order by p.createdDate desc
Here is the working query
select p.*
from post p join
(
select memberId, max(createdDate) as maxd
from post
group by memberId
) as p2 on p.memberid = p2.memberid and p.createdDate=p2.maxd
order by p.createdDate desc