How to detect if cell value appears twice in one day - mysql

Apologies in advance for the vagueness of the title. This is an issue that is stumping me and I struggled to get any more specific.
First of all, to help visualise my problem I've uploaded a photo of my database to http://imgur.com/a/rTyn8.
Basically, I've been adding up payments in my database and have run into a complex (contextually to my understanding of MySQL, anyway, which is mediocre at best) problem.
I want to calculate the number of times any given customer (customer_id) has a job_id payment of both 17 & 12 in one day. If they do, I then want to calculate the added cost of them. However, I'd like to run this query throughout the whole database between 2 specific dates (eg. 2016-01-01 -- 2016-05-06) and generate the total income during this period.
In the picture I link to above, the customer with a customer_id of 1658 has two payments - one of them with a job_id of 12, one of them 17. Therefore, I would like to add the the cost of both these (6.00 + 19.80) together, as well as anyone else who falls under this criteria, and come to a total figure.
Just to clarify, the customer (with a customer_id of 1913) below the rows I refer to would also fall under this category.
I've tried my best at getting something together, but admittedly I'm completely lost.
Thanks in advance,
Liam

Join the table to itself, once for each job type:
select
count(*) quantity,
sum(a.cost + b.cost) total
from mytable a
join mytable b on b.customer_id = a.customer_id
and a.date = b.date
where a.date between '2016-01-01' and '2016-05-06'
and a.job_id = 17
and b.job_id = 12
If you want a breakdown by customer_id, add a.customer_id to the selected columns and add group by customer_id.

Related

MySQL question about using between operators

I am learning MySQL and saw a project related to e-commerce and customer behaviour and want to follow it along.
However, when calculating the number of unique customers retained on the second day, the original author used a different approach and got a different result.
The code is below:
select count(distinct user_id) as first_day_customer_num from userbehavior
where date = '2017-11-25';-- 359 unique customers counted and retained on the first day
select count(distinct user_id) as second_day_customer_num from userbehavior
where date = '2017-11-26' and user_id in (SELECT user_id FROM userbehavior
WHERE date = '2017-11-25');-- 295 unique customers counted and retained on the second day
I used the between method for date and here is my code below to calculate the number of unique customers retained on the second day:
select count(distinct user_id) as trial from userbehavior
where date between '2017-11-25' and '2017-11-26'; -- 450 unique customers counted
Could I ask why is our result different and which part did I do wrong?
Thank you so much for your help and support, really appreciate it.

Finding the sum of a set of calculated sums

I am developing a php/mysql database.
I have a table called ‘actions’ which (amongst others) contains fields hrs, mins, actiondate, invoiceid and staffid.
For any particular actiondate there could be any number of actions carried out by various staff who would enter their time as hrs and mins.
What I need to do is produce a table which for each date and for a specific member of staff and invoice, adds up all of the hrs and mins for each date as a decimal, rounds it up to the nearest quarter and displays that result. I also need to be able to add up all of those results and display that total.
For example, if on March 1st, person with staffid=23 had carried out 4 actions for invoiced 121 lasting, 1h2m, 23m, 10m and 20m the total for that day would be 62+23+10+20 = 115m = 115/60 = 1.92 which would be rounded up to 2.00.
I can get each day’s total (maybe not very elegantly) and display it against the date using the code below
SELECT actions.`actiondate`,
(FORMAT((((CEIL((((60*SUM(hrs))+SUM(mins))/60)*4))/4)),2)) AS dayfeeqtr
FROM actions
WHERE staff.staffid=’23’
AND invoiceid=‘121’
GROUP BY actions.`actiondate`
However, what I can’t work out, is how can I add up all of these rounded up results for that invoice and that member of staff.
Can anyone help please?
If I understand correctly, you can use a subquery:
SELECT sum(dayfeeqtr)
FROM (SELECT a.`actiondate`,
FORMAT((((CEIL((((60*SUM(hrs))+SUM(mins))/60)*4))/4)), 2) AS dayfeeqtr
FROM actions a
WHERE s.staffid = '23' AND invoiceid = '121'
GROUP BY a.`actiondate`
) a;
I do note that your query is not correct -- for instance, there is a reference to staff, which is not in a from clause. However, you say that this is working, so I assume the errors are a transcription problem.

