I have 3 tables of data stored in a database each containing a date and a time field. I'm pulling all the relevant data from each table and concatenating them to an array. I now need to sort the array on date first and then time. I'm currently sorting by date at that works fine but the time sometimes can be right and is sometimes wrong
What I'm currently using to gather the data:
$results = [];
$sql_assign = mysql_query("SELECT * FROM `tk_assign` WHERE ticket_id = $tk_id");
$sql_update = mysql_query("SELECT * FROM `tk_update` WHERE ticket_id = $tk_id");
$sql_status = mysql_query("SELECT * FROM `tk_status_change` WHERE ticket_id = $tk_id");
while($row = mysql_fetch_assoc($sql_assign)){
$results[] = $row;
}
while($row = mysql_fetch_assoc($sql_update)){
$results[] = $row;
}
while($row = mysql_fetch_assoc($sql_status)){
$results[] = $row;
}
What I'm using to sort it
$orderByDate = $my2 = array();
foreach($results as $key=>$row)
{
$my2 = explode('/',$row['date']);
$my3 = explode('/',$row['time']);
$my_date2 = $my2[1].'/'.$my2[0].'/'.$my2[2];
$orderByDate[$key] = strtotime($my_date2);
}
$sorted = array_multisort($orderByDate, SORT_ASC, $results);
I've thought about turning it into timecodes but that hasn't worked either. Any help would be greatly appreciated
Example time and date:
Date: 22/09/2015 Time: 15:32:12
Date: 22/09/2015 Time: 14:50:28
Date: 25/09/2015 Time: 12:21:58
I think this line is wrong:
$my3 = explode('/',$row['time']);
It probably should be:
$my3 = explode(':',$row['time']);
In any case, you're not even using the $my3 variable in your sorting algorithm.
Here's another solution. Just after merging the arrays, add the following code:
for ($i =0; $i < count($results); $i++){
$results[$i]['datetime'] = $results[$i]['date'].' '.$results[$i]['time'];
}
function compareDateTime($a, $b) {
$mya = new DateTime();
$mya->createFromFormat('d/m/Y H:i:s', $a['datetime']);
$myb = new DateTime();
$myb->createFromFormat('d/m/Y H:i:s', $b['datetime']);
if ($mya == $myb)
return 0;
if ($mya > $myb)
return 1;
return -1;
}
usort($results, 'compareDateTime');
If you are using PHP > 5.2 then you should use following way.
$orderByDate = $my2 = array();
foreach($results as $key=>$row)
{
$myDateTime = DateTime::createFromFormat('d/m/Y', $date);
$newDateString = $myDateTime->format('Y-m-d');
$orderByDate[$key] = strtotime($newDateString." ".$row['time']);
}
$sorted = array_multisort($orderByDate, SORT_ASC, $results);
Related
Hey I made an API in PHP from my MySQL database, It is rather CPU intensive and is being called multiple times a second.
$timer = $candle_time * 60;
$DATABASE_HOST = '';
$DATABASE_USER = '';
$DATABASE_PASS = '';
$DATABASE_NAME = '';
$response = array();
$link = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME);
$query = "SELECT * FROM table WHERE name LIKE 'name' ORDER BY table.datetime ASC";
$result = mysqli_query($link, $query);
while ($row = mysqli_fetch_row($result)) {
$dates .= $row[1]. ',';
$price .= $row[2]. ",";
$datetime .= $row[3]. ',';
}
$dates = explode(",",$dates);
$price = explode(",",$price);
$datetime = explode(",",$datetime);
for($i = 0; $i < count($dates); $i++){
array_push($response,array(strtotime($datetime[$i]),$dates[$i],$price[$i]));
}
$counting_segments = 0;
$grouped_prices = array();
$final_grouping = array();
$rounded = ceil($response[0][0]/$timer)*$timer;
$counted = count($response)-1;
for($i = 0; $i < count($response); $i++){
if($i == $counted){
$rounded = ceil($previous_time/$timer)*$timer;
array_push($final_grouping,array($rounded,$grouped_prices));
}
if($response[$i][0] > $rounded){
$previous_time = $response[$i][0];
array_push($final_grouping,array($rounded,$grouped_prices));
$grouped_prices = array();
$rounded = ceil($response[$i][0]/$timer)*$timer;
}
if($response[$i][0] < $rounded){
$previous_time = $response[$i][0];
array_push($grouped_prices,$response[$i][2]);
} else {
array_push($grouped_prices,$response[$i][2]);
}
}
$new_array = array();
for($i = 0; $i < count($final_grouping); $i++){
$first_array = $final_grouping[$i][0];
$second_array = $final_grouping[$i][1];
$first_price = $second_array[0];
$last_price = end($second_array);
$high_price = max($second_array);
$low_price = min($second_array);
$final_date = $first_array;
$obj = new StdClass;
$obj->time = $final_date;
$obj->open = $first_price;
$obj->high = $high_price;
$obj->low = $low_price;
$obj->close = $last_price;
array_push($new_array,$obj);
}
$json_api = json_encode($new_array);
echo $json_api
I think the reason for the 503 is the CPU power it is taking to calculate the requests. Is there a way I can have a script or something that pulls the data and saves it to a php file every second to lessen the load or is there a better way of doing this?
I did run this personally and it works perfectly, however with more people requesting from it it provides a 503 often.
Thanks.
The PHP code itself doesn't look like it should overload the CPU. However, there are a lot of things you can do to optimize it
How's the query performing. Execute the query directly and see if you need to add an index. This could be an index on 2 fields: name and datetime.
You're using specific columns date, price, and datetime, but you're getting all rows in the response. It's better to specify the columns you want
SELECT `date`, `price`, `datetime` FROM table WHERE name LIKE 'name' ORDER BY table.datetime ASC
You're building up comma-separated strings and then splitting them right after. That's unnecessary. Instead build-up arrays.
while ($row = mysqli_fetch_row($result)) {
$dates[] = $row[1];
$price[] = $row[2];
$datetime[] = $row[3];
}
In this case, you don't even need separate arrays, but can just build-up $response in the fetch loop.
while ($row = mysqli_fetch_row($result)) {
$response[] = array(strtotime($row[1]), $row[2], $row[3]);
}
P.S. Don't use array_push() unless you care about the inserted index. The $array[] = $value syntax is faster.
Just count once, not every iteration in the loop
$counted = count($response);
for($i = 0; $i < $counted; $i++){
if($i == $counted - 1){
I have set up an array called $compData by importing data from MySql and pushing two separate arrays called $yearsArray and $salesArray into $compData. Before pushing these two arrays to $compData I have first set their ['name'] to 'Year' and 'Sales', respectively. The code for this is included below.
$sth = mysqli_query($conn, "SELECT * FROM {$tableName} WHERE ID = 'ID_YEAR'");
$yearsArray = array();
$yearsArray['name'] = 'Year';
while($r = mysqli_fetch_array($sth)) {
For ($n = 1; $n <= $CI_YEARS; $n++){
$yearsArray['data'][] = $r["Year$n"];
}
}
$sth = mysqli_query($conn, "SELECT * FROM {$tableName} WHERE ID = 'IS_SALES'");
$salesArray = array();
$salesArray['name'] = 'Sales';
while($rr = mysqli_fetch_assoc($sth)) {
For ($n = 1; $n <= $CI_YEARS; $n++){
$salesArray['data'][] = $rr["Year$n"];
}
}
$compData = array();
array_push($compData,$yearsArray); // 0
array_push($compData,$salesArray); // 1
Now I want to access and echo the data in $compData by using the code below, but this doesn't work. I am not very comfortable with PHP and am wondering if I am not using the ['Year'] and ['Sales'] identifiers correctly. Any help is much appreciated.
foreach($compData['Year'] as $result) {
echo $result, '<br>';
}
foreach($compData['Sales'] as $result) {
echo $result, '<br>';
}
You've set 'Year' as the value of key 'name', but try to use it as key (of another array).
Now you have
echo $compData[0]['name']; // -> 'Year'
echo $compData[1]['name']; // -> 'Sales'
You probably want
$compData = array();
$compData['Year'] = $yearsArray;
$compData['Sales'] = $salesArray;
instead of the array_push..
I want to show the result like this: -
[{"date:Jul-25","value:1"},{"date:Jul-24","value:0"},{"date:Jul-23","value:1"}]
But it show like this:
[{"value":"1"},{"Date":"Jul-25"},{"value":"0"},{"Date":"Jul-24"}]
Please help.
function get_new_member()
{
global $db_conn;
$data = array();
for ($i=0; $i<= 14; $i++)
{
$key = date('M-d', mktime(0, 0, 0, date("m"), date("d")-$i, date('Y')));
$date1 = date('Y-m-d', mktime(0,0,0,date("m"),date("d")-$i,date("Y")));
$sql=<<<EOF
SELECT count(*) as count
FROM crm_members
WHERE REGISTER_DATE ='{$date1}'
EOF;
$sql_res = mysqli_query($db_conn,$sql);
$row = mysqli_fetch_array($sql_res);
$numRows = $row['count'];
$data[]['value'] = $numRows;
$data[]['Date'] = $key;
}
}
This might help:
try doing:
$data[$i]['value'] = $numRows;
$data[$i]['Date'] = $key;
this will assign your values under same array variable
You have another Array in each recod try this
$data = array('value'=>$numRows,'Date'=>$key);
I have a list of clients who have many appointments in db. I want to iterate through the appointments totalling their duration for each client so I can create an invoice. When I run the below code the first client's appointments duration are added correctly. However my issue is, for the next client it seems to add the first clients duration too. Is array_sum the correct method?? What do i need to use if not?
foreach($clients as $client)
{
$appointments = Client::find($client->id)->appointments()->get();
foreach($appointments as $appointment)
{
$date1 = $appointment->starts_at;
$date2 = $appointment->ends_at;
$start = Carbon::parse($date1);
$end = Carbon::parse($date2);
$length = $start->diffinhours($end);
$duration[] = $length; //is this correct?
$total = array_sum($duration); //is this correct?
}
$invoice = new Invoice;
$invoice->total_hours = $total;
dd($invoice);
$invoice->save();
}
Reset the duration for each client and array_sum after the appointment loop:
foreach ($clients as $client)
{
$appointments = Client::find($client->id)->appointments()->get();
$duration = array();
foreach ($appointments as $appointment)
{
$date1 = $appointment->starts_at;
$date2 = $appointment->ends_at;
$start = Carbon::parse($date1);
$end = Carbon::parse($date2);
$length = $start->diffinhours($end);
$duration[] = $length;
}
$total = array_sum($duration);
$invoice = new Invoice;
$invoice->total_hours = $total;
dd($invoice);
$invoice->save();
}
Yes you can use this method, but you need to move it outside the loop and also you should empty $total with each iteration:
....
$duration = [];
foreach ($appointments as $appointment)
{
$date1 = $appointment->starts_at;
$date2 = $appointment->ends_at;
$start = Carbon::parse($date1);
$end = Carbon::parse($date2);
$length = $start->diffinhours($end);
$duration[] = $length;
}
$total = array_sum($duration);
....
Also, you could add start_at and end_at timestamps to the $dates array in a model and use this code instead:
foreach ($appointments as $appointment)
{
$duration[] = $appointment->starts_at->diffInHours($appointment->ends_at);
}
I'm creating an array in PHP to send back to the front end for display in a Flot line chart. I have data that should be displayed year to date by month. If my SQL statement doesn't find any values for a given month, there is no array element for that month, and the Flot chart doesn't plot a data point for that month (See Mar and Apr in screenshot below). I'd like it to show a zero data point for months where there is no data.
Here's how I'm creating my array:
$array = array();
$array['data'] = Array();
$array['label'] = $tags[0]['tag_name'];
foreach($tags as $key=>$value) {
$month = $value['month'];
$arr = Array($month, $value['trans_amount']);
array_push($array['data'], $arr);
}
Current output:
{"data":[[1,"75.00"],[2,"170.00"],[5,"100.00"]],"label":"example label"}
Desired output:
{"data":[[1,"75.00"],[2,"170.00"],[3, "0"],[4, "0"],[5,"100.00"]],"label":"example label"}
and here's how the chart currently displays with the current output:
This works. It's a slight modification of your foreach loop. You need an extra variable $monthVal keep track of the current month.
//Assuming this the month uptil which you want the data.
$current_month = 7;
$monthVal = 1;
foreach($tags as $key=>$value) {
$month = $value['month'];
if($month != $monthVal){
while($month != $monthVal){
$array['data'][] = Array($monthVal, "0");
$monthVal += 1;
}
}
$arr = Array($month, $value['trans_amount']);
array_push($array['data'], $arr);
$monthVal += 1;
}
//This loop is added to append the array if the last entry is not equal to $current_month.
while($monthVal <= $current_month){
$array['data'][] = Array($monthVal, "0");
$monthVal += 1;
}
This should work. What I do is check if there is a missing months and then populate that month with zero as value.
$currMonth = 1;
foreach($tags as $key=>$value) {
$month = $value['month'];
if($month != $currMonth){
//if we are missing some months populate that month with zero as value
while($month != $currMonth){
array_push($array['data'],Array($currMonth, "0"));
$currMonth++;
}
}
$arr = Array($month, "'" . $value['trans_amount'] . "'");
array_push($array['data'], $arr);
$currMonth++;
}
echo json_encode($array);
I would change your SQL query to return more data, if it is stored as a date.
Try to maintain dates as dates rather than integers. PHP and SQL date functions are extensive and useful.
This simple for loop will fill the array with the missing data from the SQL query before the foreach.
for($i=1;$i<=12;$i++){
if(!isset($tags[$i])){
$tags[$i]['month'] = $i;
$tags[$i]['trans_amount'] = 0;
}
}
foreach($tags as $key=>$value) {
$month = $value['month'];
$arr = array($month, $value['trans_amount']);
array_push($array['data'], $arr);
}
Try this (works in PHP 5.3+):
$array = array();
$month_min = $month_max = 0;
foreach($tags as $value) {
$month = $value['month'];
$array[$month - 1] = array($month, $value['trans_amount']);
$month_max = $month;
if (!$month_min) $month_min = $month;
}
$months = array_values(array_map(function ($v) { return intval($v['month']); }, $tags));
$months_range = range(1, $month_max);
foreach (array_diff($months_range, $months) as $month) {
$array[$month - 1] = array($month, 0);
}
$result = array(
'data' => array_slice($array, $month - 1),
'label' => $tags[0]['tag_name'],
);
print_r(json_encode($result));