Get each patients' highest bill - sql

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

Related

SUM most recent ID/Product combinations for the latest date

select * from
(select Id, Prodcut, Billing_date
, row_number() over (partition by Id, product order by Billing_date desc) as RowNumber
,sum(Revenue)
from Table1
group by 1,2,3,4,1) a
where a.rowNumber = 1
There are rows where Id+product combination repeats for latest billing date and which causing some data to be missed out. I am trying to add sum with row_number to sum all the ID&product combinations for the latest date but not able to make it work.
Can anyone please help me out here!
Data Sample Image
Database: Athena, Dbeaver
I would expect this to do what you want:
select *
from (select Id, Product, Billing_date,
row_number() over (partition by Id, product order by Billing_date desc) as seqnum,
sum(Revenue)
from Table1
group by Id, Product, Billing_date
) t1
where seqnum = 1;
Your group by columns do not seem correct. I'm surprised your query runs in any datbase.

Find the lowest score after the first Highest Score

I am looking for a SQL query.
Table 1: Source Table
Table 2: Result Table
Attached the patient table. Here I want to find the Highest Score, Highest Score Date, Lowest Score and Lowest Score Date of each patient. The tricky part is that if a patient has same highest score (here it is 9) on two different dates (10/5/2018 and 8/4/2020), we need to take earliest high score (10/5/2018). Similarly, if the patient has same lowest score (6 here) on two different dates (3/1/2019 and 4/2/2020) we should take the latest low score (4/2/2020)
Table 1: Source table contains all scores of a single patient. Patient ID is the primary key of that table. I want a result table that look like table 2.
I have tried this
SELECT distinct
pat.PAT_NAME 'Patient Name'
, pat.PAT_ID
, CAST(pat.CONTACT_DATE AS DATE) 'Service Date'
, pat.MEAS_VALUE 'Score'
, [Row Number] = rank() OVER (PARTITION BY pat.PAT_ID ORDER BY CAST(pat.MEAS_VALUE AS int) DESC, CONTACT_DATE asc)
FROM Patient pat
WHERE pat.PAT_ID = 'A112233'
But this code can show me highest or the lowest score. But it does not meet all my requirement.
If there is table t with columns: PatientName, PatientID, ServiceDate, Score. Something like this:
;with high_low_cte(PatientID, high_rn, low_rn) as(
select
PatientID,
row_number() over (partition by PatientID order by Score, ServiceDate asc),
row_number() over (partition by PatientID order by Score, ServiceDate desc)
from
t)
select * from high_low_cte where high_rn=1 and low_rn=1;
After update to question:
;with high_low_cte([Patient Name], PAT_ID, [Service Date], Score, high_rn, low_rn) as (
SELECT distinct
pat.PAT_NAME 'Patient Name'
,pat.PAT_ID
,CAST(pat.CONTACT_DATE AS DATE) 'Service Date'
,pat.MEAS_VALUE 'Score'
,high_rn=row_number() OVER (PARTITION BY pat.PAT_ID ORDER BY CAST(pat.MEAS_VALUE AS int) DESC, CONTACT_DATE asc)
,low_rn=row_number() OVER (PARTITION BY pat.PAT_ID ORDER BY CAST(pat.MEAS_VALUE AS int) asc, CONTACT_DATE asc)
FROM
Patient pat
WHERE
pat.PAT_ID='A112233')
select hld1.*, hld2.Score [Low_Score], hld2.[Service Date] [Low Service Date]
from high_low_cte hld1 join high_low_cte hld2 on hld1.PAT_ID=hld2.PAT_ID
where
hld1.high_rn=1
and hld2.low_rn=1;
You can use conditional aggregation with row_number():
select PatientName, PatientID,
min(case when ;
_hi = 1 then ServiceDate end) as high_date,
max(score) as high_score,
min(case when seqnum_lo = 1 then ServiceDate end) as low_date,
min(score) as low_score
from (select t.*
row_number() over (partition by PatientID order by Score desc, ServiceDate asc) as seqnum_hi,
row_number() over (partition by PatientID order by Score, ServiceDate desc) as seqnum_lo
from t
) t
group by PatientName, PatientID;
First, get highest and lowest score, then find on which date it's occurred
;with scores as ( -- get highest/lowest score per patientId
select patientID, max(score) hScore, min(score) lScore
from table
group by patientID
), dates as (
-- get first date a patient had the highest score
select patientID, min(ServiceDate) dateHScore, score
from table t
inner join scores s on s.patientid = t.patientid and s.hScore= t.score
group by patientID, score
union all
-- get the last date a patient had the lowest score
select patientID, max(ServiceDate) dateLScore, score
from table t
inner join scores s on s.patientid = t.patientid and s.lScore = t.score
group by patientID, score
)
select t.patientName, scores.*
from table t
inner join scores s on s.patientid= t.patientid
If you want highest/lowest score on separate columns on the same row, just split the second cte and join them appropriately in the select
I haven't tested, but maybe something like this could do the job:
select x.PatientName, x.PatientId,
case when x.HSD=1 then 'Highest' else 'Lowest' as ScoreType,
Score, ScoreDate
from (
select
p.PAT_NAME as PatientName,
p.PAT_ID as PatientId,
p.MEAS_VALUE as Score,
p.CONTACT_DATE as ScoreDate,
row_number() over (partition by p.PatientId order by p.MEAS_VALUE desc, p.CONTACT_DATE desc) as HSD,
row_number() over (partition by p.PatientId order by p.MEAS_VALUE asc, p.CONTACT_DATE asc) as LSD
from Patient p
) x
where
x.HighestScore=1 or
x.LowestScoreDate=1
You should receive two rows. You would need to pivot the data in order to get your expected output.

