MySQL Query to group by date range - mysql

I am having a problem with this query:
SELECT
YEAR(passDate) as Year,
count(*) AS total_amount
FROM
`dsp_drop_pass_details`
WHERE passDate
BETWEEN '2009-01-01'
AND '2012-05-01'
AND batch='DROPOUT'
GROUP BY YEAR(passDate)
ORDER BY YEAR(passDate)
output---
Month total amount
2011 30
2012 20
But my desire out put is
Month total amount
2009 0
2010 0
2011 40
2012 20
I want 0 where count is 0

The easiest way would be to have a table Years, with all the wanted years.
create table Years(yearValue int);
insert into years values (2001), (2002)..., (2020);
then do a left join on your actual table.
SELECT y.yearValue, COALESCE(COUNT(d.id), 0) --assumning you have a field id in dsp_drop_pass_details
FROM years y
LEFT join dsp_drop_pass_details d on y.yearValue = YEAR(d.passDate)
WHERE y.yearValue between 2009 and 2012
GROUP BY y.yearValue
ORDER BY y.yearValue;

Related

MySQL: how to pick a value from one GROUP BY level and broadcast across all levels

I have a MYSQL table like this
person giftaid postcode year amount
A 1 NULL 2010 10
A 0 XY123 2010 15
A 0 NULL 2011 10
A 0 NULL 2011 20
B 0 NULL 2010 20
B 0 NULL 2010 1
B 0 NULL 2011 30
C 1 NULL 2010 50
C 1 AB345 2011 80
And I want to sum the amounts given by each person in each year, but take the giftaid and postcode values for that person from any year. I.e. I need
person ever_giftaided any_postcode year sum
A 1 XY123 2010 25
A 1 XY123 2011 30
B 0 NULL 2010 21
B 0 NULL 2011 30
C 1 AB345 2010 50
C 1 AB345 2011 80
Note that although person A didn't agree to giftaid in 2011, because they agreed in 2010, I'm happy to fill out the ever_giftaided column with a 1 for all years, and take any non-null postcode too.
If I do a simple GROUP BY person, year, and use MAX(giftaid) AS ever_giftaided, MAX(postcode) AS any_postcode, then in the second row, person A gets a 0 for ever_giftaided, and NULL for any_postcode, because the group by clause doesn't transfer information between the groupings by person, but by the groupings of the combinations of person and year. I could simply GROUP BY person, but then I don't get the amounts broken down by year. So how can I do this?
Join two queries. One groups by person, the other groups by person, year.
SELECT t1.person, t1.ever_giftaided, t1.any_postcode, t2.year, t2.sum
FROM (
SELECT person, MAX(giftaided) AS ever_giftaided, MAX(postcode) AS any_postcode
FROM yourTable
GROUP BY person) AS t1
JOIN (
SELECT person, year, SUM(amount) AS sum
FROM yourTable
GROUP BY person, year) AS t2 ON t1.person = t2.person
You can also do one of the groupings in the main query:
SELECT t1.person, MAX(giftaided) AS ever_giftaided, MAX(postcode) AS any_postcode,
t2.year, t2.sum
FROM yourTable AS t1
JOIN (
SELECT person, year, SUM(amount) AS sum
FROM yourTable
GROUP BY person, year) AS t2 ON t1.person = t2.person
GROUP BY t1.person

Group by customer ids in a period of time having count

Im trying to select only ids of customers that have ordered atleast once every year in a specific time period for example 2010 - 2017
example:
1. customer ordered in 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 should be shown
2. customer ordered in 2010, 2011, 2012,2013,2014,2015, 2017 should not be shown
my query counts in all years not within the period
o_id o_c_id o_type o_date
1345 13 TA 2015-01-01
7499 13 TA 2015-01-16
7521 14 GA 2015-01-08
7566 14 TA 2016-01-24
7654 16 FB 2016-01-28
c_id c_name c_email
13 Anderson example#gmail.com
14 Pegasus example#gmail.com
15 Miguel example#gmail.com
16 Megan example#gmail.com
my query:
select c.id, c.name, count(*) as counts, year(o.date)
from orders o
join customer c on o.c_id=c.id
where year(o.date) > 2009
group oy c.id
having count(*) > 7
You need a table with all the years so you can check if user order that year. I create a sample with only two years because that is what in your sample data.
You can use this to create a list of years:
How to get list of dates between two dates in mysql select query
Also I use ranges for years so you can use index at the moment of the join.
If you already have a table users you can replace the subquery
SQL DEMO
SELECT user_id, COUNT(o_id) as total_years
FROM years y
CROSS JOIN (SELECT DISTINCT `o_c_id` as `user_id` FROM `orders`) as users
LEFT JOIN orders o
ON o.`o_date` >= y.`year_begin`
AND o.`o_date` < y.`year_end`
AND o.`o_c_id` = `user_id`
GROUP BY user_id
HAVING total_years = (SELECT COUNT(*) FROM years)
;

I need to join two table in mysql

I need some help to solve an issue with my query. I want to join the output of two select statements:
1st
select extract(year from createdDate) as year,
count(extract(year from createdDate)) as count
from table
where to_user_id= 322
group by extract(year from createdDate);
and its output
Year Count
2014 18
2015 117
2016 9
and 2nd query
select count(extract(year from createdDate)) as count
from table
where userId=322
group by extract(year from createdDate);
and its output
Count
18
110
11
I want to add this two tables into one table.
I want that type of output,
Year Count Count
2014 18 18
2015 117 110
2016 9 11
Note that I use to_user_id in query 1 but userId in query 2.
I tried to solved out this thing but I got repeated values in the output.
Anyone know the solution?
Write them as subqueries and join them together.
SELECT a.year, a.count AS t_user_count, b.count AS user_count
FROM (select YEAR(create_date) AS year, COUNT(*) AS count
FROM table
WHERE to_user_id = 322
GROUP BY year) AS a
JOIN (SELECT YEAR(create_date) AS year, COUNT(*) AS count
FROM table
WHERE user_id = 322
GROUP BY year) AS b
ON a.year = b.year

