Retrieving the latest record for each unique entry in another column - unique

This seems so simple but for the life of me cannot figure this out. I have a table EERate with 3 columns and data similar to this.
EmployeeNo RateAmt RaiseDate
C100 | 10.00 | 1/1/2013
C100 | 11.00 | 6/1/2013
C100 | 10.50 | 8/1/2013
C200 | 15.00 | 6/1/2013
C200 | 16.00 | 8/1/2013
I need a select statement that will return the latest data for each employee.
Select EmployeeNo, Max(RaiseDate), RateAmt from EErates group by employeeNo
fails because rateamt is not an aggregate function.
Select EmployeeNo, Max(RaiseDate), max(RateAmt) from EErates group by employeeNo
retrieves the wrong data.
Any ideas?

SELECT EmployeeNo, RateAmt, RaiseDate FROM EErates o
WHERE RateAmt = (SELECT TOP 1 RateAmt FROM EErates i1 WHERE i1.EmployeeNo = o.EmployeeNo ORDER BY RaiseDate DESC)
AND RaiseDate = (SELECT TOP 1 RaiseDate FROM EErates i2 WHERE i2.EmployeeNo = o.EmployeeNo ORDER BY RaiseDate DESC)

Related

join table with recent rows only

I know there are questions on the same topic, but I couldn't get it right.
I am following this link, and tried this query:
SELECT * FROM food_list f
INNER JOIN (
SELECT MAX(updated_on) max_row, rate, item_id
FROM food_rate
GROUP BY rate, item_id
) f_max ON (f_max.item_id = f.id)
INNER JOIN food_rate fr ON (fr.updated_on = f_max.max_row);
But I am not getting the records right.
Here's my table:
food_list:
id | item
----------------
1 | pizza
2 | burger
3 | sandwich
food_rate:
id | item_id | rate | updated_on
----------------------------------------------
1 | 1 | 80 | 2018-06-01
2 | 2 | 90 | 2018-06-01
3 | 3 | 70 | 2018-06-01
4 | 1 | 60 | 2018-06-02
I want to receive the records with latest date from food_rate for each item in food_list.
Here's the expected output:
item_id | rate | updated_on
----------------------------------
1 | 60 | 2018-06-02
2 | 90 | 2018-06-01
3 | 70 | 2018-06-01
You can get the latest rows using a correlated subquery:
select fr.*
from food_rate fr
where fr.updated_on = (select max(fr2.updated_on)
from food_rate fr2
where fr2.item_id = fr.item_id
);
You can add the join for the filtering:
select fr.*
from food_list fl join
food_rate fr
on fr.item_id = fl.id
where fr.updated_on = (select max(fr2.updated_on)
from food_rate fr2
where fr2.item_id = fr.item_id
);
You can use your aggregation method, but it is likely to be less efficient (given appropriate indexes) because the join on food_list presumably reduces the number of rows. You are missing a condition in the on clause:
INNER JOIN
food_rate fr
ON fr.updated_on = f_max.max_row AND fr.item_id = f_max.item_id;
You only want to get data from the food_rate table, so there is no need to join anything. Select from food_rate where updated_on is the maximum updated_on for the item_id:
select item_id, rate, updated_on
from food_rate
where (item_id, updated_on) in
(
select item_id, max(updated_on)
from food_rate
group by item_id
);
As of MySQL 8.0 you can also use a window function for this, thus reading the table only once:
select item_id, rate, updated_on
from
(
select
item_id, rate, updated_on,
max(updated_on) over (partition by item_id) as max_updated_on
from food_rate
) rates
where updated_on = max_updated_on;

How to Select First Date, Previous Date, Latest Date where first date is higher than a reference date