MYSQL Database Joined tables query pulling up limited records and adding results

I have two tables in my database that I"m trying to use one Query to get data from both for a specific report.
Table one is "Movies" and it has these fields:
Movies_ID
Name
Season
Table two is "Boxoffice" sales income for each movie:
Boxoffice_ID
Movies_ID
Date
Amount
I want to run a query to compare the opening weekends for each movie in a given season and return them as one dataset with the amounts collected added together. So I want to take each movie and get the first three days of box office for each film and add them up so that I get back a query like this
Movie A, 49.1 Million
Movie B, 42.2 Million
Movie C, 29.5 Million
Please note the amount collected only needs to output the number and I'll take care of the formatting. I'm just having trouble figuring out how to only query the first three days of box office for each movie and adding them together.
I know I could run one query and get the movies with box office and then loop over that and re-query the database but I know that with a lot of movies that isn't the most efficient way of doing things. I'm not sure if there is a way to do all of this (first three days of each movie added together) in one query but I wanted to see if someone with more advanced knowledge could help me out.
SELECT a.Name, SUM(COALESCE(b.Amount,0)) totalAmount
FROM Movies a
LEFT JOIN BoxOffice b
ON a.Movies_ID = b.Movies_ID
WHERE b.date BETWEEN DATE_ADD(CURDATE(),INTERVAL -3 DAY) AND CURDATE()
GROUP BY a.Name
if the value of CURDATE() is 2012-11-06 (which is today), it will calculate from 2012-11-03 until 2012-11-06.
followup question, how do you calculate the date? by day? by week? or what?
UPDATE 1
SELECT a.Name, SUM(COALESCE(b.Amount,0)) totalAmount
FROM Movies a
LEFT JOIN BoxOffice b
ON a.Movies_ID = b.Movies_ID
LEFT JOIN
(
SELECT movies_ID, MIN(date) minDate
FROM BoxOffice
GROUP BY Movies_ID
) c ON a.Movies_ID = c.Movies_ID
WHERE DATE(b.date) BETWEEN DATE(c.minDate) AND
DATE(DATE_ADD(c.minDate,INTERVAL 3 DAY))
GROUP BY a.Name
just join the tables on Movies_ID and add WHERE with TIMEDIFF between issue date and Date being 3 days.

How to deal with counting items by date in MySQL when the count for a given date increment is 0?

