Efficiently charting data by dates - php

I want to display a user's entered information on a time series line graph. ChartJS seems to be a great free way to do this. It needs an array of dates, and an array of the values for those dates.
Say if the user asks for data between two dates, and grouped by the day.
In my database I have a table, and each row has a UNIX timestamp. I can easily call up data and group by a given day, e.g.
SELECT some_metric
FROM tbl_example
WHERE date BETWEEN [start_ts] AND [end_ts]
GROUP BY DAY(FROM_UNIXTIME(date))
I also have a function that can make an array of the days between two dates.
Now the problem is that users don't have data on certain days, so I'll need to amend the array that MySQL spits out so that some days have 0.
Apart from a horrid double nested foreach cross-checking dates in either array is there an efficient way to fix gaps in data in MySQL or PHP?
Update: This seems like a possible solution for handling gaps in time series data on the JavaScript side.
Update: I came up with a relatively simple 20-line solution in PHP. It reformats the array of values that MySQL spits out and for each date does an if (isset(...)) check on that array and then adds 0 for that date.
It does the job for days so far but I'll have to delve a little deeper for it to work with weeks and months.

I would suggest to use this method to generate values for the dates between start_ts and end_ts:
Get a list of dates between two dates
And then UNION with your results.
It would save you the trouble of iterating the results in php...
If you are using some aggregation (e.g. SUM,COUNT) on some_metric, you can generate a new field called some_metric with the generated dates, with NULL or 0 values, and the aggregation would be valid regardless of the existence of records for those dates.

Related

Convert from arbitrary dates to single date format

I've been asked to migrate data from one table to another. The old data includes a series of dates entered in a mishmash of whatever format the user felt like using at the time, the new format requires separate FROM date and TO date fields in MM/YYYY.
So some dates are a single date, such as DD.MM.YYYY or DD/MM/YY or DD YYYY or YYYY or again whatever. Some dates are both dates, such as DD.MM.YYYY-DD/YYYY or DD/MM/YY--DD/MM/YYYY. So just a mess. There are only a couple hundred rows but I don't feel like going through and changing them manually if I can avoid it.
Most of the Google results are for converting one format to another format, how can I convert from a mess of formats to one?
Using a single expression to encompass all combinations is hard so just do the patterns one by one:
UPDATE olddata,newdata
SET newdata.date=STR_TO_DATE(olddate.date, "%d.%m.%Y")
WHERE olddata.id=newdata.id
AND olddata.date REGEXP '[:digit:]{1,2}\.[:digit:]{1,2}.[:digit:]{4}'
AND newdata.date IS NULL
Do this a multiple times for each date format, and use the right expression in STR_TO_DATE. Experiment selecting with the right regulate expression before doing the update.
Eventually you'll have enough record to edit manually

PHP Foreach Loop Query

