Time Machine for Business Intelligence (PHP/MySQL) - php

Currently I am developing a time machine for a open-source Business Intelligence software from scratch using PHP/MySQL.
My time-machine table is used by all other tables that need date info (such as orders, products, etc.) and they binding with time_id. So its MySQL table like this:
time_id | timestamp | day | week | month | quarter
1 1303689654 25 17 4 2
2 1303813842 26 17 4 2
...
Order table binding like this:
order_id | time_id ...
3123 2
...
edit: it's similar to STAR SCHEMA.
The problem is getting TIME (13:45) information as well. Usually I don't need this, but like orders, and sometimes a couple of tables need this HOUR/MINUTE infomation.
How can I solve this problem cleverly? I have a couple of solutions, but first i want to see your opinions..

Why don't you simply store timestamps in your other tables?
Or, if you want to keep the dates table, simply add a TIME field to your other tables which need it.

If I understand your timestamp correctly, you can probably just go:
echo date('H:i.s',1303689654);
edit
What are you trying to do? After re-reading your question you may be looking for the JOIN keyword in SQL (brief tute)

Related

Create view from live stats

I created a sistem to input results from a school basketball tournament. The idea is that after the game the operators will input the result in a format that the system fetches to save in the db in a format like the one below:
Date | Team | Score 1Q | Score 2Q | Score 3Q | Score 4Q | Score OT | Final Score | W | L | Won over Team | Lost to Team | Regular Season? | Finals?
I created a PHP page that calculate many stats from the table above, like Total Wins, Win%, Avg Points, Avg. Points per Quarter, % Turn Around Games when loosing on Half Time or 3Q, % Finals games disputed, Times became champions etc, and many more deep stats.
But I was thinking in creating a View with this information calcalated on the DB and in real time, instead of having the script handles it.
But how can I turn the selects needed from the first table into a working second table with all calculations done whenever we make the selection?
Thanks
#decio, I think your idea about creating a view to calculate those stats is not a bad idea. You might be able to do so with the something similar to the following SQL script:
CREATE VIEW result_stats_view AS SELECT SUM(W) as total_wins, SUM(L) as total_losses FROM precalculate_stats_table_name;
This shows the total wins and losses for the season, but you probably get the idea. Check out MySQL aggregate functions (like average, sum, etc.) here:
https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html
Once you have your calculations added to the view then you can simply do query like this to get your calculated data:
SELECT * from result_stats_view

MySQL using RegEx to update/select columns