I want to SELECT the Latest Date, the Second Latest Date and the First Date FROM a table1 where the First Date is higher than a reference Date found in another table2. And that reference Date should also be the latest from that table2. I have a solution, supposed to be. But the problem is, the solutions will not return an output if there is ONLY 1 record from table1. Example of the tables:
table1
Reg ID | DateOfAI | byTechnician
2GP001 | 2015-01-13 | 31
2GP001 | 2015-02-18 | 31
2GP001 | 2017-11-10 | 45
2GP001 | 2017-11-30 | 32
2GP044 | 2017-11-30 | 28
2GP001 | 2017-12-23 | 32
table2
Reg ID | DateOfCalving | DryOffDate
2GP001 | 2016-01-14 |
2GP070 | 2016-01-14 |
2GP065 | 2017-04-08 |
2GP001 | 2017-04-12 |
my expected output would be:
Reg ID | LatestDateOfCalving | 1stDateOfAI | PreviousAIDate | LastestAIDate
2GP001 | 2017-04-12 | 2017-11-10 | 2017-11-30 | 2017-12-23
I have searched everywhere from the moon and back... still no luck. these are the queries that i have used
the Fisrt:
SELECT b.actualDam,COUNT(x.actualDam) AS ilanba, max(b.breedDate) AS huli, max(x.breedDate) AS nex,MIN(x.breedDate) AS una,IFNULL(c.calvingDate,NULL) AS nganak,r.*,h.herdID,a.animalID,a.regID, IFNULL(a.dateOfBirth,NULL) AS buho
FROM x_animal_breeding_rec b
LEFT JOIN x_animal_calving_rec c ON b.recID=c.brecID
LEFT JOIN x_herd_animal_rel r ON b.actualDam=r.animal
LEFT JOIN x_herd h ON r.herd=h.herdID
LEFT JOIN x_animal_main_info a ON b.actualDam=a.animalID
JOIN x_animal_breeding_rec x ON b.actualDam = x.actualDam AND x.breedDate < b.breedDate
WHERE h.herdID = ? AND x.mateType = ? AND x.recFlag = ? GROUP BY b.actualDam
and the Second one that I've tried is this code:
SELECT b.recID
, b.actualDam
, b.breedDate
, min(b.breedDate) AS una
, max(b.breedDate) AS huli
, COUNT(b.actualDam) AS sundot
, b.mateType
, b.recFlag
, a.animalID
, a.regID
, h.*
FROM
( SELECT c.recID, c.actualDam
, c.breedDate
, c.mateType
, c.recFlag
, CASE WHEN #prev=c.recID THEN #i:=#i+1 ELSE #i:=1 END i
, #prev:=c.recID prev
FROM x_animal_breeding_rec c
, ( SELECT #prev:=null,#i:=0 ) vars
ORDER BY c.recID,c.breedDate DESC
) b
LEFT JOIN x_animal_main_info a ON b.actualDam=a.animalID
LEFT JOIN x_herd_animal_rel h ON b.actualDam=h.animal
WHERE i <= 2 GROUP BY b.actualDam HAVING h.herd = ? AND b.mateType = ? AND b.recFlag = ? ORDER BY b.breedDate DESC
Another problem here is the first solution returns a WRONG COUNT. the second solution returns a CORRECT COUNT, however, wrong Dates were returned. I hope you could give me an idea. Thanx in Advance.
The following query answers your question:
SELECT
RegID,
LatestDateOfCalving,
MIN(DateOfAI) AS 1stDateOfAI,
REPLACE(SUBSTRING_INDEX(GROUP_CONCAT(DateOfAI ORDER BY DateOfAI DESC), ',', 2), CONCAT(MAX(DateOfAI), ','), '') AS PreviousAIDate,
MAX(DateOfAI) AS LatestAIDate
FROM (
SELECT
t1.RegID,
LatestDateOfCalving,
DateOfAI,
IF(DateOfAI >= LatestDateOfCalving, 1, 0) AS dates
FROM table1 AS t1
INNER JOIN (
SELECT
RegID,
MAX(DateOfCalving) AS LatestDateOfCalving
FROM table2 GROUP BY RegID
) AS tt2 ON t1.RegID = tt2.RegID) AS x
WHERE dates = 1
GROUP BY RegID
HAVING COUNT(dates) >= 3;
Output:
+--------+---------------------+-------------+----------------+--------------+
| RegID | LatestDateOfCalving | 1stDateOfAI | PreviousAIDate | LatestAIDate |
+--------+---------------------+-------------+----------------+--------------+
| 2GP001 | 2017-04-12 | 2017-11-10 | 2017-11-30 | 2017-12-23 |
+--------+---------------------+-------------+----------------+--------------+
DEMO
In a subquery we select RegID and LatestDateOfCalving from table2 in order to have a reference date. Then join it to table1 and flag the record whether DateOfAI is greater or equal to LatestDateOfCalving (IF(DateOfAI >= LatestDateOfCalving, 1, 0)). We use this subquery in the outer query (SELECT RegID, LatestDateOfCalving, MIN(DateOfAI) AS 1stDateOfAI, MAX(DateOfAI) AS LatestAIDate, ...) and select only those records where the DateOfAI are at or after LatestDateOfCalving (WHERE dates = 1, where 1 is the flag where the condition was true) and have at least 3 records (HAVING COUNT(dates) >= 3). In the outer query I use the REPLACE(SUBSTRING_INDEX(GROUP_CONCAT(...))) structure in order to extract the previousAIDate from a comma (,) separated list of dates.

Join a table on itself

I have a table ValuationHistory with the following columns
Code | ValuationDate | NetAssetValue | PricePerShare | Subscriptions | Redemptions
ABC | 2014-06-30 | 12546.50 | 100.23 | 60 | 70
CEF | 2014-06-30 | 10025.20 | 120.50 | 30 | 20
ABC | 2014-07-31 | 12505.50 | 101.50 | 40 | 60
ABC | 2014-08-31 | 13051.41 | 102.50 | 35 | 70
Now the user will select a Valuation date and a code from an aspx page. I want to write an sql query that will give me a report with the following columns for all the valuation dates prior to the valuation date selected by the user
Code | BeginningEquity | Subscriptions | Redemptions | EndingEquity
Where
Code is the code selected by the user
BeginningEquity is the NetAssetValue for the previous valuation
Subscriptions is straight forward
Redemptions is straight forward
EndingEquity is the NetAssetValue on the valuationDate
I first created a table variable called #ValDates and got all the valuation dates into this temp table. Then I did a join of #ValDates with the ValuationHistory table.
But I am getting an error on the following query. The error message is:
subquery returned more than one value
Could somebody help me write this query in a better way
SELECT (SELECT NetAssetValue
FROM ValuationHistory
WHERE ValuationDate IN (SELECT Max(ValuationDate)
FROM ValuationHistory
WHERE ValuationDate < nd.ValuationDate)),
Subscriptions,
Redemptions,
EndingEquity
FROM ValuationHistory vh
INNER JOIN #ValDates vd
ON vh.ValuationDate = vd.ValuationDate
WHERE vh.Code = #Code
AND vh.ValuationDate < = #ValuationDate
I'm not very clear about your requirement. Based on the description, you may try to start your query as below
DECLARE #Code VARCHAR(10) = 'ABC'
,#ValuationDate date = '2014-07-31'
;WITH cte AS (
SELECT
rn = ROW_NUMBER() OVER (PARTITION BY Code ORDER BY ValuationDate), *
FROM ValuationHistory
)
SELECT
c1.Code,
c2.NetAssetValue AS BeginningEquity,
c2.ValuationDate AS BeginningDate,
c1.NetAssetValue AS EndingEquity,
c1.ValuationDate AS EndingDate,
c1.[Subscriptions],
c1.[Redemptions]
from cte c1
LEFT JOIN cte c2
ON c1.Code = c2.Code
AND c2.rn = c1.rn - 1
WHERE c1.Code = #Code
AND c1.ValuationDate < = #ValuationDate
SQL Fiddle Demo

Mysql to select rows group by with order by another column

I am trying to select the rows from a table by 'group by' and ignoring the first row got by sorting the data by date. The sorting should be done by a date field, to ignore the newest entry and returning the old ones for the group.
The table looks like
+----+------------+-------------+-----------+
| id | updated on | group_name | list_name |
+----+------------+----------------+--------+
| 1 | 2013-04-03 | g1 | l1 |
| 2 | 2013-03-21 | g2 | l1 |
| 3 | 2013-02-26 | g2 | l1 |
| 4 | 2013-02-21 | g1 | l1 |
| 5 | 2013-02-20 | g1 | l1 |
| 6 | 2013-01-09 | g2 | l2 |
| 7 | 2013-01-10 | g2 | l2 |
| 8 | 2012-12-11 | g1 | l1 |
+----+------------+-------------+-----------+
http://www.sqlfiddle.com/#!2/cec99/1
So, basically, I just want to return ids (3,4,5,6,8) as those are the oldest in the group_name and list_name. Ignoring the latest entry and returning the old ones by grouping it based on group_name and list_name
I am not able to write sql for this problem. I know order by will not work with group by. Please help me in figuring out a solution.
Thanks
And also, is there a way to do this without using subqueries?
Something like the following to get only the rows that are the minimum date for a specific row:
select a.ID, a.updated_on, a.group_name, list_name
from data a
where
a.updated_on <
(
select max(updated_on)
from data
group by group_name having group_name = a.group_name
);
SQL Fiddle: http://www.sqlfiddle.com/#!2/00d43/10
Update (based on your reqs)
select a.ID, a.updated_on, a.group_name, list_name
from data a
where
a.updated_on <
(
select max(updated_on)
from data
group by group_name, list_name having group_name = a.group_name
and list_name = a.list_name
);
See: http://www.sqlfiddle.com/#!2/cec99/3
Update (To not use Correlated Subquery but Simple subquery)
Decided correlated subquery is too slow based on: Subqueries vs joins
So I changed to joining with a aliased temporary table based on nested query.
select a.ID, a.updated_on, a.group_name, a.list_name
from data a,
(
select group_name, list_name , max(updated_on) as MAX_DATE
from data
group by group_name, list_name
) as MAXDATE
where
a.list_name = MAXDATE.list_name AND
a.group_name = MAXDATE.group_name AND
a.updated_on < MAXDATE.MAX_DATE
;
SQL Fiddle: http://www.sqlfiddle.com/#!2/5df64/8
You could try using the following query (yes, it has a nested join, but maybe it helps).
SELECT ID FROM
(select d1.ID FROM data d1 LEFT JOIN
data d2 ON (d1.group_name = d2.group_name AND d1.list_name=d2.list_name AND
d1.updated_on > d2.updated_on) WHERE d2.ID IS NULL) data_tmp;
CORRECTION:
SELECT DISTINCT(ID) FROM
(select d1.* FROM data d1 LEFT JOIN
data d2 ON (d1.group_name = d2.group_name AND d1.list_name=d2.list_name AND
d1.updated_on < d2.updated_on) WHERE d2.ID IS NOT NULL) date_tmp;
SELECT DISTINCT y.id
FROM data x
JOIN data y
ON y.group_name = x.group_name
AND y.list_name = x.list_name
AND y.updated_on < x.updated_on;

nested query & transaction

Update #1: query gives me syntax error on Left Join line (running the query within the left join independently works perfectly though)
SELECT b1.company_id, ((sum(b1.credit)-sum(b1.debit)) as 'Balance'
FROM MyTable b1
JOIN CustomerInfoTable c on c.id = b1.company_id
#Filter for Clients of particular brand, package and active status
where c.brand_id = 2 and c.status = 2 and c.package_id = 3
LEFT JOIN
(
SELECT b2.company_id, sum(b2.debit) as 'Current_Usage'
FROM MyTable b2
WHERE year(b2.timestamp) = '2012' and month(b2.timestamp) = '06'
GROUP BY b2.company_id
)
b3 on b3.company_id = b1.company_id
group by b1.company_id;
Original Post:
I keep track of debits and credits in the same table. The table has the following schema:
| company_id | timestamp | credit | debit |
| 10 | MAY-25 | 100 | 000 |
| 11 | MAY-25 | 000 | 054 |
| 10 | MAY-28 | 000 | 040 |
| 12 | JUN-01 | 100 | 000 |
| 10 | JUN-25 | 150 | 000 |
| 10 | JUN-25 | 000 | 025 |
As my result, I want to to see:
| Grouped by: company_id | Balance* | Current_Usage (in June) |
| 10 | 185 | 25 |
| 12 | 100 | 0 |
| 11 | -54 | 0 |
Balance: Calculated by (sum(credit) - sum(debits))* - timestamp does not matter
Current_Usage: Calculated by sum(debits) - but only for debits in JUN.
The problem: If I filter by JUN timestamp right away, it does not calculate the balance of all time but only the balance of any transactions in June.
How can I calculate the current usage by month but the balance on all transactions in the table. I have everything working, except that it filters only the JUN results into the current usage calculation in my code:
SELECT b.company_id, ((sum(b.credit)-sum(b.debit))/1024/1024/1024/1024) as 'BW_remaining', sum(b.debit/1024/1024/1024/1024/28*30) as 'Usage_per_month'
FROM mytable b
#How to filter this only for the current_usage calculation?
WHERE month(a.timestamp) = 'JUN' and a.credit = 0
#Group by company in order to sum all entries for balance
group by b.company_id
order by b.balance desc;
what you will need here is a join with sub query which will filter based on month.
SELECT T1.company_id,
((sum(T1.credit)-sum(T1.debit))/1024/1024/1024/1024) as 'BW_remaining',
MAX(T3.DEBIT_PER_MONTH)
FROM MYTABLE T1
LEFT JOIN
(
SELECT T2.company_id, SUM(T2.debit) T3.DEBIT_PER_MONTH
FROM MYTABLE T2
WHERE month(T2.timestamp) = 'JUN'
GROUP BY T2.company_id
)
T3 ON T1.company_id-T3.company_id
GROUP BY T1.company_id
I havn't tested the query. The point here i am trying to make is how you can join your existing query to get usage per month.
alright, thanks to #Kshitij I got it working. In case somebody else is running into the same issue, this is how I solved it:
SELECT b1.company_id, ((sum(b1.credit)-sum(b1.debit)) as 'Balance',
(
SELECT sum(b2.debit)
FROM MYTABLE b2
WHERE b2.company_id = b1.company_id and year(b2.timestamp) = '2012' and month(b2.timestamp) = '06'
GROUP BY b2.company_id
) AS 'Usage_June'
FROM MYTABLE b1
#Group by company in order to add sum of all zones the company is using
group by b1.company_id
order by Usage_June desc;