I am trying to device an incentive plan for my sales agents depending on number of orders, and which shift they worked in.
The sales table (mysql) has the following columns:
sale_id (int, primary, auto increment)
employee (varchar, 255)
sale_time (datetime, the time sale was placed)
sale_amount (float 10,2)
sales_channel (tinyint, with values call (1), walk_in (2),referral(3))
is_cancelled (tinyint, with values 1 for cancelled, and 0 as default)
(and a few other columns that are not relevant for this case)
I want to have write a query to fetch result with following columns (I use orders and sales interchangeably):
employee
total_orders (count excluding cancelled sales, i.e. is_cancelled!= 1)
orders_below_100dollars (orders count with sale_amount below 100 and is_cancelled = 0)
orders_above_100dollars (orders count with sale_amount above 100 and is_cancelled = 0)
orders_dayShift (orders count placed between 9am and before 10pm and is_cancelled = 0)
orders_nightShift (orders count placed after 10pm and before next day 9am and is_cancelled = 0)
cancelled_orders (orders count with is_cancelled = 1)
I understand that the query would have group by, case and perhaps if/else in the select, but can't frame it properly. Please help.
You are looking to use conditional aggregation -- here are a couple examples:
select employee,
sum(case when is_cancelled != 1 then 1 else 0 end) total_orders,
sum(case when sale_amount < 100 then 1 else 0 end) orders_below_100dollars,
sum(case when sale_amount >= 100 then 1 else 0 end) orders_above_100dollars,
...
from sales
group by employee
I'm not exactly sure what constitutes daytime vs nighttime, but it should be easy to add given the above.
You can use conditional aggregation for a lot of these. In other words, put the condition inside of a SUM() function to get the count of rows matching certain conditions:
SELECT employee,
SUM(is_cancelled <> 1) AS totalOrders,
SUM(sale_amount < 100 AND is_cancelled <> 1) AS orders_below_100,
SUM(sale_amount > 10 AND is_cancelled <> 1) AS orders_above_100,
SUM(sale_time < '22:00:00' AND is_cancelled <> 1) AS orders_dayshift,
SUM(sale_time > '22:00:00' AND is_cancelled <> 1) AS orders_nightshift,
SUM(is_cancelled = 1) AS totalCanceled
FROM sales
GROUP BY employee;
Related
I have one question in SQL.
This is the query.
SELECT Customer,
SUM(IF(date_format(OutputDate, '%Y') = 2020 AND date_format(OutputDate, '%m') = 3, SupplyPrice, 0)) AS March
FROM (SELECT Customer, OutputDate, SupplyPrice FROM `TableOutput`) AS C
GROUP BY Customer
ORDER BY March DESC
LIMIT 20;
it makes a result below:
Customer March
A 100
B 200
C 300
D 400
...
but I wanna make Customer A and B sum together as A(not B) or new name(e.g. Z)
like this:
Customer March
A(or Z) 300
C 300
D 400
...
I want to modify the query and output it.
I understand that you want to group together customers A and B. You can do this with a CASE expression:
SELECT
(CASE WHEN customer IN ('A', 'B') THEN 'A' ELSE Customer
END) as real_customer,
SUM(CASE WHEN outputDate >= '2020-03-01' AND outputDate < '2020-04-01' THEN SupplyPrice ELSE 0 END) AS March
FROM `TableOutput`
GROUP BY real_customer
ORDER BY March DESC
LIMIT 20;
Note that I modified the date predicate on outputDate so it uses comparisons to date litterals rather than using date functions; this is a more efficient approach, that may take advantage of a possibly existing index.
I am working with a query where I want to display number of upcoming dates. The following query returns 0 even though there are dates greater than current date. Please help me to solve this problem.
SELECT (case when b.booked_date > cast(now() as date) then sum(1) else sum(0) end) as upcoming_booked_facilities
from svk_apt_book_facilities b
where b.customer_id = 1
and b.association_id = 1
and b.is_active = 1
group by b.facility_id
You need to sum a CASE expression to do conditional aggregation:
SELECT
facility_id,
SUM(CASE WHEN booked_date > CURDATE() THEN 1 ELSE 0 END) AS upcoming_booked_facilities
FROM svk_apt_book_facilities
WHERE
customer_id = 1 AND
association_id = 1 AND
is_active = 1
GROUP BY
facility_id;
You were trying to use the sum as the predicate of the CASE expression, which is probably not what you want. Note that I am also selecting the facility_id, since you are grouping by that column. If you instead want a conditional sum over the entire table, then don't select or group by facility.
I have table as below :-
With help of MySql query, I want result as below:
date total read unread
2018-01-31 8 4 4
2018-02-01 2 2 0
Try this:
SELECT date, COUNT(*) as total,
SUM(CASE WHEN read = 1 THEN 1 ELSE 0) as read
SUM(CASE WHEN read = 0 THEN 1 ELSE 0) as unread
FROM yourtable
GROUP BY date
you can use case for aggregate the filtered value for read
select date
, count(*), sum(case when read=1 then 1 else 0 end ) as read
, sum(case when read=0 then 1 else 0 end ) as unread
from my_table
group by date
Try This we don't need case in the read column as 1 means read so we simply sum the value. It will help in the performance if we are dealing with the huge data:
SELECT date,
COUNT(*) as total,
SUM(read) as read --Case not needed here
SUM(CASE WHEN read = 0 THEN 1 ELSE 0) as unread
FROM yourtable
GROUP BY date
You have to group rows by date using group by, then you can use count to count the total number of rows within each date group (= total column).
In order to obtain the number of read and unread, you can sum read and unread value
SELECT date
, COUNT(*) AS total
, SUM(READ) AS READ
, SUM(CASE WHEN READ = 0 THEN 1 ELSE 0 END) AS unread
FROM mytable
GROUP BY date
I have a database with records of date-time and a measurement value.
I've been writing two separate queries, one to return the total count of all daily records between certain times of day for the previous month, and the same query but a count of only when the measurement value is below threshold. I then manually divide the theshold count by total count for each day, and I am able to get a % uptime or SLA.
So I have two questions:
1) Can I combine these two queries into one query. I found the Answer to #1, see below
2) Can I go ahead and do the math in the queries, so what I get returned is just a listing of each day, the count above, the count below, and the % above or below threshold...
Sample data and query are listed below.
TableA
hostname, date_time, value
Sample Query to return days from previous month, excluding weekend days.
SELECT
count(*),
DATE(date_time),
SUM(
CASE WHEN rssi_val < 100
THEN 1
ELSE 0
END
)
FROM TableA
WHERE hostname = 'hostA'
AND DATE(date_time) BETWEEN '2013-07-01' AND '2013-07-31'
AND TIME(date_time) BETWEEN '06:00:00' AND '18:00:00'
AND DAYOFWEEK(date_time) NOT IN (1, 7)
GROUP BY DATE(date_time);
So now I just want to know how to add a 4th column that gives the percent uptime/downtime.
Have you tried this ?
select count(*),
DATE(date_time),
SUM(CASE WHEN rssi_val<100 THEN 1 ELSE 0 END),
SUM(CASE WHEN rssi_val<100 THEN 1 ELSE 0 END)/count(*) as percentage
from TableA
where hostname='hostA'
and DATE(date_time) between '2013-07-01' and '2013-07-31'
and TIME(date_time) between '06:00:00' and '18:00:00'
and DAYOFWEEK(date_time) NOT IN (1,7)
group by DATE(date_time);
(first : I'm french and I'm sorry if I make some grammaticals faults...)
I have a table with TV programs. I want, in one query, to search the programs in this table and to sort the results with all the programs of the day before the programs of the night.
I have an input name fullDateStart with the date in DATETIME format for extract HOUR().
I use a LEFT JOIN in my research. Here my actual request :
SELECT programId, programTitle, COUNT(*) AS score,
ROUND(startDate / 1000) AS start, ROUND(endDate / 1000) AS end
FROM people_appearances AS a
LEFT JOIN programsTable AS b ON a.programId = b.program_id
WHERE peopleId = :id AND timestamp > :twoWeeksAgo AND programId != 0
AND redif = 0 AND channel_id IN(1,2,3,5,6,7,8,9)
GROUP BY programId
ORDER BY score DESC, start DESC
LIMIT 0, 10
Here my try with UNION :
SELECT * FROM (
SELECT fullDateStart, programId, programTitle, COUNT(*) AS score1,
ROUND(startDate / 1000) AS start, ROUND(endDate / 1000) AS end
FROM people_appearances AS a
LEFT JOIN db.epg_programs AS b ON a.programId = b.program_id
WHERE HOUR(fullDateStart) > 6 AND HOUR(fullDateStart) <= 23
AND peopleId = 826 AND timestamp > 1353420511000 AND programId != 0
AND redif = 0 AND channel_id IN(1,2,3,5,6,7,8,9)
GROUP BY programId
UNION
SELECT fullDateStart, programId, programTitle, COUNT(*) AS score2,
ROUND(startDate / 1000) AS start, ROUND(endDate / 1000) AS end
FROM people_appearances AS c
LEFT JOIN db.epg_programs AS d ON c.programId =d.program_id
WHERE HOUR(fullDateStart) >= 0 AND HOUR(fullDateStart) <= 6
AND peopleId = 826 AND timestamp > 1353420511000 AND programId != 0
AND redif = 0 AND channel_id IN(1,2,3,5,6,7,8,9)
GROUP BY programId
) AS s3
ORDER BY score1 DESC,start DESC
LIMIT 0, 10
Is somebody can help me please ? (I try with a Union with two request [one for the day, one for the night] but I don't succeed to sort the results, even if they was in two requests...)
The issue in your query is the order by. You are ordering everything first by the score, then by the start date.
If the goal is to keep everything in one day, then do something like:
order by score desc, date(fulldatestart),
(case when hour(fulldatestart) between 7 and 23 then 1
else 2
end),
hour(fulldatestart)
I added a third clause for the order by, so programs with the same score are ordered by hour.
If you want the early morning hours associated with the previous day, then you need to do something like:
order by score desc, date(fulldatestart - interval 7 hour),
hour(fulldatestart - interval 7 hour)
(once you subtract 7 hours, you can keep things in the order by hour.)