I searched in the internet for an answer to select every columns that matches regex pattern. I didn't find one, or maybe I did, but I didin't understand it, because I'm new to DataBases. So here's the sql I was trying to run:
UPDATE `bartosz` SET 'd%%-%%-15'=1
(I know it's bad)
I have columns like:
ID | d1-1-15 | d2-1-15 | d3-1-15 | d4-1-15 ... (for 5 years, every month, and day)
So is there a way to select all columns from 2015?
I know i can loop it in php so the sql would look like:
UPDATE `bartosz` SET 'd1-1-15'=1, 'd1-1-15'=1, 'd3-1-15'=1 [...]
But it would be really long.
Strongly consider changing your approach. It may be technically possible to have a table with 2000 columns, but you are not using MySQL in a way that gets the most out of the available features such as DATE handling. The below table structure will give better flexibility and scaling in most use cases.
Look into tables with key=>value attributes.
id employee date units
1 james 2015-01-01 2
2 bob 2015-01-01 3
3 james 2015-01-02 6
4 bob 2015-01-02 4
With the above it is possible to write queries without needing to insert hundreds of column names. It will also easily scale beyond 5 years without needing to ALTER the table. Use the DATE column type so you can easily query by date ranges. Also learn how to use INDEXes so you can put a UNIQUE index on the employee and date fields to prevent duplication.

Structuring a database table with many columns for spreadsheet import; possibility to scale

A client wants to be able to import a fairly hefty spreadsheet of data (to my eyes, at least) on a monthly basis. At the moment it consists of around 200 rows, and 41 columns.
The first two columns are identifiers (an ID and a human-readable name for a location); the next 39 columns are all numerical values. These numbers are effectively 'ratings' that are split into 39 categories - however the client has just hinted that they may want to expand these categories in the future.
My initial thoughts were to create a database structure that imitates the spreadsheet (so, 41 columns, essentially) - however with the potential for the client to want to add to it later, I don't know if that's the best method to approach this with.
I'm not a classically-trained coder; I've just picked things up as I've needed to, so the more straightforward the solution, the better. I have considered perhaps serializing an associative array on a per-location basis:
----------------------------------------------------------
ID Name Data Date
----------------------------------------------------------
1 Newport {niceness:1, staff:6.5, etc.} Mar 13
2 Stobart {niceness:7, staff:3.1, etc.} Mar 13
----------------------------------------------------------
...but I don't know if that's the best approach, or if it will necessarily work the way I envisage. The idea being that, if March '13 only has 39 categories, but July '13 has 42 categories, then the database structure won't have to be affected; just a different associative array stored.
This kind of thing would also potentially(?) remove the possibility for column mismatch errors when importing the table - for example, if they suddenly decide to drop a category without warning, then try importing an spreadsheet that's a column short.
Things of note:
I am developing this is a Wordpress plugin, so the database table structure is written in there and would be fairly straightforward to update, thanks to WP's dbDelta function.
I'm also looking to use Matt Kruse's PHP ExcelReader, which in my initial tests appears to be excellent.
I would split tables into names, categories and a link-table called *names_categories* (or similar)
table Names
----------------------------------------------------------
ID Name Date
----------------------------------------------------------
1 Newport Mar 13
2 Stobart Mar 13
table Categories
----------------------------------------------------------
ID Category
----------------------------------------------------------
1 niceness
2 staff
table names_categories (link-table)
----------------------------------------------------------
id_name id_category value
----------------------------------------------------------
1 1 1
1 2 6.5
2 1 7
2 2 3.1
This would give you more flexibility. Even if your solution works, it's not that flexible and could be hard to do maintenance of the database in future.

Altering thousands of records every page refresh

I am starting to think about my new project and I've found a couple of speed issues, so I hope you can help me with selecting a good and elegant way to code it.
Each user has in the database records of "places" he has visited. Each place has "schools" - a number of schools in this particular place. Each school has classes. Each class may end its "learning year" at different times, so it's number should increment if date is >= end of learning year.
So we have such a database:
"places" table:
place | user_id |
-----------------
1 | 4 |
2 | 4 |
User no 4 visited place no 1 and 2
"schools" table:
school | place |
----------------
5 | 2 |
6 | 2 |
Place 2 has two schools - with id 5 and 6.
"class" table:
class | school | end_learning | class_number
---------------------------------------------
20 | 5 | 01.01.2013 | 2
21 | 5 | 03.01.2013 | 3
22 | 5 | 05.01.2013 | 4
School 5 has 3 classes with ids 20, 21, 22. If date is greater than 01.01.2013, the class number of class 20 should be incremented to 3 and end learning date changed to 01.01.2014. And so on.
And now we got into the problem - if there is 1000 places, each with 100 schools, each with 10 classes we got 1000000 records. It's a lot. Because all I have presented is just a simple example I have to consider updating whole database every time user refreshes the page so I'm afraid it might be laggy on that amount of records.
I also can serialize class into one field in school table:
school | place | classes
-------------------------------------------------------------------------
5 | 2 | serialized class 20, 21, 22 with end_learning field and class number
6 | 2 | other serialized classes from school 6
In that case I get 10 times less records but each time I have to deserialize data, check dates and if it's less than now alter it, serialize and save to database. The second problem is that I have to select all records from db to manipulate them not only all those need to be altered.
I am also thinking about having two databases: One with records that might need change in further future, and second that might need change in next 24hrs (near future). Every 24hrs all the classes which end learning in next 24 hrs are moved to "near future" db so every refresh of the page works on thousands of records, not hundreds of thousands or millions. Instead of that it works on millions of records (further future) to create "near future" table only once per day.
What do you think about all those database schemas? Maybe you have a better idea?
I don't quite understand the business logic or data model you outline - but I will assume you have thought this through.
Firstly, RDBMS solutions like MySQL are really, really good at managing large numbers of records, as long as the data you are working with is relational. As far as I can tell, you will be searching across many records, but only updating a few (a user will only be enrolled in a limited number of classes); I don't see this as a huge problem.
Secondly, it's nearly always better to go with the "standard" relational model until you can prove it doesn't meet your performance needs than to go for "exotic" solutions at the start off (I class your serialization and partitioning solution as "exotic" for the purpose of this answer). A lot of time and energy has gone into optimizing performance of SQL; if there were a simple alternative, it would be part of the standard solution. There are, of course, points at which the standard relational model doesn't scale (Facebook-size traffic, for instance), or business domains where the relational model doesn't really fit (documents, graphs). However, all the alternatives have benefits and drawbacks just like "standard" MySQL.
Thirdly, the best way to deal with possible performance issues is, well, to deal with them. In code. Build a test rig, create a schema according to the relational model, populate it with test data (e.g. using DbMonster), throw some load at it (e.g. using JMeter) and tune your schema and queries to prove your situation doesn't fit the standard solution. Only go for something exotic if you really can prove that you can't play nice with standard, relational database stuff.

Mysql query to average time

I play a lot of board games and I maintain a site/database which keeps track of several statistics. One of the tables keeps track of various times. It's structure looks like this:
gameName (text - the name of the board game)
numPeople (int - the number of people that played)
timeArrived (timestamp - the time we arrived at the house we are playing the game)
beginSetup (timestamp - the time when we begin to set up the game)
startPlay (timestamp - the time we actually start playing the game)
gameEnd (timestamp - the time the game is finished)
Basically, what I'm wanting to do is use these times to get some interesting/useful info from (like what game on average takes the longest to set up, what game on average takes the longest to play, what game is the longest from arrival to finish, etc...) Normally, I rely way too much on PHP and I would just do a select * ... and grab all the times then do some PHP calculations to find all the stats but I know that MySQL can do all this for me with a query. Unfortunately, I get pretty lost when it comes to more complex queries so I'd like some help.
I'd like some examples of a couple queries and hopefully I can figure out other average time queries once someone gets me started. What would the query look like for longest time on average to play a board game? What about quickest game/time to set up on average?
Additional Info:
drew010 - You have me off to a great start but I'm not getting the results I'd expected. I've give you some real exmples...
I've got a game called Harper and it's been played twice (so there are two records in the database with time entires). Here are what the times look like for it:
beginSetup(1) = 2012-07-25 12:06:03
startPlay(1) = 2012-07-25 12:47:14
gameEnd(1) = 2012-07-25 13:29:45
beginSetup(2) = 2012-08-01 12:06:30
startPlay(2) = 2012-08-01 12:55:00
gameEnd(2) = 2012-08-01 13:40:32
When I then run the query you provided me (and I convert the seconds into hours/minutes/seconds) I get these results (sorry, I don't know how to do the cool table you did):
gameName = Harper
Total Time = 03:34:32
...and other incorrect numbers.
From the numbers, the Average Total Time should be about 1 hour and 24 minutes - not 3 hours and 34 minutes. Any idea why I'd be getting incorrect numbers?
Here is a query to get the average setup time and play time for each game, hope it helps:
SELECT
gameName,
AVG(UNIX_TIMESTAMP(startPlay) - UNIX_TIMESTAMP(beginSetup)) AS setupTime,
AVG(UNIX_TIMESTAMP(gameEnd) - UNIX_TIMESTAMP(startPlay)) AS gameTime,
AVG(UNIX_TIMESTAMP(gameEnd) - UNIX_TIMESTAMP(beginSetup)) AS totalTime,
FROM `table`
GROUP BY gameName
ORDER BY totalTime DESC;
Should yield results similar to:
+----------+-----------+-----------+-----------+
| gameName | setupTime | gameTime | totalTime |
+----------+-----------+-----------+-----------+
| chess | 1100.0000 | 1250.0000 | 2350.0000 |
| checkers | 466.6667 | 100.5000 | 933.3333 |
+----------+-----------+-----------+-----------+
I just inserted about 8 test rows with some random data so my numbers don't make sense, but that is the result you would get.
Note that this will scan your entire table so it could take a while depending on how many records you have in this table. It's definitely something you want to run in the background periodically if you have a considerable amount of game records.
For something like how long it took to set up you could write something like:
SELECT DATEDIFF(HOUR, BeginSetup, StartTime) -- in hours how long to set up

Categories