how to grab the max of common columns with partition in sql - sql-server

i have this Table Chips:
im looking to find the max for each ID but
the code im using is just not correct i need the new table to be
select *
from
(
max (numchips) over (partition by Id)
from #chips
)

You can use ROW_NUMBER:
SELECT Id, numchips
FROM (
SELECT Id, numchips,
ROW_NUMBER() OVER (PARTITION BY Id
ORDER BY numchips DESC) as rn
FROM #chips
) t
WHERE rn = 1
rn is equal to 1 for the record having the highest numchips value within each Id partition.
Using ROW_NUMBER() makes sense only if you have some additional columns in Chips table that you also want to retrieve.

Why can't you just do?:
SELECT
MAX(c.numchips),
c.Id
FROM
#chips as c
GROUP BY
c.Id

Related

Query table and Select latest 2 rows (in SQL Server)

I have a table that logs all updates made to an application. I want to query the table and return the last update by [Timestamp] and the update before that for a different value [ITEM]. I'm struggling to figure out how to get what i need. I'm returning more than one record for each ID and don't want that.
;WITH cte AS
(
SELECT
ID,
LAG(ITEM) OVER (PARTITION BY ID ORDER BY timestamp DESC) AS ITEM,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY timestamp DESC) RN
FROM
MyLoggingTable
WHERE
accountid = 1234
)
SELECT
cte.ID,
dl.ITEM,
DL.timestamp
FROM
cte
JOIN
MyLoggingTable DL ON cte.ID = DL.ID
WHERE
rn = 1
AND cte.ID IN ('id here | Sub select :( ..')
Is ID unique? Because if it is, your code shouldn't return duplicates. If it isn't, you will get duplicates because you are joining back to the MyLoggingTable which isn't needed. You should just move those columns (dl.Item & dl.timestamp) into the cte and return them from the cte like you did cte.ID.
I removed the LAG since you didn't return that column in your final query.
;WITH cte AS
(
SELECT
ID,
ITEM,
[timestamp],
--LAG(ITEM) OVER (PARTITION BY ID ORDER BY timestamp DESC) AS ITEM,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY timestamp DESC) RN
FROM
MyLoggingTable
WHERE
accountid = 1234
)
SELECT
cte.ID,
cte.ITEM,
cte.timestamp
FROM
cte
WHERE
rn = 1
AND cte.ID IN ('id here | Sub select :( ..')
Note, if you wanted the second to the last item, as you stated in your comments, make rn=2

SQL select the row with max value using row_number() or rank()

I have data of following kind:
RowId Name Value
1 s1 12
22 s1 3
13 s1 4
10 s2 14
22 s2 5
3 s2 100
I want to have the following output:
RowId Name Value
1 s1 12
3 s2 100
I am currently using temp tables to get this in two step. I have been trying to use row_number() and rank() functions but have not been successful.
Can someone please help me with syntax as I feel row_number() and rank() will make it cleaner?
Edit:
I changed the rowId to make it a general case
Edit:
I am open to ideas better than row_number() and rank() if there are any.
If you use rank() you can get multiple results when a name has more than 1 row with the same max value. If that is what you are wanting, then switch row_number() to rank() in the following examples.
For the highest value per name (top 1 per group), using row_number()
select sub.RowId, sub.Name, sub.Value
from (
select *
, rn = row_number() over (
partition by Name
order by Value desc
)
from t
) as sub
where sub.rn = 1
I can not say that there are any 'better' alternatives, but there are alternatives. Performance may vary.
cross apply version:
select distinct
x.RowId
, t.Name
, x.Value
from t
cross apply (
select top 1
*
from t as i
where i.Name = t.Name
order by i.Value desc
) as x;
top with ties using row_number() version:
select top 1 with ties
*
from t
order by
row_number() over (
partition by Name
order by Value desc
)
This inner join version has the same issue as using rank() instead of row_number() in that you can get multiple results for the same name if a name has more than one row with the same max value.
inner join version:
select t.*
from t
inner join (
select MaxValue = max(value), Name
from t
group by Name
) as m
on t.Name = m.Name
and t.Value = m.MaxValue;
If you really want to use ROW_NUMBER() you can do it this way:
With Cte As
(
Select *,
Row_Number() Over (Partition By Name Order By Value Desc) RN
From YourTable
)
Select RowId, Name, Value
From Cte
Where RN = 1;
Unless I'm missing something... Why use row_number() or rank?
select rowid, name, max(value) as value
from table
group by rowid, name

