How do I add skipped dates on Report? - mysql

How do I add skipped dates on my report so there is no gap in time, an example
I have this:
1/1/16: 10 sales
1/3/16: 4 sales
1/7/16: 11 Sales
1/8/16: 8 Sales
I want this:
1/1/16: 10 sales
1/2/16: No sales
1/3/16: 4 sales
1/4/16: No Sales
1/5/16: No Sales
1/6/16: No Sales
1/7/16: 11 Sales
1/8/16: 8 Sales
I'm working with Visual Studio 2012 and Oracle

Regardless of which RDBMS you're using, a popular method is to either have a date table, or create a temporary table with dates in it, and join that table to whatever table has your data. For example,
SELECT [datetable].[date], [SalesTable].[NumberOfSales]
FROM [datetable]
LEFT JOIN [SalesTable] ON [SalesTable].[Date] = [datetable].[date]
will show you what you're looking for, assuming [datetable] contains every date.

I would suggest loop date-range via your programming code instead of SQL left join

Its always best to use a calendar table while reporting. Create a calendar table with all the dates and formats. Then you can join the calendar table and result view to get all dates and values.

Related

Grouping Sales into non-calendar months

I am working on a database which includes sales information; the table for this is fairly basic:
ContractID(PK), CustomerID(FK), SalesAgent(FK), Value(int), SalesDate(Date)
And I have a requirement to produce a monthly sales report - sounds simple; group the dates by month.
However, the client has a non-calendar monthly sales structure - effectively, most months are 28 days, December is 42 days, and April & August are 35 days - this means that all months start on a Monday, and the extra weeks are allocated to Easter, High Summer, and Christmas, when business is usually slower.
So effectively I have a calendar like this:
Month. StartDate, EndDate
1. 20210104, 20210131
2. 20210201, 20210228
3. 20210301, 20210328
4. 20210329, 20210502
5. 20210503, 20210530
6. 20210531, 20210627
7. 20210628, 20210725
8. 20210726, 20210829
9. 20210830, 20210926
10. 20210927, 20211024
11. 20211025, 20211121
12. 20211122, 20220102
13. 20220103, 20220130
14. 20220131, 20220227
etc.
What's the best way to allocate each sale to a period above to group for reporting - I was initially thinking of having the above table as a CTE within my query, then SELECT based on the SalesDate being before and after the start and End Dates in the above, but what join do I then use to link that to the main query?
Is there no way around this other than to run the query for each specific period as listed above, or can this be done with a UNION?
(hope this makes sense)
Join your sales data and calendar, template
with calendar(Month, StartDate, EndDate) as(
..
)
select ..
from calendar
join sales on sales.date between calendar.StartDate and calendar.EndDate
group by .. calendar.Month ..

Trying to calculate the total amount of sales for each branch since the start of the year

I'm currently trying to solve a problem where I'm trying to calculate the total amount of sales for each store branch since the beginning of the year, within the database I've created.
I have tried to write a query that returns the result from one store e.g London, however, there are a few more branch_ids e.g. Manchester, Cardiff etc... At the moment it only returns the London store however I'm stuck on how to also print out the other branch_ids so all branch_ids display the total turnover for each individual store.
SELECT branch_id,
date_sale,
sum(cost_order)
FROM Customer_Orders
WHERE branch_id like '%London%'
AND date_sale >='2019-01-01';
I would use this version:
SELECT
branch_id,
SUM(cost_order) AS total
FROM Customer_Orders
WHERE date_sale BETWEEN '2019-01-01' AND '2019-12-31'
GROUP BY
branch_id;
Note that it does not make sense to include the date_sale field in your select clause, because each record in the output actually corresponds to multiple dates of sale. Also, I use BETWEEN to express the year 2019, because writing it this way is SARGable, meaning that an index on date_sale can be used.

A query to calculate registered users per day in a range of 3.5 months

I have a table called "users" where users register and the date of registration is saved as "created_on".
I am looking to write a query that displays how many users have registered on our website daily from 1st of March 2017 till 15th of June 2017.
Unfortunately I can not.
A result that shows like this:
Date Count
01-03-2017 232
02-03-2017 422
03-03-2017 531
...
This problem is a good example of where a calendar table would come in handy. In the query below, I assume that there exists a table containing all the dates from 1st March 2017 until and including 15 June 2017. An inline form of this table would look something like this:
SELECT '2017-03-01' AS Date UNION ALL
SELECT '2017-03-02' UNION ALL
-- ...
SELECT '2017-06-15'
Assuming you have a calendar table, you can just left join it to your current table to get the counts:
SELECT
c.Date, COUNT(t.created_on) AS signup_count
FROM calendar c
LEFT JOIN yourTable t
ON c.Date = t.created_on
GROUP BY Date
Note that a calendar table may be necessary here, because there could be days where no one signed up. In this case, your original table itself does not contain enough information to generate the output you expect.
SELECT created_on,COUNT(*)
FROM users
WHERE created_on BETWEEN '2017-03-01' AND '2017-06-15'
GROUP BY DATE(created_on)
Try above query.
Hope this will help you.

Need a MySQL query to obtain dates not registered in a table

I have a little problem with a specific functionality. I have a table of reservations for rooms.
Table: Reservations
room (BIGINT), date (DATE)
4, 2012-09-25
4, 2012-09-27
4, 2012-09-30
I need to obtain the dates when room with id = 4 is available between a date range. For example, if i want the dates that the room is available between 2012-09-25 and 2012-10-01 (inclusive) i have to obtain the next result:
date (DATE)
2012-09-26
2012-09-28
2012-09-29
2012-10-01
Any help will be appreciated. Thanks in advance.
This sort of query is easily handled if you add a table of dates to your database. Fill it with a large number of dates (and add to it when you need to), and just do a right outer join to it to find the missing dates.
If you can't or don't want to add an additional table, you can convert the dates to integer field (representing the number of days since Jan 1, 1970) with this:
SELECT room, UNIX_TIMESTAMP(`date`)/86400 FROM reservations
From there, you can use the techniques in this question or elsewhere to look for gaps in that sequence.
As #steven-cheng said, i had to use the combination of mysql and code because creating a temporary table is too messy. Using the code to get the dates that are available is faster.

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)