I'm looking to make some bar graphs to count item sales by day, month, and year. The problem that I'm encountering is that my simple MySQL queries only return counts where there are values to count. It doesn't magically fill in dates where dates don't exist and item sales=0. This is causing me problems when trying to populate a table, for example, because all weeks in a given year aren't represented, only the weeks where items were sold are represented.
My tables and fields are as follows:
items table: account_id and item_id
// table keeping track of owners' items
items_purchased table: purchaser_account_id, item_id, purchase_date
// table keeping track of purchases by other users
calendar table: datefield
//table with all the dates incremented every day for many years
here's the 1st query I was referring to above:
SELECT COUNT(*) as item_sales, DATE(purchase_date) as date
FROM items_purchased join items on items_purchased.item_id=items.item_id
where items.account_id=125
GROUP BY DATE(purchase_date)
I've read that I should join a calendar table with the tables where the counting takes place. I've done that but now I can't get the first query to play nice this 2nd query because the join in the first query eliminates dates from the query result where item sales are 0.
here's the 2nd query which needs to be merged with the 1st query somehow to produce the results i'm looking for:
SELECT calendar.datefield AS date, IFNULL(SUM(purchaseyesno),0) AS item_sales
FROM items_purchased join items on items_purchased.item_id=items.item_id
RIGHT JOIN calendar ON (DATE(items_purchased.purchase_date) = calendar.datefield)
WHERE (calendar.datefield BETWEEN (SELECT MIN(DATE(purchase_date))
FROM items_purchased) AND (SELECT MAX(DATE(purchase_date)) FROM items_purchased))
GROUP BY date
// this lists the sales/day
// to make it per week, change the group by to this: GROUP BY week(date)
The failure of this 2nd query is that it doesn't count item_sales by account_id (the person trying to sell the item to the purchaser_account_id users). The 1st query does but it doesn't have all dates where the item sales=0. So yeah, frustrating.
Here's how I'd like the resulting data to look (NOTE: these are what account_id=125 has sold, other people many have different numbers during this time frame):
2012-01-01 1
2012-01-08 1
2012-01-15 0
2012-01-22 2
2012-01-29 0
Here's what the 1st query current looks like:
2012-01-01 1
2012-01-08 1
2012-01-22 2
If someone could provide some advice on this I would be hugely grateful.
I'm not quite sure about the problem you're getting as I don't know the actual tables and data they contain that generates those results (that would help a lot!). However, let's try something. Use this condition:
where (items.account_id = 125 or items.account_id is null) and (other-conditions)
Your first query is perfectly acceptable. The fact is you don't have data in the mysql table and therefore it can't group any data together. This is fine. You can account for this in your code so that if the date does not exist, then obviously there's no data to graph. You can better account for this by ordering the date value so you can loop through it accordingly and look for missed days.
Also, to avoid doing the DATE() function, you can change the GROUP BY to GROUP BY date (because you have in your fields selected DATE(pruchase_date) as date)

Tricky Rails3/mysql query

In rails 3 (also with meta_where gem if you feel like using it in your query), I got a really tricky query that I have been banging my head for:
Suppose I have two models, customers and purchases, customer have many purchases. Let's define customers with at least 2 purchases as "repeat_customer". I need to find the total number of repeat_customers by each day for the past 3 months, something like:
Date TotalRepeatCustomerCount
1/1/11 10 (10 repeat customers by the end of 1/1/11)
1/2/11 15 (5 more customer gained "repeat" status on this date)
1/3/11 16 (1 more customer gained "repeat" status on this date)
...
3/30/11 150
3/31/11 160
Basically I need to group customer count based on the date of creation of their second purchase, since that is when they "gain repeat status".
Certainly this can be achieved in ruby, something like:
Customer.includes(:purchases).all.select{|x| x.purchases.count >= 2 }.group_by{|x| x.purchases.second.created_at.to_date }.map{|date, customers| [date, customers.count]}
However, the above code will fire query on the same lines of Customer.all and Purchase.all, then do a bunch of calculation in ruby. I would much prefer doing selection, grouping and calculations in mysql, since it is not only much faster, it also reduces the bandwith from the database. In large databases, the code above is basically useless.
I have been trying for a while to conjure up the query in rails/active_record, but have no luck even with the nice meta_where gem. If I have to, I will accept a solution in pure mysql query as well.
Edited: I would cache it (or add a "repeat" field to customers), though only for this simplified problem. The criteria for repeat customer can change by the client at any point (2 purchases, 3 purchases, 4 purchases etc), so unfortunately I do have to calculate it on the spot.
SELECT p_date, COUNT(customers.id) FROM
(
SELECT p_date - INTERVAL 1 day p_date, customers.id
FROM
customers NATURAL JOIN purchases
JOIN (SELECT DISTINCT date(purchase_date) p_date FROM purchases) p_dates
WHERE purchases.purchase_date < p_date
GROUP BY p_date, customers.id
HAVING COUNT(purchases.id) >= 2
) a
GROUP BY p_date
I didn't test this in the slightest, so I hope it works. Also, I hope I understood what you are trying to accomplish.
But please note that you should not do this, it'll be too slow. Since the data never changes once the day is passed, just cache it for each day.