I have to do a SQL query for getting the incomes of a company on all the months of the year, but some months dont have records in the table.
I have used this query:
SELECT COUNT(wp_dgl_stats.datetime_stamp)*wp_dgl_ads.price as incomes, MONTHNAME(wp_dgl_stats.datetime_stamp) as month
FROM wp_dgl_ads
INNER JOIN wp_dgl_stats ON wp_dgl_stats.id_ad = wp_dgl_ads.id
WHERE YEAR(wp_dgl_stats.datetime_stamp) = 2015
GROUP BY MONTHNAME(wp_dgl_stats.datetime_stamp)
I have to say that wp_dgl_stats contains a record for every click made by an user in certain spaces of the web (the ads showed) with a reference to the ad and a datetime stamp.
This query returns exactly months with incomes and the exact amount. But I need to get also the rest of the months with a 0.
How could this be done?
After a lot of tests I got a proper solution. I will post it here if someone needs for it with an explanation.
SELECT meses.month, CAST(COUNT(stats.id)*ads.precio AS UNSIGNED) as precio
FROM
(
SELECT 1 AS MONTH
UNION SELECT 2 AS MONTH
UNION SELECT 3 AS MONTH
UNION SELECT 4 AS MONTH
UNION SELECT 5 AS MONTH
UNION SELECT 6 AS MONTH
UNION SELECT 7 AS MONTH
UNION SELECT 8 AS MONTH
UNION SELECT 9 AS MONTH
UNION SELECT 10 AS MONTH
UNION SELECT 11 AS MONTH
UNION SELECT 12 AS MONTH
) as meses
LEFT JOIN wp_dgl_stats stats ON meses.month = MONTH(stats.datetime_stamp)
LEFT JOIN wp_dgl_ads ads ON stats.id_ad = ads.id AND YEAR(stats.datetime_stamp) = '2015'
GROUP BY meses.month
Because I am a spanish developer and I need to have spanish month names I selected the month number and with an PHP array we can convert the month number to his spanish name.
If someone have some question, do it, I will be glad to answer.
You could LEFT/RIGHT join on the months:
WITH monthnames AS (SELECT <something that returns a list of the month names> as monthname)
SELECT COALESCE(COUNT(wp_dgl_stats.datetime_stamp)*wp_dgl_ads.price, 0) as incomes, MONTHNAME(wp_dgl_stats.datetime_stamp) as month
FROM wp_dgl_ads
INNER JOIN wp_dgl_stats ON wp_dgl_stats.id_ad = wp_dgl_ads.id
RIGHT JOIN monthnames ON month = monthname
WHERE YEAR(wp_dgl_stats.datetime_stamp) = 2015
GROUP BY MONTHNAME(wp_dgl_stats.datetime_stamp)
Related
This question already has answers here:
MySQL how to fill missing dates in range?
(6 answers)
Closed last year.
It was hard to find a good title for my question.
I have 3 tables: materials, orders and order_contents.
There are 5 different types of materials in the materials table
The orders table contains the dates for the orders. Orders currently span over 4 months.
The orders are filled with materials in the table called order_contents.
I am trying to get the overall cost per month for materials and display them in a highchart.
Here's the query I run:
SELECT m.name, CONCAT(MONTH(o.order_date), '/', YEAR(o.order_date)) as `month`, SUM(oc.weight * m.price) AS cost
FROM order_contents oc
INNER JOIN orders o ON oc.order_id = o.id
INNER JOIN materials m ON oc.material_id = m.id
GROUP BY MONTH(o.order_date), m.id
ORDER BY m.name, order_date ASC
Here are the results:
The problem is that if a material isn't used in a particular month, it won't generate a record for it (obviously). So when I loop through the results and try to form the hightable data series, it won't fill a month with zero. For example, the material Big Bag is only consumed in January 2022, but since it's the only entry in the data series, it maps with the first month, which is August. I can add logic to fix this problem but I thought I'd ask here first if there is a way to reformat this query to yield the results I'm looking for.
Here's what I'd like to get:
I'm way out of my league here on SQL capabilities for this sort of problem.
Here is a (probably wired) idea:
For a SQL table:
create table temp
(
month int,
year int,
name varchar(16), -- something like material-type
count int,
)
We could run:
select const_year.year, const_month.month, const_name.name, ifnull(count, 0)
from (select 1 month union
select 2 union
select 3 union
select 4 union
select 5 union
select 6 union
select 7 union
select 8 union
select 9 union
select 10 union
select 11 union
select 12) const_month -- now we have a list contains 12 months
left join (select 2020 year union
select 2021 union
select 2022 ) const_year
on true -- now we have a table contains all months between those years
left join (select distinct temp.name as name
from temp) const_name
on true -- join with all distinct names/types
left join (select temp.name as name, temp.year as year, temp.month as month, sum(count) as count
from temp
group by temp.year, temp.month, temp.name -- here is the real query for statistic
) statistic
on statistic.year = const_year.year
and statistic.month = const_month.month
and statistic.name = const_name.name
order by name, year, month -- order results if we need
I think there definitely have more better solution than this. Though it's working for some case.
Hi Have written a query for taking count of register users of all months in a year
SELECT MONTH(c1.created_on) AS MONTH,
(SELECT COUNT(c2.id)
FROM register AS c2
WHERE c2.created_on <= (DATE_FORMAT(DATE_ADD(c1.created_on,
INTERVAL 1 MONTH),'%Y-%m-01')))
AS registeruser
FROM (SELECT 3 AS mon UNION
SELECT 4 AS mon UNION
SELECT 5 AS mon
) AS m LEFT JOIN
register AS c1
ON MONTH(c1.created_on) = m.mon
GROUP BY MONTH(c1.created_on)
So created_on column datatype is DateTime and default value i have set is CURRENT_TIMESTAMP, So when I register a user, current month is april and i add 4 values after that i change month of 1 user to march and execute the query it gives me count as
for Month April as 4 and march as 1 .
Here I am facing the problem for April still it giving me 4 which should be 3
Here in image, I have changed the data, but looking at it will understand the month of April the count it is showing as 4, this only happens when i change the timestamp after added record
Your query does not count how many users registered each month.
It counts how many registered up to that month, because the condition is:
WHERE c2.created_on <= DATE_FORMAT(.....
You should group by m.mon and not by MONTH(c1.created_on) because MONTH(c1.created_on) may be null if the month does not exist and there is no need for the subquery:
SELECT
m.mon AS MONTH,
COUNT(c1.created_on) AS registeruser
FROM (
SELECT 3 AS mon UNION
SELECT 4 AS mon UNION
SELECT 5 AS mon
) AS m
LEFT JOIN register AS c1
ON MONTH(c1.created_on) = m.mon
GROUP BY m.mon
I have a simple piece of SQL code where I am trying to get the monthly averages of numbers. But the problem I am running into is if any number within any given month is 0 then the average returned is 0 or if there are any rows that don't exist with any given month then there are no values returned at all for that month. Hopefully, someone can give me some insight as to what I am doing wrong.
GROUP BY 1 = a.metric and GROUP BY 2 = a.report_dt within the subquery
I have tried inserting the missing rows with a value of 0, but as I said it will return the averaged value as 0 as well.
SELECT a.report_dt - INTERVAL 1 DAY AS 'Date',
a.metric,
a.num
FROM (SELECT *
FROM reporting.tbl_bo_daily_levels b
WHERE b.report_dt = reporting.func_first_day(b.report_dt)
AND b.report_dt > DATE_SUB(NOW(), INTERVAL 12 MONTH)
GROUP BY 1,2
)a;
My expected results are to get the average numbers of each month even if there are non-existent rows within the specified date range or even if there zeroes as values.
You need a relation of all the months you want to span. This can be made ad hoc with UNION ALL. Then left join the data on the months GROUP BY the month and the metric and get avg(num).
SELECT m.year,
m.month,
l.metric,
coalesce(avg(l.num), 0)
FROM (SELECT 2017 year,
12 month
UNION ALL
SELECT 2018 year,
1 month
UNION ALL
SELECT 2018 year,
2 month
...
SELECT 2018 year,
11 month
UNION ALL
SELECT 2018 year,
12 month) months m
LEFT JOIN reporting.tbl_bo_daily_levels l
ON year(l.report_dt) = m.year
AND month(l.report_dt) = m.month;
GROUP BY m.year,
m.month,
l.metric;
(Change the second parameter to coalesce if you want any other number than 0 if there are no numbers for a month. Or don't use coalesce() at all if you want NULL in such cases.)
I am trying to create a query for a bar-chart which displays a monthly overview of the number of orders.
The query I am using is correctly providing me with the breakdown per month but when I skipped a month, it is not providing a 0 for that month, just doesnt add it at all.
Since this chart is expecting 12 numbers, everything after the missing month would be off an inaccurate.
Current Attempt:
select Month(dateCreated) as monthID,
Monthname(dateCreated) as monthName,
count(dateCreated) as totalRewards
from reward
where Year(dateCreated) = '2018'
GROUP BY monthID
If we were to assume that it is currently May 2018, I would like to see Jan - May, current counts even if the month had no orders (April = 0).
Whats the best way to include all months that have happened so far in the provided year and then their appropriate count?
You can mock a months table, then LEFT JOIN the reward table against it. To ensure you only get valid results, it's best to use a SUM() where not null rather than a COUNT() aggregate:
SELECT
months.id as monthID,
MONTHNAME(CONCAT('2018-',months.id,'-01')) as monthName,
SUM(CASE WHEN dateCreated IS NULL THEN 0 ELSE 1 END) as totalRewards
FROM
(
SELECT 1 AS id
UNION SELECT 2
UNION SELECT 3
UNION SELECT 4
UNION SELECT 5
UNION SELECT 6
UNION SELECT 7
UNION SELECT 8
UNION SELECT 9
UNION SELECT 10
UNION SELECT 11
UNION SELECT 12
) as months
LEFT JOIN reward
ON MONTH(reward.dateCreated) = months.id
AND YEAR(dateCreated) = '2018'
GROUP BY monthID, monthName
ORDER BY monthID;
SQL Fiddle
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
So I got two Mysql tables and I'm having a hard time doing following query.
Query: Get the the sales value per month, per city
users
id, name, city
sales
*id, user_id, name, amount, date (datetime)*
I started with SELECT MONTHNAME(datetime) AS month GROUP BY month.
Thanks in advance!
Assuming you want a figure of 0 for any month and / or city which doesn't have any sales, but where there are sales for other cities for that month then something like this:-
Cross join a pair of subselects, one to get a list of the months used and one to get a list of the cities, then join those against the records to get the amounts for that month / city, and sum those amounts up:-
SELECT Sub1.YearMonth, Sub2.city, SUM(sales.amount)
FROM (SELECT DISTINCT EXTRACT(YEAR_MONTH FROM `date`) AS YearMonth
FROM sales) Sub1
CROSS JOIN (SELECT DISTINCT city FROM users) Sub2
LEFT OUTER JOIN sales ON Sub1.YearMonth = EXTRACT(YEAR_MONTH FROM sales.`date`)
LEFT OUTER JOIN users ON sales.user_id = users.id AND Sub2.city = sales.city
GROUP BY Sub1.YearMonth, Sub2.city
ORDER BY Sub1.YearMonth, Sub2.city
Down side of this is that if you have a month where nothing was sold to anybody then this month will not appear at all. To get around this you would need to change the subselect for the months to instead take a start date and add a range of numbers to it to get each month.
An example of generating a range is as follows:-
SELECT Sub1.YearMonth, Sub2.city, SUM(sales.amount)
FROM (SELECT EXTRACT(YEAR_MONTH FROM DATE_ADD('2009-01-01', INTERVAL a.i*100+b.i*10+c.i MONTH)) AS aMonth
FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a,
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b,
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c
WHERE DATE_ADD('2009-01-01', INTERVAL a.i*100+b.i*10+c.i MONTH) <= '2014-12-01') Sub1
CROSS JOIN (SELECT DISTINCT city FROM users) Sub2
LEFT OUTER JOIN sales ON Sub1.YearMonth = EXTRACT(YEAR_MONTH FROM sales.`date`)
LEFT OUTER JOIN users ON sales.user_id = users.id AND Sub2.city = sales.city
GROUP BY Sub1.YearMonth, Sub2.city
ORDER BY Sub1.YearMonth, Sub2.city
This example is giving every month between 2009-01-01 and 2014-12-01 inclusive, then getting all the sales by city for that range. It will cope with a range of up to 1000 months.
Hey noob (nice name btw) :D
Try this one, I've added the YEAR() on the GROUP BY clause since month numbers are repeating per year, and I suppose you do not want the sum of sales of records with the same month but different in year. You can just omit the year on the SELECT statement if you do not want it.
SELECT YEAR(S.date) AS Year
, MONTHNAME(S.date) AS Month
, U.city
, SUM(S.amount) AS SalesPerMonthPerCity
FROM sales S
INNER JOIN users U ON U.id = S.user_id
GROUP BY YEAR(S.date), MONTH(S.date), U.city
You have an SQL Fiddle test page so you and others can try the solution.
This is the query in question:
SELECT MONTHNAME(`date`) AS Monthly
, `city`
, SUM(`amount`) AS Profit
FROM sales
INNER JOIN users ON userid = idu
GROUP BY MONTHNAME(`date`), `city` WITH ROLLUP
Used the WITH ROLLUP to add a subtotal by month and a grand total at the end.
PS: I agree with the comments, you should show some more effort on solving your problem, you are not new on SO so you should be aware of that ;)