Finding the differences between two rows of data, key by key - php

I have two rows of data - always just two rows, but there could be a maximum of around forty columns. The column names are different on a case by case basis, but here is a representative example:
id | height | width | colour | in_stock | featured | on_sale
------------------------------------------------------------
1 | 30 | 20 | black | yes | no | yes
2 | 30 | 25 | red | yes | yes | no
I want to get all of the differences between those two rows into an array so that I can log what was changed from row 1 to row 2.
I thought it array_diff() would do the job!
So I cheerfully chucked array_diff() at it thus:
//Simplified queries for the example
$sql1 = "SELECT * FROM table WHERE id = 1";
$rs1 = $conn->Execute($sql1);
$rs1 = $rs1->fields;
$sql2 = "SELECT * FROM table WHERE id = 2";
$rs2 = $conn->Execute($sql2);
$rs2 = $rs2->fields;
//Build first array
foreach($rs1 as $key => $value){
$data1[$key] = $value;
}
//Build second array
foreach($rs2 as $key => $value){
$data2[$key] = $value;
}
//Find the differences
$theDifferences = array_diff($data1, $data2);
//Loop through the differences logging the changes
foreach($theDifferences as $field => $value){
echo "Change found for ".$field."!";
}
Why that doesn't work.
This "looked like" it was working. Since many columns contain long strings, colour names, dates etc, so when one changed it was duly pushed into the differences array. The problem was (of course) that the multiple "yes" or "no" columns did not behave as I had expected. Thus the result of the code above, for the table example is:
colour, width
It is not "seeing" the featured or on_sale columns as changed because the data1 array AND the data2 array both contain no's and yes's.
I suppose I need to compare on a key by key basis? Something like the opposite of array_diff_key()? But here I am stuck.
I also considered if this could be done solely with the SQL query, which would I suppose be more efficient, but that is way beyond my SQL ability.
Thanks in advance.

I think you're very nearly there. Maybe something like this after your queries:
$theDifferences = array();
foreach($rs1 as $key => $value){
if ($rs2[$key] != $value){
$theDifferences[$key] = $value;
}
}
As for SQL, you can use an EXCEPT to get a list of rows which are different between two queries, but you'd still have to loop through the keys and look for nulls - which doesn't save you a whole lot.

Related

How can i get one id result and add it to another in a mysql table?

