How to select multiple max values from a sql table - sql

I am trying to get the top performers from a table, grouped by the company but can't seem to get the grouping right.
I have tried to use subqueries but this goes beyond my knowledge
I am trying to make a query that selects the rows in green. In other words I want to include the name, the company, and what they paid but only the top performers of each company.
Here is the raw data
create table test (person varchar(50),company varchar(50),paid numeric);
insert into
test
values
('bob','a',200),
('jane','a',100),
('mark','a',350),
('susan','b',650),
('thabo','b',100),
('thembi','b',210),
('lucas','b',110),
('oscar','c',10),
('janet','c',20),
('nancy','c',30)

You can use MAX() in a subquery as
CREATE TABLE T(
Person VARCHAR(45),
Company CHAR(1),
Paid INT
);
INSERT INTO T
VALUES ('Person1', 'A', 10),
('Person2', 'A', 20),
('Person3', 'B', 10);
SELECT T.*
FROM T INNER JOIN
(
SELECT Company, MAX(Paid) Paid
FROM T
GROUP BY Company
) TT ON T.Company = TT.Company AND T.Paid = TT.Paid;
Demo
Or using a window function as
SELECT Person,
Company,
Paid
FROM
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY Company ORDER BY Paid DESC) RN
FROM T
) TT
WHERE RN = 1;
Demo

Here's your query.
select a.person, a.company, a.paid from tableA a
inner join
(select person, company, row_number() over (partition by company order by paid desc) as rn from tableA) as t1
on t1.person = a.person and t1.company = a.company
where t1.rn = 1

Maybe something like
WITH ranked AS (SELECT person, company, paid
, rank() OVER (PARTITION BY company ORDER BY paid DESC) AS rnk
FROM yourtable)
SELECT person, company, paid
FROM ranked
WHERE rnk = 1
ORDER BY company;

You can use rank() function with partition by clause.
DENSE_RANK gives you the ranking within your ordered partition, but the ranks are consecutive. No ranks are skipped if there are ranks with multiple items.
WITH cte AS (
SELECT person, company, paid
rank() OVER (PARTITION BY company ORDER BY paid desc) rn
FROM yourtable
)
SELECT
*
FROM cte

Related

How to retrieve the most frequent value of a column for a specific ID in a table

I'm trying to fetch the most frequent value from a SQLite 3 database table for each specific ID (which is the ID of a company). I have tried with GROUP BY and ORDER BY as well as with COUNT() function.
SELECT company_id, max(car)
FROM car_orders
GROUP by company_id
ORDER by max(car)
For a specific company_id (9) I am expecting 'Audi' to be in result but this is not the case as its 'Volkswagen' (which is wrong)
Similar to your attempts, consider joining two aggregates that calculates COUNT per car and company and MAX of same counter per company. Below uses CTE introduced in SQLite in version 3.8.3, released in February 2014.
WITH cnt AS (
SELECT company_id, car, COUNT(*) AS car_count
FROM car_orders
GROUP by company_id, car
),
max_cnt AS (
SELECT cnt.company_id, MAX(cnt.car_count) as max_count
FROM cnt
GROUP BY cnt.company_id
)
SELECT cnt.company_id, cnt.car
FROM cnt
INNER JOIN max_cnt
ON cnt.company_id = max_cnt.company_id
AND cnt.car_count = max_cnt.max_count
In the more recent versions of SQLite, you can use window functions:
SELECT cc.*
FROM (SELECT company_id, car, COUNT(*) as cnt,
ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY COUNT(*) DESC) as seqnum
FROM car_orders
GROUP by company_id, car
) cc
WHERE seqnum = 1;
In earlier versions, it is a little more complicated:
WITH cc as (
SELECT company_id, car, COUNT(*) as cnt
FROM car_orders
GROUP by company_id, car
)
SELECT cc.*
FROM cc
WHERE cc.cnt = (SELECT MAX(cc2.cnt)
FROM cc cc2
WHERE cc2.company_id = cc.company_id
);

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
);

Sum column but for each row

