How to store previous 30 days and next 30 days data? - mysql

Suppose I have 100 items whose price vary daily. Say today is 11 sep 2017, I want to store price for these 100 items for last 30 days and next 30 days say from 11 Aug 2017 to 11 Oct 2017. If I opt for every date as a column name then I will have 100 rows ( 1 row per Item) and each row will have 60 column ( each column will display data for that day price ). Now after today ends, I have to delete column corresponding to 11 Aug and add column corresponding to 12 Oct. Should I use Cron for this purpose.

If you choose rational database then it is trivial task, you just need to created a table that link product price with date.
One for example:
| productId | day | price |
| 1 | 11-09-2017 | 50.25 |
| 2 | 11-09-2017 | 12.50 |

NO! 60 rolling rows in a table, not 60 rolling columns.
It is easy to INSERT and DELETE a row each day. It is messy to do the same with columns.
The table would have (at least): (date, item_id, price)

Related

Selectively select column data based on date range in MySQL

Is there a way in MySQL to select specific columns based on dates entered as variables?
For example, if there is a table containing daily data from Day 1 to Day 31 for various items. Like the table below -
id
Month
Year
Item
Day 1
Day 2
Day3
Day 4
Day 5
1
December
2021
Bag
2
4
2
5
1
2
December
2021
Pencil
3
5
1
8
2
This goes up to Day 31 if needed for any number of items in the month.
I'd like to be able to enter a date range such as 2021-12-01 and 2021-12-03 along with the item name 'Bag' and get the sum of the values in that data range - 2+4+2 = 8.
Is this possible?
And if it isn't possible with this current method I'm attempting, is there a way to get it done?
Thanks.
This may not be the answer you want, but you should seriously fix your data model. Do not store your dates as columns, but rather store each date's data point in a separate record. So the first record from your sample table would become:
id | Item | Date | num_items
1 | Bag | 2021-12-01 | 2
1 | Bag | 2021-12-02 | 4
1 | Bag | 2021-12-03 | 2
1 | Bag | 2021-12-04 | 5
1 | Bag | 2021-12-05 | 1
Now your query becomes much more tractable:
SELECT id, Item, SUM(num_items) AS total
FROM yourTable
WHERE Date BETWEEN '2021-12-01' AND '2021-12-03' AND Item = 'Bag'
GROUP BY id, Item;
a bit verbose, but you can do something like this :
SELECT
IF (DAY('2021-12-01') <= 1 AND DAY('2021-12-03') >= 1, day1, 0)
+ IF (DAY('2021-12-01') <= 2 AND DAY('2021-12-03') >= 2, day2, 0)
+ IF (DAY('2021-12-01') <= 3 AND DAY('2021-12-03') >= 3, day3, 0)
+ ...
Although it's probably better to change your data model to have a date and value as column.

SSRS - Details with Quarterly Avgs, as well as YTD Avgs across multiple years

