I'm trying to come up with a database structure to account for products that are available on certain days of week and on certain weeks ( odd / even )
An example:
- product1 is available for selling Mondays in odd weeks
- product2 is available everyday on even weeks
- product3 is available on weekends
I thought of isolating the availability in a second table with the product as fk and each condition on a separate row like so:
fk_prod1 weekday 1
fk_prod1 weekparity 1
fk_prod2 onweekday 1
fk_prod1 weekparity 0
In this form I don't know how I would get the products that are available for today, for the rest of the week and next week.
Any suggestions are welcome :)
Queries are also much appreciated!
This may help out :) Might needed adjusted depending on your circumstances with the program but heres an idea:
Table 1: Products
This could hold ProductID, ProductName
So a row could look like this: 1, product1
Table 2: ProductDayMatrix (ProductDayID,ProductDay)
1,Monday
2,Tuesday
3,Wednesday
4,Thursday
5,Friday
6,Saturday
7,Sunday
Table 3: ProductWeekMatrix (ProductWeekID, ProductWeek)
1 = odd weeks
2 = even weeks
or like
1, Week1
2, Week2
3, Week3
4, Week4
Finally then Table 4:
Product Matrix: (ProductID,ProductDayID,ProductWeekID)
This could hold your products and their corresponding data. So you would insert data into this table with your information and it would look like this.
(1,4,2) = Product 1, On a Thursday, on the even weeks.
Or if things need multiple conditions have 2 different tables that would hold the day information.
Like: ProductAvailablityMatrixDay & ProductAvailabilityMatrixWeek
Then those could hold mulitple values for each so if product 1 was on monday and thursday you could insert: (1,1) & (1,4). Then reading from that table would tell you that product 1 was on day 1 and 4. Same goes with the weeks.
Would it be worth considering an approach similar to the way cron jobs are structured?
Your day of the week will always be 1-7
Your week of the month will always be 1-6
So using LIKE would give 0 possible conflicts where 1 could be matched to 10 for example as you won't ever have 2 digits.
So if your product1 it could be:
day = 1
week = 1,3,5
For product2 it would be:
day = 1,2,3,4,5,6,7
week=2,4,6
For product3 it would be:
day=6,7
week=1,2,3,4,5,6 (September this year spans 6 different weeks)
The your queries would be something like:
Today:
"SELECT * FROM availability WHERE day LIKE '%".date("N")."%' AND week LIKE %".(date("W")-date("W",strtotime("first day of the month")))."%'";
// this is using some PHP to get the week of the days of the week and week of the month.
Tomorrow:
"SELECT * FROM availability WHERE day LIKE '%".date("N",strtotime("tomorrow")."%' AND week LIKE %".(date("W",strtotime("tomorrow"))-date("W",strtotime("first day of the month")))."%'";
// this again is using some PHP to get the week of the days of the week and week of the month - you can achieve the same with just MYSQL but I'm more familiar with PHP to give you an idea.
I'm not saying its perfect but unless your going to do more with these rows I don't think the use of foreign keys is going to help you? Hope that helps?
Related
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 ..
I'm in need of some help structuring in-time queries. There's a few of them I need - but I think that if I can be shown how to do one, I can figure out the others.
What I'm after:
-Rolling 12 month view of 'inactive accounts'...ie number of accounts that have not placed an order in the 12 months prior.
-This ideally will be a subquery (in a much larger script) joining back on to a dates table (see below)
January 2015 | # of customers with no orders from 1/2014-1/2015
February 2015 | # of customers with no orders from 2/2014-2/2015
March 2015 | # of customers with no orders from 3/2014-3/2015
etc...
What I'm having trouble wrapping my mind around is how I'd structure a where clause to ensure that it scans all orders and only returns the total of account ID's that had not placed an order in the year prior to that month. I've used different combinations of DATEDIFF, DATESUB etc.
SELECT DATE_FORMAT(order_datetime, '%Y-%m'), COUNT DISTINCT (account_id)
FROM warehouse.orders
JOIN warehouse.accounts ON xyz
WHERE...
It feels like I'm on the right path - I just keep mentally going in circles trying to figure this out.
Cheers and thanks in advance.
I don't have enough reputation points to simply comment on your question. I don't fully understand it though.
Are you using SQLServer/TSQL or MySQL?
Do you want to have just one column which calculates the last 12 months' rolling average or 12 columns for the rolling average each month? If it is just one figures for the last 12 months tolling do you want that to be from the current day or the beginning of that month?
If it was SQL Server and a rolling 12 months to now, the calculation could be:
SELECT SUM(CASE WHEN DATEDIFF(y,GETDATE(),order_date_time) < 1 THEN COUNT(DISTINCT account_id) END) as January2015
If you're using MySQL replace GETDATE() with NOW()
If you want one value rolling but to the beginning of the month then you could use:
SELECT SUM(CASE WHEN DATEDIFF(y,DATEADD(M, DATEDIFF(M, 0, GETDATE()), 0),order_date_time) < 1 THEN COUNT(DISTINCT account_id) END) as January2015
If I've missed the point entirely, please let me know and I'll happily amend the answer
You should query between dates, in order to get the count of events for each id.
select case
when count(account_id)<0 then 'INACTIVE'
when count(account_id)>0 then 'ACTIVE'
from warehouse.orders
where data_format(order_datetime, '%m/%Y') between '1/2014' and '1/2015'
group by account_id)
I have a table
PEOPLE, DATE, DELETED
Amanda, 2015-03-01, Null
Ray, 2015-03-01, Null
Moe, 2015-04-01, Null
Yan, 2015-05-01, Null
Bee, 2015-05-05, 2015-06-12
now I need to group it and sum it with months like this:
March: 2 people
April: 3
May: 5
June: 5
July: 4
so new people should not be counted in previous month but they should be in next months for my range (January - June). And if man is DELETED, he should be counted together with another people last time in month when he has been deleted.
How to write query for this?
This can be at least solved using running totals. This just the outline how to do it, you'll need to do some work for the actual solution:
select people, date, 1 as persons from yourtable
union all
select people, deleted, -1 as persons from yourtable where deleted is not null
Then do a running total of this data, so that you sum the +-1 persons -field, and that should give you the amount of people that are there so far.
For the events happening in the middle of the month, you'll have to adjust the date to be the start of that or the next month whichever way you want them to be calculated.
If you need also those months when no changes happened, you'll probably need a table that contains the first day of each month for the biggest range of dates you'll ever need, for example 1.1.2000 - 1.12.2100.
I'm a little lost on how I should do this any help or guidance would be appreciated. I have a table that has 3 columns with multiple values inserted into it basically a log_book table of events. We can say there is an order_id, event_status, and datetime. I need to get the difference of days between the datetime columns and sum them together where order_id=? and event_status=? I know how to limit my queries to get the data I want. But what would be the best way to get the difference in days and add them together. Essentially there could be only one entry with the same order_id and event_status or there could be multiple entries with the same order_id and event_status.
Event Status codes
1 = initially assigned
2 = submitted for review
3 = sent back for more work
because 2015-01-01 to 2015-01-15 is 15 days
and 2015-01-17 to 2015-01-18 is 1 day
so the total days would be: 16 Days
I'm using MySQL Workbench to run my query.
I want to run a couple of different date queries, I don't know if it's possible in SQL.
1) Run the report from the first date in the system to X date.
How can I find what the first orderID or date is as part of the calculations?
I know that if I have the date to begin with, I can use:
where T5.date_purchased BETWEEN '2005-01-01' AND '2015-12-31' OR:
where T5.date_purchased BETWEEN '2005-01-01' AND CURDATE() + INTERVAL 1 DAY
UPDATE
----- Query 2 has been answered (although open to any improvement) -----
2) Run the report from the first time a product shows up, to + 6 months (to see it's first 6 months of order) ie: Widget 1 (first order) + 6 months from order date. Something like:
where widget=widgetID AND date between widget1's first purchase and +6 months
Update: This doesn't work, however this is somewhat of what I was thinking:
where (T3.products_id = 39) and DATE_ADD((T1.products_date_added), INTERVAL 1 MONTH)
I would use my P3.products_date_added, however, I don't know how to use it as part of the above, correctly.
Are either of these possible, I know how to pull the records when I know the date, I just don't know if it can be done with 'date unknown' or if I have to run a "pre-report" first. Or is it a post processing filter in excel?
Thank you in advance.
Answering problem #2:
2) Run the report from the first time a product shows up, to + 6 months (to see it's first 6 months of order) ie: Widget 1 (first order) + 6 months from order date. Something like:
where widget=widgetID AND date between widget1's first purchase and +6 months
Answer:
-- Use for specific comparisons of products OR for the first X months of sales
where (T3.products_id = 39) and T5.date_purchased between T1.products_date_added and DATE_ADD((T1.products_date_added), INTERVAL 2 MONTH)
-- This results in PID: release: 10th July, +2 months; 10th Sep. 31 units.
OR
-- (T3.products_id = 11 or T3.products_id = 39) gives the results of the 2 product orders from release date to the first 2 months of each
-- (T3.products_id) gives all products, their first 2 months of release
-- (T3.products_id = 39) gives specific product release sales
-- Inspired by: http://stackoverflow.com/questions/28788691/mysql-range-between-dates-first-order-6-months?noredirect=1#comment45853546_28788691
If it is possible for your solution, try and run 2 separate queries:
- ONE for finding the date of first order
- then calculate +6 months from query 1 result
- AND the second one to get the purchases BETWEEN both dates