My Requirement is to get the row before the max(create_date).
SELECT servicecalls_servicecall_id, max(created_at) FROM
service_followup_details where servicecalls_servicecall_id IN (SELECT
service_call_id from service_calls where status=2) group by
servicecalls_servicecall_id
How can I do it by MySQL query?
Get the max(create_at), then pick the one which is less than that max value.
select servicecalls_servicecall_id,created_at
from `service_followup_details`
where created_at<(
SELECT max(created_at)
FROM `service_followup_details`
where servicecalls_servicecall_id IN
(SELECT service_call_id from service_calls
where status=2)
group by servicecalls_servicecall_id
)
order by created_at desc
limit 1
;
Well you can achieve this with the help of ROW_NUMBER() function.
Check my implementation below. What I've done is, I'm sorting the records by created_at in a DESC order. Off course, this is partitioned by the servicecalls_servicecall_id so the sequence will restart for each new servicecalls_servicecall_id. Then you can simply pick the records that have row_number=2 to get the closest record to the max created_date.
SELECT servicecalls_servicecall_id,
ROW_NUMBER() OVER (partition by servicecalls_servicecall_id ORDER BY created_at DESC) AS row_number
FROM service_followup_details
WHERE servicecalls_servicecall_id IN (
SELECT service_call_id FROM service_calls WHERE status=2
)
AND row_number = 2;
Related
I have the transaction table with the following columns :
TRANSACTION_ID, USER_ID, MERCHANT_NAME, TRANSACTION_DATE, AMOUNT
-)Query to calculate time difference (in days) between current and previous order of
each customer
-)the avg time difference between two orders for every
customer.
Note : Exclude users with single transactions
I tried the following code to get the 1st part of the query but it looks too messy
with t1 as
(Select USER_ID,TRANSACTION_DATE,Dense_rank() over(partition by USER_ID order by TRANSACTION_DATE desc) as r1
from CDM_Bill_Details
order by USER_ID, TRANSACTION_DATE desc)
Select t11.USER_ID, datediff(t11.TRANSACTION_DATE,t111.TRANSACTION_DATE) from t1 as t11,t1 as t111
where (t11.r1=1 and t111.r1=2) and (t11.USER_ID=t111.USER_ID)
Please try this:
with t2 as (select *,
lag(t1.TRANSACTION_DATE, 1) OVER (PARTITION BY USER_ID ORDER BY TRANSACTION_DATE) AS previous_date,
datediff(t1.TRANSACTION_DATE, lag(t1.TRANSACTION_DATE, 1) OVER (PARTITION BY USER_ID ORDER BY TRANSACTION_DATE)) AS diff_prev_curr
from CDM_Bill_Details t1)
select *,
avg(diff_prev_curr) OVER (PARTITION BY USER_ID) AS avg_days_diff
from t2
where previous_date is not null
We are tracking order statuses sent by our shipping partners via a webhook fired by them. The webhook adds a row everytime its fired and therefore each order has multiple rows associated with it.
Structure of the table
enter image description here
We are trying to create a sql query to get the following
Find the last received row for a 'awb'. Get the current_status in that row. If the current_status is any of 'PICKUP EXCEPTION', 'OUT FOR PICKUP', 'PICKUP RESCHEDULED' then find the row with the first occurrence of these statuses for that specific 'awb'
Check number of days between first occurrence and last occurrence of those statuses for the awb
and output the awbs that have more than 2 days difference.
Here is the query i have been able to create.
WITH ranked_order_status AS (
SELECT os.*,
datediff(
now() ,
first_value(recived_at) over (partition by awb order by recived_at asc)
) as diff,
ROW_NUMBER() OVER (PARTITION BY awb ORDER BY recived_at desc) AS rn
FROM order_status AS os where current_status in ('PICKUP EXCEPTION', 'OUT FOR PICKUP', 'PICKUP RESCHEDULED')
)
SELECT * FROM ranked_order_status WHERE rn = 1 and diff > 2
This unfortunately shows me all awbs with rows having those statuses and not only the ones with the last received current status of 'PICKUP EXCEPTION', 'OUT FOR PICKUP', 'PICKUP RESCHEDULED'
Any idea how i can edit this?
So if I understood it correctly, this should be a clear case of an analytical function using RANK().
This would be my approach regarding the constraints you mentioned:
WITH t1 AS (
SELECT os.*,
FIRST_VALUE(os.received_at) OVER(PARTITION BY os.awb
ORDER BY os.received_at) AS first_received_at
FROM order_status AS os
WHERE os.current_status IN ('PICKUP EXCEPTION', 'OUT FOR PICKUP', 'PICKUP RESCHEDULED')
),
t2 AS (SELECT RANK() OVER (PARTITION BY t1.awb
ORDER BY t1.received_at DESC) AS reverse_event_sequence,
DATE_DIFF(t1.received_at, t1.first_received_at, DAY) AS day_diff
t1.*
FROM t1
),
final AS (
SELECT *
FROM t2
WHERE t2.day_diff > 2
AND t2.reverse_event_sequence = 1
)
SELECT *
FROM final
Basically, you want to first grab the first value of the received_at for every row, then you want to rank all the events for every awb and order it on descending order to always have the last event as rank=1, and then you apply the desired constraints on the date difference :)
I have to mention that not having a data sample doesn't help, though. And would appreciate any feedback on my approach :)
You can enumerate the rows from the most recent rows in two ways:
Partitioned by awb and ordered by received at descending
Partitioned by awb and status and ordered by received at descending
For the last status for each awb, the difference between these will be zero. You can select this and then aggregate:
select awb, current_status,
min(received_at), max(received_at)
from (select os.*,
row_number() over (partition by awb order by received_at desc) as seqnum,
row_number() over (partition by awb, current_status order by received_at desc) as seqnum_2
from order_status os
) os
where seqnum = seqnum_2 and
current_status in ('PICKUP EXCEPTION', 'OUT FOR PICKUP', 'PICKUP RESCHEDULED')
group by awb, current_status
having max(received_at) > min(received_at) + interval 2 day;
I'm doing a small project and I'm trying to get the restaurant with the most votes each week to be displayed once.
This is my query:
SELECT votedRestaurant,
week,
COUNT(*)
FROM mylunch.votes
GROUP BY votedRestaurant,
week
ORDER BY week DESC;
This gets me the following result:
I would only like to have the one with the highest COUNT(*) displayed per week.
Thanks for any help.
you can try use LIMIT and ordering by count, for example
SELECT votedRestaurant,
week,
COUNT(*) AS tcount
FROM mylunch.votes
GROUP BY votedRestaurant,
week
ORDER BY tcount DESC
LIMIT 1;
Also, you can use subquery, so says the documentation.
Using Mysql 8 you can make use of window functions
WITH
cte AS (SELECT votedRestaurant, WEEK, COUNT(*) total
FROM votes
GROUP BY votedRestaurant,WEEK
ORDER BY WEEK DESC, votedRestaurant)
SELECT *
FROM (
SELECT *,
row_number() over (PARTITION BY WEEK ORDER BY total DESC) AS rn
FROM
cte
) t
WHERE rn = 1
Demo
Another way would be by using string fuctions
SELECT t.week, SUBSTRING_INDEX(GROUP_CONCAT(t.votedRestaurant ORDER BY t.total DESC),',',1) votedRestaurant, MAX(t.total)
FROM(
SELECT votedRestaurant, WEEK, COUNT(*) total
FROM votes
GROUP BY votedRestaurant,WEEK
ORDER BY WEEK DESC
) t
GROUP BY t.week
ORDER BY t.week DESC
Demo
I have a food selling website in which there is order table which record the order of every user.It column for user id ,user name,orderid ,timestamp of order.I want to know the maximum number of order that has been made in any one hour span through out the day.Give me any formula for this,or any algorithm or any sql queries for these.
SQL server:
with CTE as
(
select cast(t1.timestamp as date) as o_date, datepart(hh, t1.timestamp) as o_hour, count(*) as orders
from MyTable t1
group by cast(t1.timestamp as date), datepart(hh, t1.timestamp)
)
select o_date, o_hour, orders
from CTE
where orders = (select max(orders) from CTE)
Oracle
with CTE as
(
select to_char(t1.timestamp, 'YYYYMMDD') as o_date, to_char(t1.timestamp, 'HH24') as o_hour, count(*)
from MyTable t1
group by to_char(t1.timestamp, 'YYYYMMDD'), to_char(t1.timestamp, 'HH24')
)
select o_date, o_hour, orders
from CTE
where orders = (select max(orders) from CTE)
You can get count by day and hour like this
For SQL
SELECT TOP 1
COUNT(*)
FROM myTable
GROUP BY DATEPART(day, [column_date]), DATEPART(hour, [column_date])
ORDER BY COUNT(*) DESC;
For MySQL
SELECT
COUNT(*)
FROM myTable
GROUP BY HOUR(column_date), DAY(column_date)
ORDER BY COUNT(*) DESC
LIMIT 1;
I have a table of production readings and need to get a result set containing a row for the min(timestamp) for EACH hour.
The column layout is quite simple:
ID,TIMESTAMP,SOURCE_ID,SOURCE_VALUE
The data sample would look like:
123,'2013-03-01 06:05:24',PMPROD,12345678.99
124,'2013-03-01 06:15:17',PMPROD,88888888.99
125,'2013-03-01 06:25:24',PMPROD,33333333.33
126,'2013-03-01 06:38:14',PMPROD,44444444.44
127,'2013-03-01 07:12:04',PMPROD,55555555.55
128,'2013-03-01 10:38:14',PMPROD,44444444.44
129,'2013-03-01 10:56:14',PMPROD,22222222.22
130,'2013-03-01 15:28:02',PMPROD,66666666.66
Records are added to this table throughout the day and the source_value is already calculated, so no sum is needed.
I can't figure out how to get a row for the min(timestamp) for each hour of the current_date.
select *
from source_readings
use index(ID_And_Time)
where source_id = 'PMPROD'
and date(timestamp)=CURRENT_DATE
and timestamp =
( select min(timestamp)
from source_readings use index(ID_And_Time)
where source_id = 'PMPROD'
)
The above code, of course, gives me one record. I need one record for the min(hour(timestamp)) of the current_date.
My result set should contain the rows for IDs: 123,127,128,130. I've played with it for hours. Who can be my hero? :)
Try below:
SELECT * FROM source_readings
JOIN
(
SELECT ID, DATE_FORMAT(timestamp, '%Y-%m-%d %H') as current_hour,MIN(timestamp)
FROM source_readings
WHERE source_id = 'PMPROD'
GROUP BY current_hour
) As reading_min
ON source_readings.ID = reading_min.ID
SELECT a.*
FROM Table1 a
INNER JOIN
(
SELECT DATE(TIMESTAMP) date,
HOUR(TIMESTAMP) hour,
MIN(TIMESTAMP) min_date
FROM Table1
GROUP BY DATE(TIMESTAMP), HOUR(TIMESTAMP)
) b ON DATE(a.TIMESTAMP) = b.date AND
HOUR(a.TIMESTAMP) = b.hour AND
a.timestamp = b.min_date
SQLFiddle Demo
With window function:
WITH ranked (
SELECT *, ROW_NUMBER() OVER(PARTITION BY HOUR(timestamp) ORDER BY timestamp) rn
FROM source_readings -- original table
WHERE date(timestamp)=CURRENT_DATE AND source_id = 'PMPROD' -- your custom filter
)
SELECT * -- this will contain `rn` column. you can select only necessary columns
FROM ranked
WHERE rn=1
I haven't tested it, but the basic idea is:
1) ROW_NUMBER() OVER(PARTITION BY HOUR(timestamp) ORDER BY timestamp)
This will give each row a number, starting from 1 for each hour, increasing by timestamp. The result might look like:
|rest of columns |rn
123,'2013-03-01 06:05:24',PMPROD,12345678.99,1
124,'2013-03-01 06:15:17',PMPROD,88888888.99,2
125,'2013-03-01 06:25:24',PMPROD,33333333.33,3
126,'2013-03-01 06:38:14',PMPROD,44444444.44,4
127,'2013-03-01 07:12:04',PMPROD,55555555.55,1
128,'2013-03-01 10:38:14',PMPROD,44444444.44,1
129,'2013-03-01 10:56:14',PMPROD,22222222.22,2
130,'2013-03-01 15:28:02',PMPROD,66666666.66,1
2) Then on the main query we select only rows with rn=1, in other words, rows that has lowest timestamp in each hourly partition (1st row after sorted by timestamp in each hour).