Sql Server - top 1 post per member ordered by createdDate - sql

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

Related

Sql group by max column value after CTE

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.

Select most recent status for each ID and department code

I have the following table:
I want to get the most recent status for each dept_code that a CL_ID has. So the desired output would be this:
I have tried the following but this give me just the most recent status for each client and not each of their dept_codes.
SELECT *
FROM [CIMSHR6_MERGED].[dbo].[C3CLSTAT] C
INNER JOIN
(SELECT CLIENT_NUMBER, MAX(STATUS_DATE) AS SDATE
FROM [CIMSHR6_MERGED].[dbo].[C3CLSTAT]
GROUP BY CLIENT_NUMBER) X
ON X.CLIENT_NUMBER = C.CLIENT_NUMBER
AND X.SDATE = C.STATUS_DATE
ORDER BY C.CLIENT_NUMBER
Any help would be much appreciated. Thanks.
A convenient method that works in SQL Server is:
select top (1) cl.*
from [CIMSHR6_MERGED].[dbo].[C3CLSTAT] cl
order by row_number() over (partition by cl_id, dept_code order by status_date desc);
A method that is efficient with the right indexes in almost any database is:
select cl.*
from [CIMSHR6_MERGED].[dbo].[C3CLSTAT] cl
where cl.status_date = (select max(cl2.status_date)
from [CIMSHR6_MERGED].[dbo].[C3CLSTAT] cl2
where cl2.cl_id = cl.cl_id and cl2.dept_code = cl.dept_code
);
The right index is on (cl_id, dept_code, status_date).
I would also use ROW_NUMBER, but with a subquery:
SELECT CL_ID, Status_date, Status, Dept_code
FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CL_ID, Dept_code ORDER BY Status_date DESC) rn
FROM CIMSHR6_MERGED].[dbo].[C3CLSTAT]
) t
WHERE rn = 1;
1) Firstly group everything on Dept_Code,CL_ID and assign rank for each row with in the group in descending order.
2) Select all the rows with rnk=1 which would display your desired result.
SELECT Z.CL_ID,
Z.Status_Date,
Z.Status,
Z.Dept_Code
FROM
(
SELECT *,
RANK() OVER( PARTITION BY Dept_Code,CL_ID, ORDER BY Status_Date DESC ) AS rnk
FROM [CIMSHR6_MERGED].[dbo].[C3CLSTAT]
) Z
WHERE Z.rnk = 1;
This would work for almost all databases
select * from c3clstat c
where exists
(select 1 from c3clstat c1
where c1.cl_id=c.cl_id
and c1.dept_code=c.dept_code
group by cl_id,dept_code
having c.status_date=max(c1.status_date)
)

Max count by customer and category

I have transactional data that looks like this
Account ProductCategory
1 a
1 a
1 b
2 c
2 d
2 d
I need to find the ProductCategory that appears most per customer. Results:
Account ProductCategory
1 a
2 d
My result was a long with many nested subqueries. Any good ideas?
Thank you in advance for the help.
Most databases support the ANSI-standard window functions, particularly row_number(). You can use this with aggregation to get what you want:
select Account, ProductCategory
from (select Account, ProductCategory, count(*) as cnt,
row_number() over (partition by Account order by count(*) desc) as seqnum
from table t
group by Account, ProductCategory
) apc
where seqnum = 1;
This can be done using analytic SQL , or just using count over group. The syntax depends on the RDBMS, as asked by Michael .
you can try following SQL :
select * from
(select account, ProductCategory, ct , ROW_NUMBER() OVER (partition by account, ProductCategory ORDER BY ct DESC ) As myRank
from (select account, ProductCategory, count(0) as ct
from <table>
group by account, ProductCategory ) t ) t2
where t2.myRank = 1
Code:
WITH A AS (SELECT [Account], ProductCategory, COUNT([ProductCategory]) OVER(PARTITION BY ProductCategory) AS [Count]
FROM tbl_all)
SELECT A.Account, ProductCategory
FROM A INNER JOIN (SELECT Account, MAX([Count]) AS Count FROM A GROUP BY A.Account) AS B ON A.Account=B.Account AND A.Count=B.Count
GROUP BY A.Account, ProductCategory

Group by clause with min

