How to use IF statement in a calculation in a SQL query - mysql

I use following query to give me the earned commission of our sales agents.
SELECT * FROM
(SELECT agent,
COUNT(*) as sales,
(4*(SELECT COUNT(*)
FROM Sales Sales2
WHERE Sales2.agent=Sales.agent AND finalized_at BETWEEN '2020-11-01 00:00:00' AND '2020-11-27 23:59:59' AND flow=117))
/
(SELECT SUM(uren) FROM Uren WHERE datum BETWEEN '2020-11-01 00:00:00' AND '2020-11-27 23:59:59' AND agent=Sales.agent) as sph
FROM Sales
WHERE finalized_at BETWEEN '2020-11-27 00:00:00' AND '2020-11-27 23:59:59' AND flow=117
GROUP BY agent ) r
ORDER BY sales * sph desc;
Now I want the output to be sorted by (sales * sph * factor). Where factor is 10 if sph > 1.5 and else 7.5.
Is it possible to implement this in the query. If yes how do I achieve this?
It would also be good if calculation would be done in the SELECT statement like (sales * sph * factor) as commission and then just use SORT BY commission.
I hope my question makes any sense.

You could use condition in order by eg using a case when
SELECT *
FROM (
SELECT agent,
COUNT(*) as sales,
(4*(SELECT COUNT(*)
FROM Sales Sales2
WHERE Sales2.agent=Sales.agent AND finalized_at BETWEEN '2020-11-01 00:00:00' AND '2020-11-27 23:59:59' AND flow=117))
/
(SELECT SUM(uren) FROM Uren WHERE datum BETWEEN '2020-11-01 00:00:00' AND '2020-11-27 23:59:59' AND agent=Sales.agent) as sph
FROM Sales
WHERE finalized_at BETWEEN '2020-11-27 00:00:00' AND '2020-11-27 23:59:59' AND flow=117
GROUP BY agent ) r
ORDER BY sales * sph * (case when sph > 1.5 then 10 else 7.5 end ) desc;

Related

sql group by with double conditions

I need to get the amount of distinct parent_ids that fill in one of the conditions below , grouped by day:
parent_ids that have both status = pending & processing
OR
parent_ids who have both status = canceled and processing.
I ve tried something similar to :
SELECT count(parent_id) as pencan, created_at, DATE_FORMAT(a.created_at, '%Y') AS year_key, DATE_FORMAT(a.created_at, '%m-%d') as day_key
FROM sales_flat_order_status_history
where created_at BETWEEN '2010-01-01 00:00:00' AND '2013-04-30 23:59:59'
GROUP BY created_at ,parent_id
HAVING SUM(status = 'processing')
AND SUM(status IN ('pending', 'cancelling'))
I think you just need to fix the group by:
SELECT DATE(created_at), count(parent_id) as pencan
FROM sales_flat_order_status_history
where created_at >= '2010-01-01' AND
created_at < '2013-05-01'
GROUP BY DATE(created_at) , parent_id
HAVING SUM(status = 'processing') AND
SUM(status IN ('pending', 'cancelling'))

Is there a better way to structure this MySQL query to make it run faster?