I've been tinkering with PHP lately (self-taught, no formal training), trying to understand how to grab data from a database and display the data somewhere. So far I have learned quite a bit, but now I am stumped.
I have a list of about 200 users in my local database in a table called site_members. The table has three fields: id, name, birth_date. Via PHP, I want to display all the users on a webpage, and have something like "Birthday soon!" be mentioned right after their name. Something like this:
John Smith (Birthday soon!)
I haven't written the code to do this, because I usually write pseudocode first before actually diving into the coding part. Here's the pseudocode:
Get the current date and time and convert it to Unix timestamp
Start foreach loop and go through list of users
Query the database table, get the birthdate of a user by their id, and store it in a variable named bdate.
Convert bdate to Unix timestamp
Subtract the current date from bdate, convert it into days remaining, and store it in a variable called remaining_days.
If the user's bdate is within 15 days (remaining_days is less than 15)
Display their name, followed by (Birthday soon!)
otherwise
Just display their name only
End if
End foreach loop
Here's my problem: With the above pseudocode once translated into actual code, there would be a database query made every time in that foreach loop. Some of the tutorials I consulted mentioned I should avoid that for efficiency reasons, and it makes sense. I ran Google searches to find something similar, but that didn't do much. I do not want anyone to write any actual code for me. I just want a better solution to the querying.
Thanks in advance!
I think your concept for the pseudo code is right, and you're understanding of doing multiple database queries is also right, you just tangled the two into giving you a wrong idea.
If you construct your select statement properly (that's basically what you'd be using to access the database), you actually pull the information for everyone out of the database and store it once in an array (or some other form of object). You can then start your foreach loop using the array as your value and perform the rest of your checks that way.
$date = date("m.d.y");
$people = ** insert your commands to grab the info from the DB **
foreach($people as $person) {
// do your comparison checks and echo's etc in here
}
Does this make sense?
There can be two solutions to your problem:-
1:
Instead of making query for every user, first get the data for all the users.
Traverse the data using foreach loop php
Do the processing and display the results.
2:
Store the user date_of_birth in proper mysql date datatype
Change your mysql query to use date function to get all the users who match your date difference criteria and just display those users.
It seems you failed to read up properly on the relationship between SQL and PHP. If you actually posted code, then you could have been easily unstumped because there are many ways to do the simple task from legacy tutorials to current PDO or even MVC within in 5mins or less.
I'm not going to write the code but you need to change HOW you think in your "pseudo code".
The problem with your pseudo code is because you believe that the DB is not smart and you are doing it as if it was only for storage.
The correct pattern for PHP is the following:
1) use the Date function to retrieve current day + 15. Get month and
day only.
2) you make a SQL query that retrieve all users who's
birth_date field's month and day are GREATER THAN (or equal) to
TODAY and who are less than or equal to today + 15 (day and month
only)
3) execute the query.
4) with the returned data set (if any)
you can choose two path depending situation and design
a) you can loop it with a simple FETCH which fetch each row retrieve
and display name and extra message.
or
b) iterates through the result set and store the display message
into a variable and then finally display it once the iteration is
done.
(option b is prefered because its more flexible since you can use this technique to out into a file instead of an echo)
THIS pseudo-code ensures that you are only retrieve the correct data set with the aid of the SQL system (or storage system).
In terms of overall process, aashnisshah is absolutely correct. First, you should retrieve all the records you need from your database then loop through each row to do your data comparisons and finally close the loop.
As for finding out if their birthday is close and if you want MySQL to do the hard work, you can build your query like that in PHP:
$query = "SELECT *, DATEDIFF(DATE_FORMAT(dob, '" . date('Y') . "-%m-%d'), CURDATE()) AS days_to_dob FROM Members";
The idea is to fetch an extra column called 'days_to_dob' containing the amount of days until that person's date of birth. Note that it will be negative if that date has passed for this year. With that extra column you can easily evaluate whether their dob is within 15 days.
If you don't want any php code, then here is my pseudocode:
Get date and time -> UTC stamp and store in $time_current
Get all from site_members and store in $data
for each entry in $data, store in $record
get birth_date from $record and convert to utc stamp and store in $birthday
print name from $record
if $birthday is close to $time_current then print "Birthday soon" end if
print new line
end for
That performs only one request to your database.

TYPO3 extbase: order dates by month and day (ignore year)

I have a database containing birthdates. I want to display the next birthdays from now. However, I'm not sure what would be the simplest way to do this. I cannot simply sort the dates, since I need to ignore the year of the date.
Actually, info the action controller, I fetch all the objects from the repository, I extract month and day, I put all data into an array, then I sort the array according to month and day. I was wondering if there would be an easier way to perform this task.
see how I do it in my TYPO3 news extension, https://git.typo3.org/TYPO3v4/Extensions/news.git/blob/HEAD:/Classes/Domain/Repository/NewsRepository.php#l360

I am accessing records of dates: how to assign a value when a particular date is not present?

I want to get data from database regarding dates.
Suppose I want to access data from June,1st to August,1st from my database. If, for example, there are no records for the dates 5,6 and 10 how to assign a count of zero for these dates ?
This is just a simple scenario. If we dont have data for 1 month then how to assign zero for all the days?
AFAI understand your question, you must study Coalesce or IFNULL
You could intitialize an array of dates before you access database, with values for each day in the range of search being zero. Then you fill the values for days that you have in database and rest remain unchanged, as zero.

How to combine Dates/Time selected from Dropdowns to use in MySQL Query?

I've got two sets of four dropdowns - startDate,startMonth,startYear,startTime (as 24.00) and the same for endDate/Time - for user to select a start date/time and an end date/time, but don't know how to get the selected values into a datetime format to use in a recordset query using javascript or preferably php(5).
I know I need to combine the selected into arrays such as:
//start and end Date/Time arrays from dropdowns - year,month,day and time without seconds
$startDT=$sYear.$sMonth.$sDay.' '.$sTime.':00';
$endDT =$eYear.$eMonth.$eDay.' '$eTime.':00';
but where and how do I use these so I can use them in a MySQL a query such as:
SELECT *
FROM availability
BETWEEN '%startDT%' AND '%endDT%'
The answer is probably very simple but after a lot of head scratching, hair pulling and excessive caffeine I just can't work it out...call it a blond moment!
I hope someone can help this suicidal newbie to php.
Combine your data into a string and use strtotime() to convert that to unixtime. Then save that unixtime data into your database.

Categories