I am having the following table
I used following query and i got error message. I can identify why the error is but how can i solve it
select min(id),customer_id,created_at from thunderbolt_orders
group by customer_id
I need the minimum id's customer_id and created_at how can i achieve it.
select distinct on (customer_id)
customer_id, id, created_at
from thunderbolt_orders
order by customer_id, id
with cte as (
select
*, row_number() over(partition by customer_id order by id) as row_num
from Table1
)
select *
from cte
where row_num = 1
SELECT id,customer_id,created_at
FROM thunderbolt_orders
WHERE id IN
(SELECT MIN(id) FROM thunderbolt_orders GROUP BY customer_id);
Depending on whether or not you just want the minimum ID or whether you want the minimum ID for each customer these are the solutions.
Minimum ID:
select top 1 id,customer_id,created_at from thunderbolt_orders order by id asc
Minimum ID for each customer:
with cte as (
select min(id) as id
from thunderbolt_orders
group by customer_id
)
select *
from cte c
inner join thunderbolt_orders t on t.id = c.id

How to get the max row number per group/partition in SQL Server?

I'm using SQL Server 2005. I have a payments table with payment id's, user id's, and timestamps. I want to find the most recent payment for each user. This is easy to search and find an answer for. What I also want to know though is if the most recent payment is the user's first payment or not.
I have the following which will number each user's payments:
SELECT
p.payment_id,
p.user_id,
ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date) AS paymentNumber
FROM
payment p
I'm not making the mental leap which then lets me then pick the highest paymentNumber per user. If I use the above as a subselect by using MAX(paymentNumber) and then grouping by user_id, I lose the payment_id which I need. But if I also add the payment_id into the group by clause, I'm back to one row per payment. I'm sure I'm overlooking the obvious. Any help?
Try this:
SELECT a.*, CASE WHEN totalPayments>1 THEN 'NO' ELSE 'YES' END IsFirstPayment
FROM(
SELECT p.payment_id,
p.user_id,
ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date DESC) AS paymentNumber,
SUM(1) OVER (PARTITION BY p.user_id) AS totalPayments
FROM payment p
) a
WHERE paymentNumber = 1
Do the same thing again.
SELECT
p.payment_id,
p.user_id,
ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date) AS paymentNumber,
ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date DESC) AS reversePaymentNumber,
FROM
payment p
Now the most recent payment has reversePaymentNumber 1, and the number of payments will be paymentNumber.
The query provided by OP does most of the work. All we need to do is change the ORDER BY clause provided to ROW_NUMBER() to descending at which point the most recent record will have a value of 1. I'm choosing to use a CTE as a matter of personal preference - a subquery would also be fine.
with cte as (
SELECT
p.payment_id,
p.user_id,
ROW_NUMBER() OVER (
PARTITION BY p.user_id
ORDER BY p.payment_date desc
) AS paymentNumber
FROM
payment p
)
select * from cte where paymentNumber = 1
a less cool way i suppose
; with maxp as
(
select
p.user_id,
max(p.payment_date) as MaxPaymentDate
from payment p
group by p.userid
),
nump as
(
select
p.payment_id,
p.user_id,
p.payment_date,
ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.payment_date) AS paymentNumber
FROM payment p
),
a as
(
select
nump.payment_id,
nump.user_id,
nump.paymentNumber
case when maxp.MaxPaymentDate is null then 'Old' else 'New' end as NewState
from nump
left outer join maxp
on nump.user_id=maxp.user_id
and nump.payment_date=maxp.MaxPaymentDate
)
select
*
from a
where NewState='New'
SELECT * FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY OS.ContactId ORDER BY OS.Date ASC) AS FirstRow#,
ROW_NUMBER() OVER(PARTITION BY OS.ContactId ORDER BY OS.Date DESC) AS LastRow#,
OS.Contactid,CONVERT(VARCHAR,OS.Date,106) 'Purchase Month',
OS.ProductId 'MyCII Subscription/Directory', OS.Charges 'Amount(INR)',OS.Date 'RAWDate'
FROM tblOnlineServices OS
WHERE Date IS NOT NULL AND Contactid IN('C000013112','C000010859')
) FirstPurchase
WHERE FirstRow# = 1 OR LastRow# = 1
ORDER BY Contactid, RAWDate
How about this?
SELECT
p.user_id,
MAX(p.payment_date) as lastPayment,
CASE COUNT(p.payment_id) WHEN 1 THEN 1 ELSE 0 END as isFirstPayment
FROM
payment p
GROUP BY
p.user_id