Latest Customer Donation And Amount

I have two tables:
Customer which has an Id column representing the customer Id.
CustomerDonation that contains CustomerId (FK), Amount and DatePayed
I'd like have all the customers together with their latest donation and the amount of that donation.
I am receiving duplicate values on my query so I will not paste it here.
You could also use the WITH TIES option
Select Top 1 With Ties *
From YourTable
Order By Row_Number() over (Partition By CustomerId Order By DatePayed Desc)
WITH
SortedDonation AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY DatePayed DESC) AS SeqID,
*
FROM
CustomerDonation
)
SELECT
*
FROM
Customer
LEFT JOIN
SortedDonation
ON SortedDonation.CustomerId = Customer.Id
AND SortedDonation.SeqId = 1
If the same customer can make multiple donations with the same DatePayed, then this will arbitrarily pick just one of them.
If you add additional fields to the ORDER BY you can deterministically pick which one you want.
Or, if you want all of them use DENSE_RANK() instead of ROW_NUMBER()
Use Row_Number() Analytic function .
Select * from (
Select customerId,Amount,DatePayed, row_number() over (partition by CustomerId order by DatePayed desc) as rowN)
as tab where rowN = 1
You only need the CustomerDonation table for this. You can join with the Customer table if you want other information of the customer.
WITH cte AS (
SELECT
CustomerId
, MAX(DatePayed) AS LastDate
FROM
CustomerDonation
)
SELECT
cd.CustomerId
, cd.Amount
, cd.DatePayed
FROM
CustomerDonation cd
JOIN cte ON cd.CustomerId = cte.CustomerId
AND cd.DatePayed = cte.LastDate

sql server - selecting top x rows by group

I have a problem that I've wasted way too much time playing with. It can be simplified to something like:
Platform: SQL Server
you have a table with age and zipcode
list the top 5 oldest people in each zipcode
I can see how to do it with cursors, but is there a way with top and group by to achieve this?
All inputs appreciated!
SELECT *
FROM (
SELECT *
,ROW_NUMBER() OVER (PARTITION BY zipcode ORDER BY Age DESC) rn
FROM TableName
)A
WHERE RN <= 5
You need to use ROW_NUMBER analytic function
SELECT *
FROM
( SELECT name,
age,
zipcode,
ROW_NUMBER() OVER
( PARTITION by zipcode
order by age desc)
as seq
) T
Where T.seq <=5

T-SQL: Get top n records by column

Struggling with what's probably a very simple problem. I have a query like this:
;WITH rankedData
AS ( -- a big, complex subquery)
SELECT UserId,
AttributeId,
ItemId
FROM rankedData
WHERE rank = 1
ORDER BY datEventDate DESC
The sub-query is designed to grab a big chunk of interlined data and rank it by itemId and date, so that the rank=1 in the above query ensures we only get unique ItemIds, ordered by date. The partition is:
Rank() OVER (partition BY ItemId ORDER BY datEventDate DESC) AS rk
The problem is that what I want is the top 75 records for each UserID, ordered by date. Seeing as I've already got a rank inside my sub-query to sort out item duplicates by date, I can't see a straightforward way of doing this.
Cheers,
Matt
I think your query should look like
SELECT t.UserId, t.AttributeId, t.ItemId
FROM (
SELECT UserId, AttributeId, ItemId, rowid = ROW_NUMBER() OVER (
PARTITION BY UserId ORDER BY datEventDate
)
FROM rankedData
) t
WHERE t.rowid <= 75

Resources