I use a query to output a leaderboard. Where the output is sorted by the amount of commission earned by agents. I noticed that running the query takes quite a long time (+- 30 seconds). I was wondering if by like structuring (or ohter solutions) the query differently I could make the runtime faster.
This is the query:
SELECT * FROM
(SELECT agent,
COUNT(*) as sales,
(4*(SELECT COUNT(*)
FROM Sales Sales2
WHERE Sales2.agent=Sales.agent AND finalized_at BETWEEN '2020-11-01 00:00:00' AND '2020-11-27 23:59:59' AND flow=117))
/
(SELECT SUM(uren)
FROM Uren
WHERE datum BETWEEN '2020-11-01 00:00:00' AND '2020-11-27 23:59:59' AND agent=Sales.agent) as sph,
(SELECT COUNT(*)
FROM Sales Sales3
WHERE Sales3.agent=Sales.agent AND finalized_at BETWEEN '2020-11-27 00:00:00' AND '2020-11-27 23:59:59' AND flow=165) as telecom
FROM Sales
WHERE finalized_at BETWEEN '2020-11-27 00:00:00' AND '2020-11-27 23:59:59' AND flow=117
GROUP BY agent ) r
ORDER BY sales * sph * (case when sph > 1.5 then 10 else 7.5 end ) * 0.5184 + telecom * 3.75 desc;
This is the result of the EXPLAIN
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 165 100.00 Using filesort
2 DERIVED Sales NULL ALL NULL NULL NULL NULL 14899 1.11 Using where; Using temporary; Using filesort
5 DEPENDENT SUBQUERY Sales3 NULL ALL NULL NULL NULL NULL 14899 0.11 Using where
4 DEPENDENT SUBQUERY Uren NULL ALL NULL NULL NULL NULL 7286 1.11 Using where
3 DEPENDENT SUBQUERY Sales2 NULL ALL NULL NULL NULL NULL 14899 0.11 Using where
You can try to trunc those dates so the database will only consider the full day, and by this, processing less information.
Like this:
SELECT * FROM
(SELECT agent,
COUNT(*) as sales,
(4*(SELECT COUNT(*)
FROM Sales Sales2
WHERE Sales2.agent=Sales.agent AND trunc(finalized_at) BETWEEN '2020-11-01' AND '2020-11-27' AND flow=117))
/
(SELECT SUM(uren)
FROM Uren
WHERE trunc(datum) BETWEEN '2020-11-01' AND '2020-11-27' AND agent=Sales.agent) as sph,
(SELECT COUNT(*)
FROM Sales Sales3
WHERE Sales3.agent=Sales.agent AND trunc(finalized_at) = '2020-11-27' AND flow=165) as telecom
FROM Sales
WHERE trunc(finalized_at) = '2020-11-27' AND flow=117
GROUP BY agent ) r
ORDER BY sales * sph * (case when sph > 1.5 then 10 else 7.5 end ) * 0.5184 + telecom * 3.75 desc;
This part:
finalized_at BETWEEN '2020-11-27 00:00:00' AND '2020-11-27 23:59:59'
Was changed to:
trunc(finalized_at) = '2020-11-27'

How to get the data within the same day?

I'm doing a query to calculate the verified order within the same day. Regarding how to calculate, I can do it but to limit the time, can you help me?
For example: TIMESTAMPDIFF(HOUR, enddate, startdate) <= '24',
the time will be within 1 day, but it can be from one day to next day.
Then how can get the data within the same day?
My original query is:
SELECT COUNT(*),
1.0 * count(CASE WHEN TIMESTAMPDIFF(HOUR, `Created Datetime`, `Order Verification Date`) <= '2' THEN `BOB Sales Order Item` ELSE NULL END) / COUNT(`BOB Sales Order Item`) AS within_2hours_rate,
1.0 * count(CASE WHEN TIMESTAMPDIFF(DAY, `Created Datetime`, `Order Verification Date`) <= '24' THEN `BOB Sales Order Item` ELSE NULL END) / COUNT(`BOB Sales Order Item`) AS within_the_sameday_rate
FROM data.oms
WHERE `Created Datetime` BETWEEN '2017-10-29 00:00:00' AND '2017-11-04 23:59:59' AND `Order Verification Status` = 'finance_verified'
Thanks in advance!
If you're looking to check that the two times are on the same calendar day then you can do DATE(`Created Datetime`) = DATE(`Order Verification Date`).

Minimum and Maximum Count of Overlapping Bookings

