MySql SUM and JOIN - mysql

I am trying to count sales made by a list of sales agents, this count is made every few minutes and updates a screen showing a 'sales leader board' which is updates using a Ajax call in the background.
I have one table which is created and populated every night containing the agent_id and the total sales for the week and month. I create a second, temporary table, on the fly which counts the sales for the day.
I need to combine the two tables to create a current list of sales for all agents in agent_count.
Table agent_count;
agent_id (varchar),
team_id (varchar),
name (varchar),
day(int),
week(int),
month(int)
Table sales;
agent_id (varchar),
day(int)
I can't figure out how to combine these tables. I think I need to use a join as all agents must be returned - even if they don't appear in the agent_count table.
First I make a simple call to get the week and month totals for all agents
SELECT agent_id, team_id, name, week, month FROM agent_count;
the I create a temporary table of todays sales, and then I count the sales for each agent for the day
CREATE TEMPORARY TABLE temp_todays_sales
SELECT s.id, s.agent_id
FROM sales s
WHERE DATEDIFF(s.uploaded, NOW()) = 0
AND s.valid = 1;
SELECT tts.agent_id, COUNT(tts.id) as today
FROM temp_todays_sales tts
GROUP BY tts.agent_id;
What is the best/easiet way to combine these to end up with a resultset such as
agent_id, team_id, name, day, week, month
where week and month also include the daily totals
thanks for any help!
Christy

SELECT s.agent_id, ac.team_id, ac.name,
s.`day` + COALESCE(ac.`day`, 0) AS `day`,
s.`day` + COALESCE(ac.`week`, 0) AS `week`,
s.`day` + COALESCE(ac.`month`, 0) AS `month`
FROM sales s
LEFT JOIN
agent_count ac
ON ac.agent_id = s.agent_id
team_id and name will be NULL if there is no record in agent_count for an agent.
If the agents can be missing from both tables, you normally would need to make a FULL JOIN but since MySQL does not support the latter you may use its poor man's substitution:
SELECT agent_id, MAX(team_id), MAX(name),
SUM(day), SUM(week), SUM(month)
FROM (
SELECT agent_id, NULL AS team_id, NULL AS name, day, day AS week, day AS month
FROM sales
UNION ALL
SELECT *
FROM agent_count
) q
GROUP BY
agent_id

Related

SQL Query using 5 aggregate functions

How do I query the following:
For each customer, product and month, count the number of sales transactions that were between the previous and the following month's average sales quantities. For January and December, display NULL or 0.
Can only use: 5 aggregate functions (sum, count, avg, max & min)
This is the table reference:
create table sales
(
cust varchar(20),
prod varchar(20),
day integer,
month integer,
year integer,
state char(2),
quant integer,
date date
);
Schema:
Example of my Desired Result
I am stuck with the following codes. I'm having a hard time how to execute it.
SELECT cust, prod, month, COUNT(*) AS SALES_COUNT_BETWEEN_AVGS
FROM sales
I use MySQL. Please guide me thank you.
Maybe try a query like below
the first part is to calculate averages using group by
second part is to use to those averages in a JOIN twice for past month and future month
third part is WHERE clause in which we compare data. Note we have used greatest and least functions to determine min and max between two values from past and next month
Query
WITH T AS
(SELECT cust, prod, month, AVG(quant) AS avg_quantity
FROM sales
group by cust, prod, month
)
SELECT S.cust, S.prod, S.month, COUNT(1) AS Sales_count
FROM sales S
LEFT JOIN T T1
ON T1.cust=S.Cust AND
T1.prod=S.Prod AND
T1.Month=S.Month-1
LEFT JOIN T T2
ON T2.cust=S.Cust AND
T2.prod=S.Prod AND
T2.Month=S.Month+1
WHERE S.quant BETWEEN IFNULL(LEAST(T1.avg_quantity,T2.avg_quantity),0) AND IFNULL(GREATEST(T1.avg_quantity,T2.avg_quantity),0)

How to get days missed in attendance table in mysql using NOT IN