How to select multiple max values from a sql table

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

Sql select distinct row by a columns highest value

I am having an issue trying to select one row per city name. This is the following collection I am getting:
This is my query so far:
select pl.PlaceId,
pl.Name,
pop.NumberOfPeople,
pop.Year
from dbo.Places pl
inner join dbo.Populations pop
on pop.PlaceId = pl.PlaceId
where pop.NumberOfPeople >= 1000
and pop.NumberOfPeople <= 99999
I am trying to get it to where it only selects a city one time, but uses the most recent date. So in the above picture, I would only see Abbeville for 2016 and not 2015. I believe I need to do either a group by or do a sub query to flatten the results. If anybody has any advice on how I can handle this, it will be greatly appreciated.
Assuming you are using SQLSERVER,you can use Rownumber
;with cte
as
(select pl.PlaceId,
pl.Name,
pop.NumberOfPeople,
pop.Year,
row_number() over(partition by pl.Name order by year desc) as rownum
from dbo.Places pl
inner join dbo.Populations pop
on pop.PlaceId = pl.PlaceId
where pop.NumberOfPeople >= 1000
and pop.NumberOfPeople <= 99999
)
select * from cte where rownum=1
The following query serves the purpose.
CREATE TABLE #TEMP_TEST
(
PlaceId INT,
Name VARCHAR(50),
NumberOfPeople INT,
YEAR INT
)
INSERT INTO #TEMP_TEST
SELECT 1,'Abbeville',2603,2016
UNION
SELECT 5,'Alabester',32948,2016
UNION
SELECT 9,'Aubum',63118,2016
UNION
SELECT 1,'Abbeville',2402,2015
UNION
SELECT 5,'Alabester',67902,2017
SELECT PlaceId, Name, NumberOfPeople, YEAR FROM
(
SELECT ROW_NUMBER() OVER (PARTITION BY PlaceId ORDER BY YEAR DESC) RNO,
PlaceId, Name, NumberOfPeople, YEAR
FROM #TEMP_TEST
)T
WHERE RNO = 1
DROP TABLE #TEMP_TEST

how to get the distinct records based on maximum date?

I'm working with Sql server 2008.i have a table contains following columns,
Id,
Name,
Date
this table contains more than one record for same id.i want to get distinct id having maximum date.how can i write sql query for this?
Use the ROW_NUMBER() function and PARTITION BY clause. Something like this:
SELECT Id, Name, Date FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Date desc) AS ROWNUM
FROM [MyTable]
) x WHERE ROWNUM = 1
If you need only ID column and other columns are NOT required, then you don't need to go with ROW_NUMBER or MAX or anything else. You just do a Group By over ID column, because whatever the maximum date is you will get same ID.
SELECT ID FROM table GROUP BY ID
--OR
SELECT DISTINCT ID FROM table
If you need ID and Date columns with maximum date, then simply do a Group By on ID column and select the Max Date.
SELECT ID, Max(Date) AS Date
FROM table
GROUP BY ID
If you need all the columns but 1 line having Max. date then you can go with ROW_NUMBER or MAX as mentioned in other answers.
SELECT *
FROM table AS M
WHERE Exists(
SELECT 1
FROM table
WHERE ID = M.ID
HAVING M.Date = Max(Date)
)
One way, using ROW_NUMBER:
With CTE As
(
SELECT Id, Name, Date, Rn = Row_Number() Over (Partition By Id
Order By Date DESC)
FROM dbo.TableName
)
SELECT Id --, Name, Date
FROM CTE
WHERE Rn = 1
If multiple max-dates are possible and you want all you could use DENSE_RANK instead.
Here's an overview of sql-server's ranking function: http://technet.microsoft.com/en-us/library/ms189798.aspx
By the way, CTE is a common-table-expression which is similar to a named sub-query. I'm using it to be able to filter by the row_number. This approach allows to select all columns if you want.
select Max(Date) as "Max Date"
from table
group by Id
order by Id
Try with Max(Date) and GROUP BY the other two columns (the ones with repeating data)..
SELECT ID, Max(Date) as date, Name
FROM YourTable
GROUP BY ID, Name
You may try with this
DECLARE #T TABLE(ID INT, NAME VARCHAR(50),DATE DATETIME)
INSERT INTO #T VALUES(1,'A','2014-04-20'),(1,'A','2014-04-28')
,(2,'A2','2014-04-22'),(2,'A2','2014-04-24')
,(3,'A3','2014-04-20'),(3,'A3','2014-04-28')
,(4,'A4','2014-04-28'),(4,'A4','2014-04-28')
,(5,'A5','2014-04-28'),(5,'A5','2014-04-28')
SELECT T.ID FROM #T T
WHERE T.DATE=(SELECT MAX(A.DATE)
FROM #T A
WHERE A.ID=T.ID
GROUP BY A.ID )
GROUP BY T.ID
select id, max(date) from NameOfYourTable group by id;