I have a booking system that has multiple simultaneous bookings with a count number for each. I need to get the minimum and maximum for a specified date-range (for a day, in this case). I found some good code here, which works great in the test. But in my implementation, it fails in this particular instance:
It does not count bookings that start prior to the query-range and end within the query-range.
How do I fix this?
Here is an example:
This booking exists with these properties:
listings (an ID that multiple bookings can have, but only one in this case): 2f23f23f
date_start: 2016-01-15 08:00:00
date_end: 2016-01-17 08:00:00
state: active
count: 1
Result:
min_count: 0
max_count: 0
It should return:
min_count: 0
max_count: 1
If we query the very same, but with date range 2016-01-16 00:00:00 - 2016-01-16 23:59:59, it returns the correct answer:
min_count: 1
max_count: 1
Here is the MYSQL:
SELECT
MAX(simultaneous) AS max_count,
MIN(simultaneous) AS min_count
FROM (
SELECT IFNULL(SUM(
(
CASE WHEN (
listings = '2f23f23f'
AND
(state = 'active')
)
THEN count
ELSE 0
END
)
),0) AS simultaneous
FROM bookings RIGHT JOIN (
SELECT date_start AS boundary
FROM bookings
WHERE date_start BETWEEN '2016-01-17 00:00:00' AND '2016-01-17 23:59:59'
UNION
SELECT date_end
FROM bookings
WHERE date_end BETWEEN '2016-01-17 00:00:00' AND '2016-01-17 23:59:59'
UNION
SELECT MAX(boundary)
FROM (
SELECT MAX(date_start) AS boundary
FROM bookings
WHERE date_start <= '2016-01-17 00:00:00'
UNION ALL
SELECT MAX(date_end)
FROM bookings
WHERE date_end <= '2016-01-17 23:59:59'
) t
) t ON date_start <= boundary AND boundary < date_end
LEFT OUTER JOIN cart ON cart_bookings = id
GROUP BY boundary
) t
Whew, ok, here's the answer. The original evidently wasn't complete. It needed to include the start/end dates of the time-range being requested.
UNION
SELECT :date_start
UNION
SELECT :date_end
Complete code:
SELECT
MAX(simultaneous) AS max_count,
MIN(simultaneous) AS min_count
FROM (
SELECT IFNULL(SUM(
(
CASE WHEN (
listings = '2f23f23f'
AND
(state = 'active')
)
THEN count
ELSE 0
END
)
),0) AS simultaneous
FROM bookings RIGHT JOIN (
SELECT date_start AS boundary
FROM bookings
WHERE date_start BETWEEN '2016-01-17 00:00:00' AND '2016-01-17 23:59:59'
UNION
SELECT date_end
FROM bookings
WHERE date_end BETWEEN '2016-01-17 00:00:00' AND '2016-01-17 23:59:59'
UNION
SELECT MAX(boundary)
FROM (
SELECT MAX(date_start) AS boundary
FROM bookings
WHERE date_start <= '2016-01-17 00:00:00'
UNION ALL
SELECT MAX(date_end)
FROM bookings
WHERE date_end <= '2016-01-17 23:59:59'
) t
UNION
SELECT :date_start
UNION
SELECT :date_end
) t ON date_start <= boundary AND boundary < date_end
LEFT OUTER JOIN cart ON cart_bookings = id
GROUP BY boundary
) t

Not in and In together or exist or not exist for finding renewed orders

The query is this to find renewed orders
A renewal is any school that PAID (i.e. total_line_price >0) for an order in the previous school year , but that same school has purchased (paid for – total line price>0) another order.
next year '08-01-2016 00:00:00' and '07-31-2017 00:00:00' -2016
current year '08-01-2015 00:00:00' and '07-31-2016 00:00:00' -2015
previous year '08-01-2014 00:00:00' and '07-31-2015 00:00:00' - 2014
Below is query that i have written and its not right. Need some help
select
(school_ucn
from storiacloud_staging.schl_royl_vw_edw_oms_order
where school_ucn not in ((select school_ucn
from storiacloud_staging.schl_royl_vw_edw_oms_order
where (((start_date between '08-01-2014 00:00:00' and '07-31-2015 00:00:00')
and (total_line_price >0) ))
and in
(select school_ucn
from storiacloud_staging.schl_royl_vw_edw_oms_order
where ((start_date between '08-01-2015 00:00:00' and '07-31-2016 00:00:00') and ( total_line_price >0))
)))
You are using and in inside your query. It should be and school_ucn in.
Always format your query properly to analyse easily.
select school_ucn
from storiacloud_staging.schl_royl_vw_edw_oms_order
where school_ucn not in (
select school_ucn
from storiacloud_staging.schl_royl_vw_edw_oms_order
where start_date between '08-01-2014 00:00:00' and '07-31-2015 00:00:00'
and total_line_price >0)
and school_ucn in (select school_ucn
from storiacloud_staging.schl_royl_vw_edw_oms_order
where start_date between '08-01-2015 00:00:00' and '07-31-2016 00:00:00'
and total_line_price >0)
Using Not Exists, you can rewrite your query as follows.
select school_ucn
from storiacloud_staging.schl_royl_vw_edw_oms_order as a
where start_date between '08-01-2015 00:00:00' and '07-31-2016 00:00:00'
and total_line_price >0
and not exists (select 1
from storiacloud_staging.schl_royl_vw_edw_oms_order as b
where b. school_ucn = a. school_ucn
and start_date between '08-01-2014 00:00:00' and '07-31-2015 00:00:00’
and total_line_price >0)