So I created a little tablix with a row group for the YEAR_QTR (for example 2021_Q1 we are in today). It shows daily details, then some quarterly averages below. A simple image below of what I'm talking about. I have this all working but what I would like to add is another row underneath for the YTD totals per quarter
So ideally the output would look something like this:
YEAR_QTR | BUSINESS DATE | CREDITS |
2020_Q1 1/15/2020 8
2/1/2020 2
3/16/2020 5
3/22/2020 10
| QUARTERLY AVG | 6.25 | -- just Q1 2020
| YTD AVG | 6.25 | -- just Q1 2020
2020_Q2 4/15/2020 15
5/1/2020 3
5/11/2020 1
| QUARTERLY AVG | 6.33 | -- just Q2 2020
| YTD AVG | 6.29 | -- AVG for both Q1 & Q2 2020
etc....
Is there a way I can create a calculation in that YTD TOTAL bucket, that can allow me to average the data from Jan 1 of that quarters year until that specific quarter? Or will the grouping only have access to the data from that quarter? I was almost thinking something like:
=IIF( BUSINESS DATE BETWEEN 1/1/YEAR AND MAX(of current qtr) then SUM(CREDITS)
Would something like that work or would the data from the other quarters from each year be out of the scope for that grouping?
Any guidance would be greatly appreciated!!

MYSQL - Select query generating a column for each month in date range

I have a request for a report that must return the total qty of items shipped, grouped by item, within a date range. No big deal. BUT they want the report to display one column for each month in the range.
Example: Customer specified start date = 2017-11-15 and end date = 2018-03-14
There is a bunch of columns prior to the month columns, but for the sake of simplicity, I'll use only ITEMCODE in the example. The result should look like the following:
ITEMCODE | NOV 17 | DEC 17 | JAN 18 | FEB 18 | MAR 18
SHIRT123 | 10 | 25 | 33 | 20 | 7
PANTS123 | 5 | 20 | 20 | 18 | 6
I don't even know if it's possible to do this. Note, under each month is the sum of the QTY column.

Mysql: find active users who logged in once a week

I have a table users and another table logins everytime the user log-in into the website we record a row in logins ex.
Users
-----
14 | name1
17 | name2
20 | name3
21 | name4
25 | name5
logins
----
14 | 2015-03-01
14 | 2015-03-07
14 | 2015-03-16
14 | 2015-03-24
14 | 2015-03-30
17 | 2015-03-01
17 | 2015-03-07
17 | 2015-03-16
17 | 2015-03-17
17 | 2015-03-30
20 | 2015-03-01
20 | 2015-03-07
20 | 2015-03-08
20 | 2015-03-16
20 | 2015-03-25
20 | 2015-03-30
if start date is 2015-03-01 and end date is 2015-04-01 then 14 & 20 should be selected while 17 wont be selected since he didn't login in the week of 03-22 to 03-28 so the result would be
Result
------
2
First you get the list of users per week which has logged in at least once, then you count per month the amount of users:
SELECT LoginYear,LoginWeek,COUNT(*) as NumbUsers
FROM (
SELECT Year(logins.date) as LoginYear, Week(logins.date) as LoginWeek, logins.UserID
FROM logins
WHERE logins.date>='2015-03-01'
GROUP BY LoginYear, LoginWeek, logins.UserID
HAVING COUNT(*)>0
) t
GROUP BY LoginYear,LoginWeek;
Week numbering: MySQL can count the weeks in different ways (such as starting on a Sunday/Monday) using the mode: WEEK(date,mode). See the WEEK MySQL documentation.
Update: to get the number of persons which has been logged in at least once every week: first we get the users that were logged in at least once per week in the subquery weektable. Then the users are select which have a week count which equals the total number of weeks in that period (thus having been online each week). Finally we count those users.
SELECT COUNT(*)
FROM (
SELECT UserID
FROM (
SELECT Year(logins.date) as LoginYear, Week(logins.date) as LoginWeek, logins.UserID
FROM logins
WHERE logins.date>='2015-03-01'
GROUP BY LoginYear, LoginWeek, logins.UserID
HAVING COUNT(*)>0
) weektable
GROUP BY UserID
HAVING COUNT(*)>=TIMESTAMPDIFF(WEEK,'2015-03-01',NOW())
) subq;
Note 1: I put the date '2015-03-01' as an example but you can change this or put as a variable.
Note 2: depending on the dates you choose it can be that the week count by TIMESTAMPDIFF is less than the maximum number of weeks (counted by COUNT(*)), since it does not count half weeks. Therefore I put >= in the last line: HAVING COUNT(*)>=TIMESTAMPDIFF(WEEK,'2015-03-01',NOW()).
I cannot test it here at the moment but something like
SELECT COUNT(Users.id) WHERE logins.date>=XXXX AND logins.date<=XXXX GROUP BY Users.id
should work

Find n occurrences within a date range that is within a larger date range

In MySQL, I have a table that records user "actions" (an action can be any number of things: a click, a purchase, etc). The table looks like so, where action_id is unique:
+--------------------------------------------+
| table_actions |
+--------------------------------------------+
| action_id | user_id | date_created |
+-----------+---------+----------------------+
| 1 | 321 | 2011-01-21 06:00:00 |
+-----------+---------+----------------------+
| 2 | 123 | 2011-02-21 06:00:00 |
+-----------+---------+----------------------+
| 3 | 456 | 2011-03-21 06:00:00 |
+-----------+---------+----------------------+
| 4 | 654 | 2011-04-21 06:00:00 |
+--------------------------------------------+
I want to find the number of distinct user_ids that took three actions no more than one year apart within a 30 month date range. My first try was this:
select ta.user_id
from table_actions ta
where ta.date_created > DATE_SUB(now(),interval 30 month)
group by ta.user_id
having COUNT(ta.action_id) > 2 AND DATEDIFF(MAX(ca.created_at),MIN(ca.created_at)) > 364;
This runs just fine, but errors in only checking the difference between a users first and last action. If user's first and last action are 30 months apart, but somewhere in that span of time they took 3 actions in 3 days, they would not be counted by my query.
My research found a few posts on date ranges, but none that looked for a certain number of occurrences within a range within a range.
I'm assuming this could involve a loop or row numbering of some kind, but I've quickly reached the limits of my knowledge.
Update 1:
If a real world example would help:
Jane takes action in March 2010, March 2011, April 2011 and December 2011.
John takes action in January 2010, January 2011, February 2011 and March 2012.
Each have take 3 or more actions in the past 30 months, but only Jane has taken 3 or more actions that fell within a 12 month period inside the last 30 months. I'm looking for a query that returns all the Janes.
Where I'm getting stuck is accounting for the fact that a user can take any number of actions in the past 30 months. If they were limited to only 3 actions, this would be simple. But, I don't know how to take a user who has taken 5 actions in the past 30 months and check if 3 of those actions fell in a year long period.
Hopefully that helps clarify. Thanks everyone.