I'm trying to solve a problem in my analytical project whereas a representative gets a customer call/email and if needed they would ask for an advisor help (advise ring) and after that the representative would resolve the email/phone, henceforth sending a survey to the customer.
I want to track the first survey sent after the advise ring have been resolved only, but it does not matter if the customer opened the incident again and the representative resolved the incident without an advise ring, we would not want to count that survey.
Use case: A Representative gets an email > Pulls an advise ring > The advisor resolves it > Representative solves the email > Survey is sent (Gets counted). > Customer open the incident again > Rep solves the incident without an advise ring > Survey is sent (Does not get counted).
The problem here is that I can't track the subsequent dates for some reason.
Survey Table example
Incident_ID| Survey_sent_date | survey_id | response |
-----------+---------+-----+------------+------------------
3324324 | 2022-03-03 16:23:02.1| 7 | |
3324324 | 2022-03-03 18:32:0.1 | 14 | N |
3324324 | 2022-03-04 11:32:0.1 | 9 | Y |
3324324 | 2022-03-05 16:23:02.1| 17 | Y |
3324324 | 2022-03-11 18:31:12.1| 134 | N |
3324324 | 2022-03-11 20:35:12.1| 139 | N |
3324324 | 2022-03-15 19:45:26.0| 29 | Y |
3324324 | 2022-03-17 19:45:26.0| 229 | Y |
Advise ring table
Incident_ID| advise_ring_resolve_date| advise_ring_id
-----------+---------+-----+------------+--------------
3324324 | 2022-03-11 18:30:52.1 | 247 |
3324324 | 2022-03-15 19:30:37.0 | 143 |
Expected Results:
Incident_ID| Survey_sent_date | survey_id | response |
-----------+---------+-----+------------+------------------
3324324 | 2022-03-11 18:31:12.1 | 134 | N |
3324324 | 2022-03-15 19:45:26.0 | 29 | Y |
I have tried to get the first rank of each date between each survey_sent_date and get the subsequent survey_id between the advise_ring_resolve_date and the survey_sent_date.
What I have in mind is the following:
On the advise_ring_id 247, get the survey sent on 2022-03-11 18:31:12.1 ONLY as it was immediately sent after the advise ring was resolved.
Similarly, the advise_ring_id 143 would get the survey sent on 2022-03-15 19:45:26.0 as it was immediately after the advise ring was resolved. and so on.
WITH surveys_sent as(
SELECT DISTINCT
ss.incident_id,
ss.survey_sent_date,
ss.survey_id,
ss.response,
ROW_NUMBER OVER (PARTITION BY ss.survey_id ORDER BY ss.survey_sent_date) as req
FROM SURVEY_TABLE SS
WHERE ss.incident_id = '3324324'),
advise_ring as(
SELECT DISTINCT
ar.incident_id,
ar.advise_ring_resolve_date,
ar.advise_ring_id
FROM ADVISE_TABLE
WHERE ss.incient_id = '3324324')
SELECT DISTINCT
finalar.case_id,
finalss.survey_id,
finalss.survey_sent_date
FROM advise_ring finalar
INNER JOIN surveys_sent finalss
ON finalar.case_id = finalss.case_id AND finalar.advise_ring_resolve_date BETWEEN
finalar.advise_ring_resolve_date AND finalss.survey_sent_date
WHERE finalss.req = 1;
I tried to full outer and left join the table, also tried to remove the ranking bit which did not help at all.
The full outer join provided me with a union like join where both of the columns are empty at their respective timestamp.
The desired result would having the count OR the details of the surveys sent after the first advise ring has been sent on that specific date.
Do you have any advise on the above?
Thanks!
EDIT:
I have tried to get the rank of the lowest difference between the advise ring date and the survey sent date, however it gives me duplicate values for some reason.
WITH base AS
(
SELECT DISTINCT *
FROM ADVISE_TABLE
WHERE INCIDENT_ID = 3324324
)
SELECT *
FROM
(
SELECT
base.advise_ring_id,
ss.survey_sent_date,
ss.survey_id,
base.advise_ring_resolve_date,
DATEDIFF(sec,ss.survey_sent_date,base.advise_ring_resolve_date)
as time_diff
,ROW_NUMBER() over (PARTITION BY base.advise_ring_id ORDER BY
DATEDIFF(sec,ss.survey_sent_date,base.advise_ring_resolve_date)
DESC) as rk
FROM base
LEFT JOIN SURVEY_TABLE ss
on ss.incident_id = base.incident_id
WHERE
DATEDIFF(sec,ss.survey_sent_date,base.advise_ring_resolve_date)
<=0
)
WHERE rk = 1
Result is from real table but different data:
base.advise_ring_id|Survey_sent_date | survey_id | base.advise_ring_resolve_date|
-----------+---------+-----+------------+------------------
123 | 2022-12-22 16:23:02.1| 7 | 2022-12-15 13:23:02.1 |
333 | 2022-01-03 06:55:25.1 | 14 | 2022-12-23 18:23:02.1 |
333 | 2022-01-03 06:55:25.1 | 14 | 2022-12-29 11:23:02.1 |
Basically from the result the top 2 only should be included not the third one, so by each date.
I think something like this should work. Use LAG to get the previous survey date based on the current row. Then search for any Advise_Ring records between the previous and current survey date range. Finally use ROW_NUMBER() to rank the Advise_Ring records and return the first one.
WITH surveys AS (
SELECT *
, LAG(Survey_Sent_Date, 1) OVER(
PARTITION BY Incident_Id ORDER BY Survey_Sent_Date
) AS Prev_Survey_Sent_Date
FROM Survey_Table
)
SELECT t.Incident_ID
, t.Survey_sent_date
, t.survey_id
, t.response
, t.advise_ring_id
FROM (
SELECT s.Incident_ID
, s.Survey_sent_date
, s.survey_id
, s.response
, ar.advise_ring_id
, ar.advise_ring_resolve_date
, ROW_NUMBER() OVER(
PARTITION BY s.survey_id
ORDER BY ar.advise_ring_resolve_date, ar.advise_ring_id
) AS advise_row_num
FROM surveys s INNER JOIN Advise_Ring ar
ON s.Incident_ID = ar.Incident_ID
AND s.Prev_Survey_Sent_Date < ar.advise_ring_resolve_date
AND s.Survey_Sent_Date > ar.advise_ring_resolve_date
) t
WHERE t.advise_row_num = 1
ORDER BY t.Survey_Sent_Date
;
Results:
Incident_ID
Survey_sent_date
survey_id
response
advise_ring_id
7496137492
2021-12-22 15:25:48
5245
Y
1
7496137492
2022-01-03 06:55:25
4613
Y
12
db<>fiddle here
Related
I'm using MySql 5.6 and have a select query with a LEFT JOIN but i need to retrieve the max of a associated column email_nb) but with a different "perimeter" of constraints.
Let's take an example: let me state that it is a mere example with only 5 rows but it should work also when I have thousands... (I'm stating this since there is a LIMIT clause in my query)
Table 'query_results'
+-----------------------------+------------+--------------+
| query_result_id | query_id | author |
+-----------------------------+------------+--------------+
| 2 | 1 | john |
| 3 | 1 | eric |
| 7 | 3 | martha |
| 9 | 4 | john |
| 10 | 1 | john |
+-----------------------------+------------+--------------+
Table 'customers_emails'
+-------------------+-----------------+--------------+-----------+-------------+------------------------
| customer_email_id | query_result_id | customer_id | author | email_nb | days_since_sending
+-------------------+-----------------+--------------+-----------+-------------+------------------------
| 5 | 2 | 12 | john | 2 | 150
| 12 | 3 | 7 | eric | 4 | 90
| 27 | 3 | 12 | eric | 2 | 86
| 40 | 9 | 15 | john | 9 | 87
| 42 | 2 | 12 | john | 7 | 23
| 51 | 10 | 12 | john | 3 | 89
+-------------------+-----------------+--------------+-----------+-------------+-----------------------
Notes:
you can have a query_result where the author appears in NO row at all in any of the customers_emails, hence the LEFT JOIN I'm using.
You can see author is by design kind of duplicated as it's both on the first table and the second table each time associated with a query_result_id. It's important to note.
email_nb is an integer between 0 and 10
there is a LIMIT clause as I need to retrieve a set number of records
Today my query aims at retrieving query_results with a certain number of conditions on The specificity is that I make sure to retrieve query_results with an author who does not appear in any customer_email_id where the days_since_sending would be less than 60 days: it means i check these days_since_sending not only within the records for this query, but across all customers_emails thanks to the subquery NOT IN (see below).
This is my current query for customer_id = 12 and query_id = 1
SELECT
qr.query_result_id,
qr.author,
FROM
query_results qr
LEFT JOIN
customers_emails ce
ON
qr.author = ce.author
WHERE
qr.query_id = 1 AND
qr.author IS NOT NULL
AND qr.author NOT IN (
SELECT recipient
FROM customers_emails
WHERE
(
customer_id = 12 AND
( days_since_sending >= 60) )
)
)
# we don't take by coincidence/bad luck 2 query results with the same author
GROUP BY
qr.author
ORDER BY
qr.query_result_id ASC
LIMIT
20
This is the expected output:
+-----------------------------+------------+--------------+
| query_result_id | author | email_nb |
+-----------------------------+------------+--------------+
| 10 | john | 7 |
| 3 | eric | 2 |
+-----------------------------+------------+--------------+
My challenge/difficulty today:
Notice on the 2nd line Eric is tied to email_nb 2 and not the max of all Eric's emails which could have been 4 if we had taken the max of email_nb across ALL messages to author=eric. but we stay within the limit of customer_id = 12 so there's only one left with email_nb = 2
Also notice that on the first line, the email_nb associated with query_result = 10 is 7, and not 3, which could have been the case as 3 is what appears in table customers_emails on the last line.
Indeed for emails to 'john' i had the choice between email_nb 2, 7 and 3 but I take highest so it's 7 (even if this email is from more than 60 days ago !! This is very important and part of what I don't know how to do: the perimeters are different: today I retrieve all the query_results where the author has NOT been sent a email for the past 60 days (see the NOT IN subquery) BUT I need to have in the column the max email_nb sent to john by customer_id=12 and query_id=1 EVEN if it was sent more than 60 days ago so these are different perimeters...Don't really know how to do this...
It means in other words I don't want to find the max (email_nb) within the same WHERE clauses such as days_since_sending >= 60 or within the same LIMIT and GROUP BY...as my current query: what I neeed is to retrieve the maximum value of email_nb for customer_id=12 AND query_id=1 and sent to john across ALL records on the customers_emails table!
If there is no associated row on customers_emails at all (it means no email have been ever sent by this customer for this query in the past) then the email_nb should be sth like NULL..
This means I do NOT want this output:
+-----------------------------+------------+--------------+
| query_result_id | author | email_nb |
+-----------------------------+------------+--------------+
| 10 | john | 3 |
| 3 | eric | 2 |
+-----------------------------+------------+--------------+
How to achieve this in MySQL 5.6 ?
Since you were confusing a bit, I came up on this.
select
max(q.query_result_id) as query_result_id,q.author,max(email_nb) as email_nb
from query_results q
left join customers_emails c on q.author=c.author
where customer_id=12 and query_id=1
group by q.author;
I think the best thing to do in a situation like this is break it down into smaller queries and then combine them together.
The first thing you want to do is this:
The specificity is that I make sure to retrieve query_results with an author who does not appear in any customer_email_id where the days_since_sending would be less than 60 days
This might look something like this:
-- Query A
SELECT DISTINCT q.author FROM query_results q
WHERE q.author NOT IN (
SELECT c.author FROM customers_emails c
WHERE c.days_since_sending < 60
)
AND q.query_id = 1
This will get you the list of authors (with duplicates removed) that haven't had an email in the last 60 days that appear for the given query ID. Your next requirement is the following:
I need to have in the column the max email_nb sent to john by customer_id=12 and query_id=1 EVEN if it was sent more than 60 days ago
This query could look like this:
-- Query B
SELECT c.query_result_id, c.author, MAX(c.email_nb) as max_email_nb
FROM customers_emails c
LEFT JOIN query_results q ON c.author = q.author
WHERE c.customer_id = 12
AND q.query_id = 1
GROUP BY c.query_result_id, c.author
That gets you the maximum email_nb for each author/query_result combination, not taking into consideration the date at all.
The only thing left to do is reduce the set of results from the second query down to only the authors that appear in the first query. There are a few different methods for doing that. For example, you could INNER JOIN the two queries by author:
SELECT b.* FROM (
-- Query B
SELECT c.query_result_id, c.author, MAX(c.email_nb) as max_email_nb
FROM customers_emails c
LEFT JOIN query_results q ON c.author = q.author
WHERE c.customer_id = 12
AND q.query_id = 1
GROUP BY c.query_result_id, c.author
) b INNER JOIN (
-- Query A
SELECT DISTINCT q.author FROM query_results q
WHERE q.author NOT IN (
SELECT c.author FROM customers_emails c
WHERE c.days_since_sending < 60
)
AND q.query_id = 1
) a ON a.author = b.author
You could use another NOT IN clause:
SELECT b.* FROM (
-- Query B
SELECT c.query_result_id, c.author, MAX(c.email_nb) as max_email_nb
FROM customers_emails c
LEFT JOIN query_results q ON c.author = q.author
WHERE c.customer_id = 12
AND q.query_id = 1
GROUP BY c.query_result_id, c.author
) b
WHERE b.author NOT IN (
-- Query A
SELECT DISTINCT q.author FROM query_results q
WHERE q.author NOT IN (
SELECT c.author FROM customers_emails c
WHERE c.days_since_sending < 60
)
AND q.query_id = 1
) a
There are most likely ways to improve the speed or reduce down the lines of code for this query, but if you need to do that you now have a query that works at least that you can compare the results to.
I am trying to develop a ranking table for a sort of questionnaire.
Each day a question is asked at 16h (4:00 pm), which can be answered by 17:59:59 the following day. The table has to show the position of the participants taking into account the correct answers is the time.
My table will be of the sort:
+-------+---------+---------------------+
|userid | correct | timestamp |
+-------+---------+---------------------+
| 2 | 1 | 2018-02-07 16:00:01 |
| 1 | 1 | 2018-02-07 16:02:00 |
| 3 | 1 | 2018-02-07 17:00:00 |
| 1 | 0 | 2018-02-08 16:00:02 |
| 3 | 1 | 2018-02-08 16:00:05 |
| 2 | 0 | 2018-02-08 16:01:00 |
+-------+---------+---------------------+
For now I started with this query:
SELECT `userid`, `correct `, `timestamp`,
count(correct) as count
FROM `results`
WHERE correct = 1
GROUP BY `userid `
ORDER BY count DESC, timestamp DESC
But I have already realized that this is not what I intend because the ranking has to be cumulative but taking into account the several days.
Does anyone have an idea how I can do this?
A user from Stackoverflow Portugal advised this code but it is not working either.
SELECT userid, SUM(correct),
SUM(TIMESTAMPDIFF(HOUR,(timestamp,CAST(CONCAT_WS(' ',date(timestamp), '17:59:59') as DATETIME)))) time
FROM results
GROUP BY userid
ORDER BY correct DESC, time
Don’t deal with this datetime (16h), this may be changed and you will be lost on your query.
Instead, you should count by userid and questionnaire_id. To do so:
add new table questionnaire [id, title] (you can add extra column
later : created_time, end_time, …)
edit your record table by adding the questionnaire id as FK : [userid, questionnaireid, correct, timestamp]
then count normally: Correct answer by user, by questionnaire
SELECT userid, questionnaireid ,
sum(correct) as total
FROM results r
INNER JOIN questionnaire q
ON r.questionnaireid = q.id
WHERE correct = 1
GROUP BY userid, questionnaireid
ORDER BY total DESC, id ASC
I am trying to construct a highscore table from entries in a table with the layout
id(int) | username(varchar) | score(int) | modified (timestamp)
selecting the highest scores per day for each user is working well using the following:
SELECT id, username, MAX( score ) AS hiscore
FROM entries WHERE DATE( modified ) = CURDATE( )
Where I am stuck is that in some cases plays may achieve the same score multiple times in the same day, in which case I need to make sure that it is always the earliest one that is selected because 2 scores match will be the first to have reached that score who wins.
if my table contains the following:
id | username | score | modified
________|___________________|____________|_____________________
1 | userA | 22 | 2014-01-22 08:00:14
2 | userB | 22 | 2014-01-22 12:26:06
3 | userA | 22 | 2014-01-22 16:13:22
4 | userB | 15 | 2014-01-22 18:49:01
The returned winning table in this case should be:
id | username | score | modified
________|___________________|____________|_____________________
1 | userA | 22 | 2014-01-22 08:00:14
2 | userB | 22 | 2014-01-22 12:26:06
I tried to achieve this by adding ORDER BY modified desc to the query, but it always returns the later score. I tried ORDER BY modified asc as well, but I got the same result
This is the classic greatest-n-per-group problem, which has been answered frequently on StackOverflow. Here's a solution for your case:
SELECT e.*
FROM entries e
JOIN (
SELECT DATE(modified) AS modified_date, MAX(score) AS score
FROM entries
GROUP BY modified_date
) t ON DATE(e.modified) = t.modified_date AND e.score = t.score
WHERE DATE(e.modified) = CURDATE()
I think this would works for you and is the simplest way:
SELECT username, MAX(score), MIN(modified)
FROM entries
GROUP BY username
This returns this in your case:
"userB";22;"2014-01-22 12:26:06"
"userA";22;"2014-01-22 08:00:14"
However, I think what you want (in your example would be wrong) the most recent row. To do it, you need this:
SELECT username, MAX(score), MAX(modified)
FROM entries
GROUP BY username
Which returns:
"userB";22;"2014-01-22 18:49:01"
"userA";22;"2014-01-22 16:13:22"
I have a table from which I am trying to retrieve the latest position for each security:
The Table:
My query to create the table: SELECT id, security, buy_date FROM positions WHERE client_id = 4
+-------+----------+------------+
| id | security | buy_date |
+-------+----------+------------+
| 26 | PCS | 2012-02-08 |
| 27 | PCS | 2013-01-19 |
| 28 | RDN | 2012-04-17 |
| 29 | RDN | 2012-05-19 |
| 30 | RDN | 2012-08-18 |
| 31 | RDN | 2012-09-19 |
| 32 | HK | 2012-09-25 |
| 33 | HK | 2012-11-13 |
| 34 | HK | 2013-01-19 |
| 35 | SGI | 2013-01-17 |
| 36 | SGI | 2013-02-16 |
| 18084 | KERX | 2013-02-20 |
| 18249 | KERX | 0000-00-00 |
+-------+----------+------------+
I have been messing with versions of queries based on this page, but I cannot seem to get the result I'm looking for.
Here is what I've been trying:
SELECT t1.id, t1.security, t1.buy_date
FROM positions t1
WHERE buy_date = (SELECT MAX(t2.buy_date)
FROM positions t2
WHERE t1.security = t2.security)
But this just returns me:
+-------+----------+------------+
| id | security | buy_date |
+-------+----------+------------+
| 27 | PCS | 2013-01-19 |
+-------+----------+------------+
I'm trying to get the maximum/latest buy date for each security, so the results would have one row for each security with the most recent buy date. Any help is greatly appreciated.
EDIT: The position's id must be returned with the max buy date.
You can use this query. You can achieve results in 75% less time. I checked with more data set. Sub-Queries takes more time.
SELECT p1.id,
p1.security,
p1.buy_date
FROM positions p1
left join
positions p2
on p1.security = p2.security
and p1.buy_date < p2.buy_date
where
p2.id is null;
SQL-Fiddle link
You can use a subquery to get the result:
SELECT p1.id,
p1.security,
p1.buy_date
FROM positions p1
inner join
(
SELECT MAX(buy_date) MaxDate, security
FROM positions
group by security
) p2
on p1.buy_date = p2.MaxDate
and p1.security = p2.security
See SQL Fiddle with Demo
Or you can use the following in with a WHERE clause:
SELECT t1.id, t1.security, t1.buy_date
FROM positions t1
WHERE buy_date = (SELECT MAX(t2.buy_date)
FROM positions t2
WHERE t1.security = t2.security
group by t2.security)
See SQL Fiddle with Demo
This is done with a simple group by. You want to group by the securities and get the max of buy_date. The SQL:
SELECT security, max(buy_date)
from positions
group by security
Note, this is faster than bluefeet's answer but does not display the ID.
The answer by #bluefeet has two more ways to get the results you want - and the first will probably be more efficient than your query.
What I don't understand is why you say that your query doesn't work. It seems pretty fine and returns the expected result. Tested at SQL-Fiddle
SELECT t1.id, t1.security, t1.buy_date
FROM positions t1
WHERE buy_date = ( SELECT MAX(t2.buy_date)
FROM positions t2
WHERE t1.security = t2.security ) ;
If the problems appears when you add the client_id = 4 condition, then it's because you add it only in one WHERE clause while you have to add it in both:
SELECT t1.id, t1.security, t1.buy_date
FROM positions t1
WHERE client_id = 4
AND buy_date = ( SELECT MAX(t2.buy_date)
FROM positions t2
WHERE client_id = 4
AND t1.security = t2.security ) ;
select security, max(buy_date) group by security from positions;
is all you need to get max buy date for each security (when you say out loud what you want from a query and you include the phrase "for each x", you probably want a group by on x)
When you use a group by, all columns in your select must either be columns that have been grouped by or aggregates, so if, for example, you wanted to include id, you'd probably have to use a subquery similar to what you had before, since there doesn't seem to be any aggregate you can reasonably use on the ids, and another group by would give you too many rows.
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;