How to pass parameters in subquery mysql?

So, I have a mysql table with user id(id) and date of transaction(dot) that looks like:
id dot
-------------------------------
101 2015-06-12 12:18:42 UTC
102 2015-06-12 12:18:40 UTC
103 2015-06-12 12:18:42 UTC
101 2015-07-12 12:18:42 UTC
and so on.
(Output for this data should be:
Year Month Num of users
-----------------------------
2015 06 0
2015 07 2
)
It logs all the transactions that are made. For each month m, I want to find out the count of users by month and year who transacted in m-1 month but not in m month. The results need to be grouped by year and month. Ideally, table should look like (http://sqlfiddle.com/#!9/b80f49/1)
Year Month Num of users
-----------------------------
2015 05 0
2015 06 2
2015 07 1
2015 08 4
Now for a single month(E.g. 05/2015), I can hardcode:
SELECT "2015" AS Year,"05" AS Month, "COUNT(DISTINCT id) FROM table WHERE
MONTH(dot)=4 AND YEAR(dot)=2015
AND id NOT IN
(SELECT id FROM table WHERE MONTH(dot)=5 AND YEAR(dot)=2015)
To group the count of users using GROUP BY, the query would look like:
SELECT YEAR(dot) as Year,MONTH(dot),COUNT(DISTINCT id) as Month FROM table
WHERE id NOT IN(SELECT id FROM table
WHERE DATEDIFF(dot_parent,dot_this_table)<30 AND DATEDIFF(dot_parent,dot_this_table)>=0)
Here dot_parent is the dot of the parent query and dot_this_table is the dot of the subquery. Now the problem here is that I can't pass the dot_parent inside the subquery. Is there a way to do that or frame the query in another way such that its logical structure remains similar, since I would have to make similar queries for multiple date ranges.
You must query the same table thrice: once for the months to show, once to find the users in the previous months, once for user matches in the months in question. You'd select distinct users per month, as you are not interested in whether a user had more than one transaction in a month or not.
Here is the complete query:
select
this_month.year,
this_month.month,
count(prev_month_users.user) - count(this_month_users.user) as users
from
(
select distinct year(timing) as year, month(timing) as month
from transactions
) this_month
left join
(
select distinct
year(timing) as year, month(timing) as month, id as user,
year(date_add(timing, interval 1 month)) as next_month_year,
month(date_add(timing, interval 1 month)) as next_month_month
from transactions
) prev_month_users
on prev_month_users.next_month_year = this_month.year
and prev_month_users.next_month_month = this_month.month
left join
(
select distinct year(timing) as year, month(timing) as month, id as user
from transactions
) this_month_users
on this_month_users.user = prev_month_users.user
and this_month_users.year = prev_month_users.next_month_year
and this_month_users.month = prev_month_users.next_month_month
group by this_month.year, this_month.month;
Result:
year month users
2015 5 0
2015 6 2
2015 7 1
2015 8 3
Note that I show three users for August (users 101, 102, 104). User 101 had two transactions in July, but it is still three users who had transactions in July but not in August.
Here is your SQL fiddle back: http://sqlfiddle.com/#!9/b80f49/13

SQL sum aggregate including 0

I have two tables. One is an employee table containing the employee information and the other table is the sales the employee has made. I am trying to group the sum of sales made by an employee in a month including the months where he/she has made zero sales. Here are some of the values in the table
Employees table
number name
1 Matt
2 Foggy
3 Karen
4 Wilson
sales
employee_number month sale_number sale_amount
1 January 2015 1 300
1 January 2015 2 50
1 February 2015 1 400
2 March 2015 1 300
3 January 2015 1 50
I was able to write the query for getting the monthly sales sum using the following query
select sum(sales.sale_amount), sales.employee_number, sales.month, sales.sale_number
from sales group by employee_number, month;
Now because I also need the months including zeros I thought left outer join with the different months should do the trick. However the output still consists of the same output from before without zeros or null. Does the left outer join not join the null values?
The output should be something like this.
number name sale_amount sale_month
1 Matt 350 January 2015
1 Matt 400 February 2015
1 Matt 0 March 2015
2 Foggy 0 January 2015
2 Foggy 0 February 2015
2 Foggy 300 March 2015
and so on.
A left outer join conjures up null values for missing rows from the right hand table. To show all months, you'd switch the order of tables:
from months
cross join
employees
left outer join
sales
on sales.month = months.month
and employees.number = sales.employee_number
If you're missing a months table, you can ad-lib one from the sales table:
select months.month
, employees.name
, sum(sale_amount) as sales
from (
select distinct month
from sales
) as months
cross join
employees
left outer join
sales
on sales.month = months.month
and employees.number = sales.employee_number
group by
months.month
, employees.name
Example at SQL Fiddle.
Following query will help you:
SELECT q1.month, q1.number, q2.total_sales FROM
(SELECT distinct s.month, e.number
FROM sales s, Employees e) AS q1
LEFT JOIN
(SELECT SUM(sales.sale_amount) AS total_sales, sales.employee_number, sales.month, sales.sale_number
FROM sales group by employee_number, month) AS q2
ON (q1.month = q2.month) AND (q1.number = q2.employee_number)
ORDER BY month, number;
check the fiddle