time difference between two rows - mysql - php

I wanted to know if there is any way where i can calculate time difference between two rows. I want to calculate time difference for name -> test etc. The name can be in any order.
I want to know if test has two times at row 1 and 3 and then at row 7 and 11, can i calculate time difference between these rows? i.e for row 1 and 3, and other for row 7 and 11.
below image with my database

try using TIMEDIFF() and subquery
SELECT TIMEDIFF((SELECT `entered_at` FROM `demo_test3` WHERE `id`='1'),
(SELECT `entered_at` FROM `demo_test3` WHERE `id`='3'))

If you want to check the difference in PHP you can do something like this.
function secondsBetweenRows($first, $second)
{
return strtotime($second->entered_at) - strtotime($first->entered_at);
}
// group rows by users
$users = []
foreach ($rows as $row) {
$users[$row->name] = $row;
}
// check row difference
$timeDiff = [];
foreach ($users as $userName => $userRows) {
// assume there are always to, if not do some checks here
$timeDiff[$userName] = secondsBetweenRows($userRows[1], $userRows[0]);
}
print_r($timeDiff);
/*
Array
(
[test] => 24
[test1] => 26
)
*/

Related

Return 0 if no match found from array with MySQL IN statement

I know there are many similar questions and answers, but none of them are working in this case, as I'm using IN statement to get matches from array and my dates are in varchar data type because of its format. Here it is:
I'm trying to check if array items exists in database and get the count for each of them as an array. My SQL query runs fine and gets the results, but the only problem is that I want it to return 0 for array items that does not exist in a database instead of skipping it.
So for example here is my database table:
postId reactedTo reactedDate
126 Like 22 Jun 2019
172 Haha 24 Jun 2019
172 Wow 27 Jun 2019
132 Like 27 Jun 2019
Here is my function to run the SQL Query and get the results as an array
public function reactionsAnalytics() {
global $wpdb;
$tableName = $wpdb->prefix.'reactions';
$dates = $this->getLastNDays(7); //array('22 Jun 2019', '23 Jun 2019', ... ,'28 Jun 2019');
$reacts = $wpdb->get_results("
SELECT reactedDate, count(*) AS count
FROM {$tableName}
WHERE reactedDate IN ('".implode("','", $dates)."')
GROUP
BY reactedDate
", ARRAY_A);
$result = array();
foreach ($reacts as $react) {
$result[] = $react['count'];
}
wp_die(json_encode($result));
}
The expected outout of this function is ["1","0","1","0","0","2","0"], but I'm getting ["1","1","2"]. How can I prevent the $reacts query from skipping not found items and make it output 0 instead?
I've tried using COALESCE, IFNULL and SUM in various variations but got same results without zeroes.
Here is the SQL Fiddle and you can play with it:
http://sqlfiddle.com/#!9/ffbb98/5
Thanks!
Instead of trying to complicate the query, you simply need to change your application (PHP) code slightly. Get the query results for the dates available in the DB. Now, in PHP code, simply check if the count is available for the date or not. If yes, use the count, else set as zero.
// Change the SQL query result to an array with date as key, and count as value
$reacts_mod = array_combine(array_column($reacts, 'reactedDate'),
array_column($reacts, 'count'));
// Now prepare the $result
$result = array();
// Loop over input dates here
foreach ($dates as $dt) {
// If you have count obtained from the query result, then consider that else 0
if ( isset($reacts_mod[$dt]) ) {
$result[] = $reacts_mod[$dt];
} else {
$result[] = 0;
}
// Note: PHP7 code would be simply:
// $result[] = $reacts_mod[$dt] ?? 0;
}

Algorithm that generates all versions of an array with possible weights assigned 0-100

I have a following array (php):
[
[id=>1,weight=]
[id=>2,weight=]
[id=>3,weight=]
[id=>4,weight=]
]
I need to create all possible versions of this array asigning 0-100 weight to each item['weight'] with a step of N.
I don't know how this type of problems are called. It is NOT permutation/combination.
Lets say N is 10, I am aiming to get:
[
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=10]
[id=>4,weight=70]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=20]
[id=>4,weight=60]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=30]
[id=>4,weight=50]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=40]
[id=>4,weight=40]
]
...all possible combination of weights for id=x.
[
[id=>1,weight=70]
[id=>2,weight=10]
[id=>3,weight=10]
[id=>4,weight=10]
]
]
Sum of 4 item['weights'] in array on same level is always 100 (or 0.1). And inside parent array I've all possible combinations of weights from 10-100 for id=x.
This problem is sometimes described as allocating identical balls into distinct bins. You didn't specify your problem exactly, so I'll take a guess here but the logic will be identical.
I'll assume you're distributing b = N/step balls into 4 bins.
Think of the balls all in a row, and then using 3 bars to separate the balls into 4 bins:
*|||*****.
If N=10 and you're distributing 100 points, the above example is the same is 30, 20, 0, 50. If zeroes aren't allowed, you can reduce the amount you're distributing by 4*b and assume each bin starts out with N/step in it (so you're distributing the leftover points).
The number of ways to do this is choose(balls + bins - 1, bins - 1).
Theres probably a better way, but heres my attempt:
$result=array(); // Empty array for your result
$array=range(1117,7777); // Make an array with every number between 1117 and 7777
foreach ($array as $k=>$v) { // Loop through numbers
if ((preg_match('/[890]/',$v) === 0) && (array_sum(str_split($v, 1)) === 10)) {
// If number does not contain 8,9 or 0 and sum of all 4 numbers is 10
// Apply function to multiply each number by 10 and add to result array
$result[] = array_map("magnitude", str_split($v, 1));
}
}
function magnitude($val) { // function to multiply by 10 for array map
return($val * 10);
}
print_r($result);
Working demo here
EDIT
Sorry I realised my code explanation isn't totally clear and I condensed it all a bit too much to make it easy to follow.
In your example the first array would contain (10,10,10,70). For the sake of simplicity I divided everything by 10 for the calculations and then just multiplied by 10 once I had a result, so your array of (10,10,10,70) becomes (1,1,1,7). Then your final array would be (70,10,10,10) which would become (7,1,1,1).
My approach was to first to create an array containing every combination of these four numbers, which I did in two steps.
This line $array=range(1117,7777); creates an array like this (1117, 1118, 1119 ... 7775, 7776, 7777) (My number range should really have been 1117 - 7111 instead of 1117-7777).
Applying str_split($v, 1) to each value in the loop splits each 4 digit number in the array into another array conatining 4 single digit numbers, so 1117 will become (1, 1, 1, 7) etc
As each of your items can't have a weight below 10 or above 70 we use (preg_match('/[890]/',$v) === 0) to skip any arrays which have 0,8 or 9 in them anywhere, then array_sum(str_split($v, 1)) === 10) adds up the four digits in the array and only returns arrays which total 10 (you wanted ones which total 100, but I divided by 10 earlier).
array_map applies a function to each element in an array. In my example the function multiplies each value by 10, to undo the fact I divided by 10 earlier.
When you say is it possible to alter steps, can you give me a couple of examples of other values and the output you want for them?
If you want a totally different approach and using mysql isn't a problem then this also works:
Create a new table with a single row. Insert all the values you need to check
INSERT INTO `numbers` (`number`) VALUES
(10),
(20),
(30),
(40),
(50),
(60),
(70);
Then your php looks like this
$result=array();
try {
$dbh = new PDO('mysql:host=aaaaa;dbname=bbb', 'ccc', 'dddd');
foreach($dbh->query('SELECT *
FROM numbers a
CROSS JOIN // A cross join returns the cartesian product of rows
numbers b // so every row with every combination of the other rows
CROSS JOIN
numbers c
CROSS JOIN
numbers d
ON
a.number = b.number OR a.number != b.number') as $row) {
if (($row[0] + $row[1] + $row[2] + $row[3]) === 100) {
$result[] = $row;
}
}
$dbh = null;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
print_r($result);

Undefined index error on key that has been declared

I am building a leaderboard (scorebored) for a poker tournament. My aim is to echo data to a table to display scores for the season and scores all time. I want the table to run in order with the highest season points at the top.
I am getting an error message that reads:
Notice: Undefined index: season in C:\wamp\www\UPT Site\leaders.php on line 11
When I print_r an array from the $allplayers array, it shows that all the players arrays are going in correctly, including the [season] key and value declared on line 6 in the bit below...
Can anyone please tell me how to fix my code? (note, the real code doesn't have line numbers in it, I just added them here to make discussion easier).
1 foreach($allplayers as $player){
2 $i = $player[1];
3 if (${"seasonplayerid" . $i}){
4 $sum = array_sum(${"seasonplayerid" . $i});}
5 //$sum = points this season.
6 ${"playerid" . $i}['season'] = $sum;
7 }
8 function val_sort($array,$key) {
9 //Loop through and get the values of our specified key
10 foreach($array as $k=>$v) {
11 $b[] = strtolower($v[$key]);
12 }
13 asort($b);
14 /* foreach($b as $k=>$v) {
15 $c[] = $array[$k];
16 }return $c;
17 */
18 }
19 $sorted = val_sort($allplayers, '[season]');
20 foreach($allplayers as $player){
21 $i = $player[1];
22 echo ("<tr><td>" . $player[0] . $t . ${"playerid" . $i}[3] . $t . ${"playerid" . $i}[4] . $t. ${"playerid" . $i}['season'] . $t. count(${"seasonplayerid" . $i}). "</td><tr>");
23 }
Here is the print_r output for array $playerid1:
Array ( [0] => Jonathan Thompson [1] => 1 [2] => 2015-S 3 [3] => 944 [4] => 7 [season] => 470 )
Here is a key of the information in the array:
/*
$allplayers is a multidimentional array, containing many arrays of players called $playerid1, $playerid2, $playerid3 etc
playerid1[0] = Player name
playerid1[1] = Player ID
playerid1[2] = Current season
playerid1[3] = total points earned
playerid1[4] = total games played games
playerid1[season] = points earned in current season
*/
Looks like at line 19 you are trying to pass key in second parameter but defined it incorrectly.So, to call function val_sort($array,$key) you have to do something like that.
Therefore at line 19 change
$sorted = val_sort($allplayers, '[season]');
to
$sorted = val_sort($allplayers, 'season');
Also i suggest you to use data table it is good and fast
Instead of below line
$sorted = val_sort($allplayers, '[season]');
you should pass the key as below
$sorted = val_sort($allplayers, 'season');
Hope this helps.
I did a dodgy quick fix in this instance.
I wrote a loop to array_pop each array inside the main array, and created a new variable for each piece of data as the array_pop loop was going.
I also array_pushed the data I wanted to sort by and an ID number to a new array.
I used rsort to sort the new array, then looped through it using the ID number to reconstruct a 3rd array in the order I wanted to output data.
Next time I will take the advice of #rocky and do a data table. I may even go back to redo this page as a data table. To be honest, I'd never heard of a data table before yesterday. Once I've given this project over to the boss I'll be investing my time in learning about data tables and AJAX.
Thank you all for your tips, but the quick fix will have to do this time as I am time poor (This site needs to be live tomorrow morning).

Possible to pull random entry from array and keep schedule?

Not sure if this is possible with just php or if I'd need something else too. Basically I'd like to have an array with a bunch of entries, such as:
(1234,5432,5678,5899,3245)
And I'd like to have the php randomly select one entry from the array AND stick to that entry it selected for 3 days. So for example, on a given date, it would pull "5432" from the array, then it would hold that entry for 3 days, then after 3 days it would pick another entry and hold it for 3 days, etc.
Any ideas how this could be done? Can it be done with just php? Thanks so much for any help.
Assuming you're running a PHP program (command line), and not running a script on a web server you can run this script to stay on all the time and wait to draw.
$entries = array( 34534, 435, 345 );
while(1) {
// subtract 1 from total number of entries because arrays start at an index of 0.
$totalNumberOfEntries = sizeof( $entries ) - 1;
// if no entries left, quit the program
if ($totalNumberOfEntries <= 0) break;
// grab a random index from your array using `mt_rand()` function
$entry = $entries[ mt_rand(0, $totalNumberOfEntries - 1) ];
// write the entry to a file
file_put_contents( 'entry.txt', $entry, FILE_APPEND );
// wait 3 days to draw again
sleep( 3600 * 24 * 3 );
}

Need array to contain all 12 keys for the 12 months in loop even if month is not found

I understand basic arrays but when they get more advanced I get a little lost. Can someone help me with the following code and array?
I am storing my DB query into an array. If all 12 months are not in the DB then that is all that is stored (as it should). However, my problem is that I need the array to have all 12 keys so I can print this out.
// Example amounts
0, 0, 0, 0, 5.23, 0, 0, 158.35, 0, 0, 0, 0
Basically if it does not exist I should still be able to print out zero for that month.
Here is my code:
$closedsales = mysqli_query($mysqli, "SELECT MONTH(date) as month, sum(amount) as total FROM sales WHERE user_id = '".$userid."' AND status = 'S' GROUP BY MONTH(date)");
while ( $row = mysqli_fetch_assoc($closedsales) ) {
$monthlysales[$row['month']] = $row['total'];
}
foreach($monthlysales as $key => $amount) {
echo "$amount <br />";
}
Prefill your result array:
$monthlysales = array_fill_keys(range(1, 12), 0);
Then run your loop, which will replace the elements with the rows from the table. If a row is missing from the table, it will have the initial 0 value.
$allmonthlysales = array_fill_keys(range(1, 12), 0);
foreach($monthlysales as $month => $sales){
$allmonthlysales[$month] = $sales;
}
var_dump($allmonthlysales);
Prepare and array with keys 1-12 and 0 as value meaning months with no sales.
Merge the array with months that have sales with the empty one built above.
And you got what you need...

Categories