How can I record all data in a table together?
i have values in individual rows that i wish to add up to one. and get the value into a variable.
what can i use instead of this code below to get all id in the table instead of one?
if(isset($_GET['ide'])){
$coode = $_GET['ide'];
so that once i get all id, i can do the query below...
$products = $db->query("SELECT e1,e2 FROM eyfstb WHERE specialnum='$coode'");
while($row = $products->fetch_assoc()){
$e1view = $row["e1"]; $e2view = $row["e2"];
}
and once the query is done, i want to be able to store them in a variable like below
$final = (e1,e2 of id1) + (e1,e2 of id2) + (e1,e2 of id3) + (e1,e2 of id4);
fine is 5
good is 4
fair is 3
my e1 is fine which is equal 5
my e2 is good which is equal 4
making 9 when i added it.
but i want to get for all record rows in the table
currently i'm able to get the details for only one student from the url $coode but i want to get for all the student from a table and be able to add the resulting data.
Table Structure
id | e1 | e2 |
---------------------------
1 | fine | good |
2 | good | good |
3 | fair | fine |
Better way is to store in database parameters like this as integer. It generates less problems with math operations or comparison.
But if you can't refactor it you should map each value to their numerical equivalent.
function mapDbValue(string $value): int {
switch ($value) {
case 'fine': return 5;
case 'good': return 4;
case 'fair': return 3;
}
}
And now in your while loop map values and add it.
$final = 0;
while (...) {
$final += mapDbValue($row['e1']) + mapDbValue($row['e2']);
}

Is it okay use the same variable name on PHP while?

I just wondering is it okay if I use the following code :
$query = mysqli_query($db, "SELECT * FROM myTable1")
while($result = mysqli_fetch_assoc($query)){
$temp = $result['id'];
}
Then I fetch another table like this :
$query = mysqli_query($db, "SELECT * FROM myTable2")
while($result = mysqli_fetch_assoc($query)){
$temp = $result['id'];
}
I use the same variable $result and $temp.
I mean is it okay to use such code ? Should I named the variable differently like $result1 $result2 and so on ?
Let's say, which one is better, safer, between use the same variable name or give the variables different name ?
I hope someone could explain about it.
Thank you before.
If you follow SOLID principle, especially the single responsibility principle wants you to isolate functionality into different function.
If you do apply this, then you are not really using the same variables, because at that point there would be in different scope, therefore it would not be an issue.
In short you shouldn't have to reuse variables, if your logic is broken up into function that perform a single task, please do not name them $result1, result2 etc ... this is a sign of code smell in your project.
If you are done with myTable1 then it is totally ok but if you are going to use it somewhere else in code then no because only myTable2 information will be saved in $result
if you use same variable to store your data then every iteration the variable value will be override with new value, and the value after while statement is the last iteration.
$temp is a local variable to the while if you haven't defined it before so it is safe to be used like that.
$query, from what the language lets you do, yes you can use it this way.
Basic PHP code
Let's say you want to store some information from database into variable and then use it before doing some more coding.
So we have this sample code. Storing id value into $temp variable. What is the output we get?
$query = mysqli_query($db, "SELECT * FROM myTable1")
while($result = mysqli_fetch_assoc($query)){
$temp = $result['id'];
}
For example table myTable1 contains data like this.
+----+---------+---------+
| id | Col1 | Col2 |
+----+---------+---------+
| 1 | Value 1 | Value 2 |
| 2 | Value 1 | Value 2 |
| 3 | Value 1 | Value 2 |
| 4 | Value 1 | Value 2 |
+----+---------+---------+
Our $temp variable will be equal to 4. Because you are getting everything from that table and then fetching every result that comes up. Now, let's use that variable.
echo 'Selected id from table myTable1 equals ' . $temp;
Which results in
Selected id from table myTable1 equals 4
Then, we are getting data from another table called myTable2.
$query = mysqli_query($db, "SELECT * FROM myTable2")
while($result = mysqli_fetch_assoc($query)){
$temp = $result['id'];
}
That table contains data like this.
+----+---------+---------+
| id | Col1 | Col2 |
+----+---------+---------+
| 3 | Value 1 | Value 2 |
| 5 | Value 1 | Value 2 |
| 6 | Value 1 | Value 2 |
| 8 | Value 1 | Value 2 |
+----+---------+---------+
Again, same thing happens, $temp variable is now equal to 8. Let's use it same way.
echo 'Selected id from table myTable2 equals ' . $temp;
Which results in
Selected id from table myTable2 equals 8
Final result
Selected id from table myTable1 equals 4
Selected id from table myTable2 equals 8
Conclusion
Nothing wrong here. You can do that if you want. But be aware that it's not recommended to use variable with same name multiple times if you have way more lines of code.
More complex PHP code
Same tables, structure and data. Let's change code.
function printIndex($id) {
echo 'Index = ' . $id;
}
$query = mysqli_query($db, "SELECT * FROM myTable1")
while($result = mysqli_fetch_assoc($query)){
$temp = $result['id']; // Store id for further use
}
$query = mysqli_query($db, "SELECT * FROM myTable2")
while($result = mysqli_fetch_assoc($query)){
$temp = $result['id']; // Store id for further use
}
printIndex($temp); // Print stored id
Output
Index = 8
Conclusion
Bad coding. You have to use unique variable names to prevent such situation.
You can use the same variable names logically. It won't give you an error(sometimes it might if you use these variables out of your loop in this context). But using general keywords for variable names are not advisable.
Instead try to name the variables based on your Model. Please look at the below examples,
If your 'myTable1' about students then you can use $student instead of $result1.
Again, if your 'myTable2' is about products then you can use $product instead of $result2.

how to use one mysql query, update data without duplicate?

id | title | text
1 | aa |
2 | aa |
3 | aa |
I have some data from json data, i am not sure how many datas have duplicate in it.
$json = '[{"a":"1","b":"bb"},{"a":"2","b":"cc"},{"a":"3","b":"bb"}]';
$array = json_decode($json);
foreach($array as $key){
UPDATE table SET text = '".$key->b."' WHERE id = '".$key->a."' and title='aa'");
}
For example, as this situation, $key->b has 2 data bb from the json data, I only want update the first one and check if bb has already in the database, then ignore update.
id | title | text
1 | aa | bb
2 | aa | cc
3 | aa | <-ignore updtae, left the data empty
I know there have an easy way, first select * from table where text != '$key->a' for check, but this will cost 2 mysql query and make one more foreach, so
how to use one mysql query, update data without duplicate?
many thanks.
If your database is MySQL, maybe you can use the ON DUPLICATE KEY UPDATE.
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
I suggest using an array to store all the values of b you have used so far and only run the UPDATE if the value didn't exist yet.
$json = '[{"a":"1","b":"bb"},{"a":"2","b":"cc"},{"a":"3","b":"bb"}]';
$usedValues = array();
$array = json_decode($json);
foreach($array as $key){
if(!isset(usedValues[$key->b])) {
mysql_query("UPDATE table SET text = '".$key->b."' WHERE id = '".$key->a."' and title='aa'");
usedValues[$key->b] = true;
}
}
EDIT: If your database already has values for text this may still produce duplicates, but you could do a SELECT DISTINCT ´text´ and populate the $usedValues array with them.

How to parse results from MySQL Table with PHP using row data?

Typically when I make calls into a mysql db, I reference a column for values I need. In this particular instance however, I need to retrieve a set of rows and parse with PHP accordingly. The example is this:
Table format
ID | Level
-----------------
1 | 1
2 | 2
3 | 2
4 | 3
5 | 4
6 | 4
I am ultimately trying to retrieve all possible levels and count the number of results by those levels. A simple GROUP BY, COUNT() will do the trick:
'Select Level, Count(*) as counter FROM table GROUP BY Levels ORDER BY Levels ASC'
Which will return:
table_new
Level | Count
--------------
1 | 1
2 | 2
3 | 1
4 | 2
The problem I face though is when retrieving these results with PHP, I am not quite sure how to set a variable, say 'level1' and set it to the value returned in the count column.
I assume the logic would follow:
while ($row = $stmt->fetch()) {
$count_level = $row['counter']
}
(but then I would need to create counts for each level type. Any suggestions?
$level = array();
while ($row = $stmt->fetch()) {
$level[$row['level']] = $row['counter']
}
then you have $level array and $level[1], $level[2] etc variables

Finding the most common values from given data

I have some data that looks something like this...
+----------+----------+----------+
| Column 1 | Column 2 | Column 3 |
+----------+----------+----------+
| Red | Blue | Green |
| Yellow | Blue | Pink |
| Black | Grey | Blue |
+--------------------------------+
I need to go through this data and find the 3 most common colours.
The raw data is in CSV and there's likely to be thousands more rows. (link)
What's the best way of doing this?
There's no magic... one row at time, one column at time.
And count each color.
Loop through all the values while keeping a count of each one of them in an array (word => count). After you've done that, find the keys with the highest values.
If the number of possible colors is manageable, just to use an associative array:
$histo = array();
//foreach cell
$color = ??; //however you're getting a cell's value
if(!isset($histo[$color]))
$histo[$color] = 1;
else
$histo[$color]++;
//end loop
//reverse sort by value
$histo = arsort($histo);
//now the first three colors in $histo are the most common ones.
If you're doing the processing in PHP and not a database, and the file contains purely color names, I'd go with something like:
$colors = array();
$fh = fopen('data.txt');
while($row = fgetcsv($fh)) { // omitting length/delimiter arguments
foreach($row as $field) {
$colors[$field]++;
}
}
fclose($fh);
$colors = arsort($colors); // sort in decescending order
After that the top 3 colors will be the first elements in $colors.

Categories