I have a database for taking attendance daily.
every day is accounted for in a datetime (attended) field since there are never no students.
So, for a particular student ID (sid) I figure I'd be able to fill in the gaps of attendance using NOT IN.
select arrived, date_format(arrived,'%a') as 'day'
from attendance
where sid = '38'
and date_format(arrived, '%Y-%m-%d') NOT IN (
select DISTINCT date_format(arrived, '%Y-%m-%d')
from attendance
where MONTH(arrived) = 6
)
and MONTH(arrived) = 6
However, this generates the same results as if I hadn't used NOT IN at all. Now I'm realizing that those missing dates can't print because they're not in the sid limited query to begin with.
Can I move the NOT IN to the front of the query, so that the actual dates I want to display as absent are displayable.
For example, the student was absent 2019-06-06 (since that date is missing in 'his' query and other students were (so the nested query does show 2019-06-06)
See this fiddle: https://www.db-fiddle.com/f/x8VVvMBmizmsbJRHmY1GEd/0
select date(absences) absences from (select distinct date(arrived) absences from attendance) t2
where date(t2.absences) not in (select date(arrived) from attendance where sid=38)
You need to swap the inner and the outer query. You should look for attendance days of all students that are NOT IN attendance days of the specific student (sid=38):
select DISTINCT date(arrived) as 'day'
from attendance
where date(arrived) NOT IN (
select date(arrived)
from attendance
where sid = '38'
and MONTH(arrived) = 6
)
and MONTH(arrived) = 6

counting occurrences between dates of different date intervals

I have a query that give me a table like this:
Person | Date_IN | Date_OUT | Structure
During a year a person ENTER and EXIT many times, ENTER and EXIT could be also the same day.
I'd like to count, for a specific day of year, how many person were IN each structure.
The final goal is to have, for a given period (1st march --> 31st march), the sum of total person for each day for each structure.
I believe the following would work. It assumes that you have a table of dates (consists of one column which contains all the dates between 1950 and 2050) and you simply join it with the person check in/out table:
SELECT dates.date, Structure, COUNT(DISTINCT Person) Persons_on_That_Date
FROM dates
LEFT JOIN turndata ON dates.date BETWEEN Date_IN AND Date_OUT
WHERE dates.date BETWEEN '2018-03-01' AND '2018-03-31'
GROUP BY dates.date, Structure
ORDER BY Structure, dates.date
Demo Here
Note: the above assumes that the out date is inclusive (the person is counted as inside on that date). If out date is exclusive then the ON clause becomes:
... ON Date_IN <= dates.date AND dates.date < Date_OUT
Please use below query, data is grouped by structure for particular timeframe.
SELECT structure, COUNT(DISTINCT person) as no_of_person
FROM table_name
WHERE DATE(Date_IN) BETWEEN '2018-08-01' AND '2018-08-31'
GROUP BY structure
You say there can be no multiple date_in for the same day and person, because a person is in at least one day. So for a given date we only must look at the latest event per person until then to see whether the person is/was in that day.
These are the steps:
create a data set for the requiered days on-the-fly
join with the table and get the last date_in until that day per person
join with the table again to get the last records
aggregate per day and count persons present
This is:
select
data.day
sum(t.date_in is not null and (t.date_out is null or t.date_out = data.day)) as count_in
from
(
select days.day, t.person, max(t.date_in) as max_date_in
from (select date '2018-03-01' as day union all ...) days
left join t on t.date_in <= days.day
group by days.day, t.person
) data
left join t on t.person = data.person and t.date_in = data.max_date_in
group by data.day
order by data.day;

Select from 2 tables only the new entries in table 2

I got 2 tables, Customers and Payment. I'm trying to select only the new customers that have payments in the specified month and year, and no previous payments in another month.
table Customer
id - name
table Payment
id - id_customer - month - year - amount
SELECT * FROM customer, payment
WHERE Customer.id = Payment.id_customer
AND month = '$month'
AND year = '$year'
That gets me all the payments in a specific month and year, but I don't know how to exclude all the customers that had other previous payments.
Thank you for your time.
I don't think that you could achieve this without a third table. What you can do is create a third table with all the ids that you have selected in query and update it every time you run a select query.
Then the below query might work:
SELECT * FROM customer c, payment p WHERE c.id = p.id_customer
AND month = '$month'AND year = '$year'AND p.id NOT IN (SELECT id FROM
third_table)
Hope it answers your question.
To get the first date of payment, use GROUP BY. But, you will have to convert the value to something like a date first:
SELECT p.id_customer, MIN(CONCAT_WS, '-', p.year, p.month)) as first_yyyymm
FROM payment p
GROUP BY p.id_customer;
You should store the payment date as a date.

Count number of bookings between a set of specified dates

I have a table of bookings. I want to count how many bookings occur on each day, starting from specified check in date and check out date. Eg. if check in date was 10-06-2012 and check out date was 14-06-2012 I require a table like this
Date Bookings
10-06-2012 1
11-06-2012 1
12-06-2012 2
13-06-2012 4
14-06-2012 3
I am struggling to get this working. I can count bookings in between the dates but not for each date between check in date and check out date.
I am not sure I understand your question. The query below assumes:
Your bookings table has (at least) columns date, checkin, checkout.
You are looking for bookings where checkin >= 10-06-2012 and checkout <= 14-06-2012.
Here is the query:
SELECT date, COUNT(*)
FROM bookings
WHERE checkin >= '2012-06-10' AND checkout <= '2012-06-14'
GROUP BY date
Use SUM() to find total bookings between a date range.
Try Below :
SELECT Date,SUM(Bookings)
FROM tablename
WHERE Date between 'startdate' AND 'enddate'
GROUP BY Date
First thing you need is a table of dates, day by day. Now mysql is not my thing, so I will try to write down as much info on what I'm doing as I can. Please correct these examples.
Table of dates might be prepared by a job checking for the last booking date and adding missing dates to table of dates. If this is not something you would accept, other solution is to create table dynamically, but there are some perils. To my knowledge there is no way to create such a table, but you can do a practically-working surrogate by selecting distinct dates from your booking table and cross joining this with table of days made in query itself:
((select distinct checkIn from bookings union select distinct checkOut from bookings)
cross join (select 0 union select 1 union select 2 ...))
The list of days should contain as many days as the biggest gap between checkin dates and each checkin and checkout date. This is something you will have to keep an eye on, or simply make the list sufficiently large, for example a hundred days.
Now that you have a table of dates, you need to count bookings matching this date. Complete query would look like this:
select tableOfDates.date, count(bookings.checkIn) bookings
from
(
(
select distinct dates.date + INTERVAL days.day DAY -- OR HOWEVER you add days in mysql
from
(select distinct checkIn date from bookings union select distinct checkOut from bookings) dates
cross join (select 0 day union select 1 union select 2 union 3 union 4 union 5 union 6 union 7) days
)
) tableOfDates
left join bookings
on tableOfDates.date between bookings.checkIn and bookings.checkOut
where tableOfDates.date between [YOUR DATE RANGE]