How to do like
and I want to have result like
and what I already try is like this
select no, student, sum(point) from student group by no, student
But the result is not like what I expected.
You appear to want a "running sum" e.g.
select
no
, student
, sum(point) over(partition by student order by no) run_sum
from student
and it seems that the extra point might a subtraction of the 2nd last running sum from the final like this.
WITH cte
AS (
SELECT
no
, student
, SUM(point) OVER (PARTITION BY student ORDER BY no) run_sum
, ROW_NUMBER() OVER (PARTITION BY student ORDER BY no DESC) rn
FROM student)
SELECT
t.*
, coalesce(t.rum_sum,0) - coalesce(ex.run_sum,0) AS extra_point
FROM cte t
LEFT JOIN (
SELECT
*
FROM cte
WHERE rn = 2) ex ON t.student = ex.student
AND t.rn = 1
AND ex.rn = 2
;
but without more guidance on the required logic for extra_point that is just a guess.

Selecting City from Customer ID in SQL

Customer have ordered from different cities. Thus we have multiple cities against same customer_id. I want to display that city against customer id which has occurred maximum number of times , in case where customer has ordered same number of orders from multiple cities that city should be selected from where he has placed last order. I have tried something like
SELECT customer_id,delivery_city,COUNT(DISTINCT delivery_city)
FROM analytics.f_order
GROUP BY customer_id,delivery_city
HAVING COUNT(DISTINCT delivery_city) > 1
WITH cte as (
SELECT customer_id,
delivery_city,
COUNT(delivery_city) as city_count,
MAX(order_date) as last_order
FROM analytics.f_order
GROUP BY customer_id, delivery_city
), ranking as (
SELECT *, row_number() over (partition by customer_id
order by city_count DESC, last_order DESC) as rn
FROM cte
)
SELECT *
FROM ranking
WHERE rn = 1
select customer_id,
delivery_city,
amount
from
(
select t.*,
rank() over (partition by customer_id order by amount asc) as rank
from(
SELECT customer_id,
delivery_city,
COUNT(DISTINCT delivery_city) as amount
FROM analytics.f_order
GROUP BY customer_id,delivery_city
) t
)
where rank = 1

Get each patients' highest bill

I have a table where an ID can be associated with more than one bill. What I need to do is find the MAX billing amount, the ID and the date of their highest (MAX) bill. The problem is that there can be thousands of billsper person, and hundreds on any given date.
My query
select patientID, max(amountPaid) as maxPaid
from myTable
group by patientID
gives me what I need, minus the date. My attempt at fixing this is
select t.patientID, t.maxPaid, myTable.billDate
from myTable
inner join
(
select patientid, max(amountPaid) as maxPaid
from myTable
group by patientID
) as t on t.patientID=myTable.patientID and =t.maxPaid=myTable.maxPaid
The error given is invalid column name maxPaid. I tried not giving the calculated field an alias but SQL Server wouldn't accept myTable.max(amountPaid) either. What's the quickest way to fix this? thanks in advance.
The problem with your current approach is that if a patient has two bills with the maximum amount, you will get both of them.
Try this instead:
SELECT
patientid,
amountPaid AS max_paid,
billDate
FROM
(
SELECT
patientid,
amountPaid,
billDate,
ROW_NUMBER() OVER (PARTITION BY patientid
ORDER BY amountpaid DESC) AS RowNumber
FROM myTable
) T1
WHERE T1.RowNumber = 1
This will always return one row per patient even if a patient has two bills that both have the same maximum amountpaid.
;WITH x AS (SELECT PatientID, BillDate, AmountPaid,
rn = ROW_NUMBER() OVER (PARTITION BY PatientID ORDER BY AmountPaid DESC)
FROM dbo.myTable
)
SELECT PatientID, BillDate, AmountPaid
FROM x
WHERE rn = 1;
Based on you description, I think you meant this:
select t1.patientID, t2.maxPaid, t1.billDate
from myTable t1
inner join
(
select patientid, max(amountPaid) as maxPaid
from myTable
group by patientID
) t2
on t1.patientID=t2.patientID
and t1.amountPaid=t2.maxPaid