Compare 2 arrays and retrieve the differences using PHP - php

I'm not a PHP expert but i'm trying Compare 2 arrays ( database relations and schema) in PHP, I need retrieve the differences between those 2 array, I'm using this php code
<?php
function maxEntities($rela, $db){
$maxenty = array();
$found = false;
foreach ($rela as $valor1) {
print $valor1[0] . " | ";
}
print " <br \>";
foreach ($db as $valor2) {
print $valor2[0] . " | ";
}
$maxenty = array_diff($rela[0], $db[0]);
print " <br \> <br \>";
foreach ($maxenty as $valor) {
print " " . $valor;
}
}
and this code give me this output
Sale | Customer | Sale_Fee | Sale | Location | Sale | Sale | Sale_Iten | Product | Customer | Location | Sale_Iten | Sale_Fee | Region |
Customer | Customer_Type | Fee_Type | Location | Location_Type | Period | Product | Product_Type | Region | Sale | Sale_Fee | Sale_Iten | State |
Sale Customer_Cust_Id
and the output i expect is
Period, Customer_Type, State, Location Type, Product Type and Fee Type
how i can solve my problem ?
i also tried with foreach, but give me also a wrong output
foreach ($rela as $relaV) {
foreach ($db as $dbV) {
if ($dbV[0] == $relaV[0]) {
$found = true;
}
if (!$found) {
$found = false;
$maxenty[] = $dbV[0];
}
}
}
in this case my output was
Customer
Customer_Type
Fee_Type
Location
Location_Type
Period
Product
Product_Type
Region
and Customer, Region, Location are in both arrays

It is not very clear, how your arrays are structured. From your code so far I guess the following structures:
$rela = array(array('Sale'), array('Customer'), array('Sale_Fee'), array('Sale'), array('Location'), array('Sale'), array('Sale'), array('Sale_Iten'), array('Product'), array('Customer'), array('Location'), array('Sale_Iten'), array('Sale_Fee'), array('Region'));
$db = array(array('Customer'), array('Customer_Type'), array('Fee_Type'), array('Location'), array('Location_Type'), array('Period'), array('Product'), array('Product_Type'), array('Region'), array('Sale'), array('Sale_Fee'), array('Sale_Iten'), array('State'));
If this is the structure of your arrays, then you can use the following code to get the difference (adopted from your foreach-approach, there may be other ways):
$maxenty = array();
foreach ($db as $dbValue) {
$found = false;
foreach ($rela as $relaValue) {
if ($relaValue[0] == $dbValue[0]) {
$found = true;
break;
}
}
if (!$found) {
$maxenty[] = $dbValue[0];
}
}
print_r($maxenty);
This will give you the $maxenty as follows:
Array
(
[0] => Customer_Type
[1] => Fee_Type
[2] => Location_Type
[3] => Period
[4] => Product_Type
[5] => State
)

Related

How to create JSON API service from mysql database in php

I have following mysql database table
id | majorFoodName | cropName | foodType | foodName | quantity | form
1 | Recipe1 | Rice | Breakfast | Foodname1 | 500+60 | 2000
4 | Recipe2 | Rice | Breakfast | Foodname2 | 500 | 1000
6 | Recipe1 | Wheat | Breakfast | Foodname2 | 518 | 1000
I have written following php code to give JSON API output
$sql = "SELECT * FROM food WHERE cropName = 'Rice' AND foodName =
'Foodname1' ";
$result = mysqli_query($connect, $sql);
$num_rows = mysqli_num_rows($result);
if ($num_rows > 0) {
$jsonData = array();
while ($array = mysqli_fetch_row($result)) {
$jsonData[] = $array;
}
}
class Emp {
public $majorFoods = "";
}
$e = new Emp();
$e->majorFoods = $jsonData;
header('Content-type: application/json');
echo json_encode($e);
I am getting following JSON output
{
"majorFoods": [
[
"1",
"Recipe1",
"Rice",
"Breakfast",
"Foodname1",
"500+60",
"2000"
]
]
}
I need to give following API JSON format for all cropName and all foodName
{
"Rice": [
{
"foodName1": {
"majorFoodName": "Receipe1",
"quantity": "500+60",
"form": "2000" }
"foodName2": {
"majorFoodName": "Receipe2",
"quantity": "500",
"form": "1000" }
]
"Wheat": [
{
"foodName2": {
"majorFoodName": "Receipe1",
"quantity": "518",
"form": "1000" }
]
}
Kindly help in improving the php code to get desired API JSON response.
When your building up your array of data, use the crop type as the main index and create sub arrays of the extra data you need to store.
while ($array = mysqli_fetch_assoc($result)) {
$cropData = array ( $array['foodName'] =>
array( 'majorFoodName' => $array['majorFoodName'],
'quantity' => $array['quantity'],
'form' => $array['form'] ));
$jsonData[$array['cropName']][] = $cropData;
}
Note that I use mysqli_fetch_assoc so that I can refer to the result fields with the column names.
The line
$jsonData[$array['cropName']][] = $cropData;
Accumulates all of the data for a particular crop name together, adding the new data to the end of the array (using []).

PHP Compare column values and edit database accordingly

I am a newbie to PHP and I am stuck at a certain point. I tried looking up a solution for it however, I didn't find exactly what I need.
My goal is to create a leaderboard, in which the values are displayed in descending order plus the rank and score are displayed. Furthermore, it should also display whether or not a tie is present.
The database should look like this:
+---------+------+----------------+-------+------+
| user_id | name | email | score | tied |
+---------+------+----------------+-------+------+
| 1 | SB | sb#gmail.com | 1 | 0 |
+---------+------+----------------+-------+------+
| 2 | AS | as#web.de | 2 | 0 |
+---------+------+----------------+-------+------+
| 3 | BR | br#yahoo.com | 5 | 1 |
+---------+------+----------------+-------+------+
| 4 | PJ | pj#gmail.com | 5 | 1 |
+---------+------+----------------+-------+------+
And the outputted table should look something like this:
+------+-------------+-------+------+
| rank | participant | score | tied |
+------+-------------+-------+------+
| 1 | BR | 5 | Yes |
+------+-------------+-------+------+
| 2 | PJ | 5 | Yes |
+------+-------------+-------+------+
| 3 | AS | 2 | No |
+------+-------------+-------+------+
| 4 | SB | 1 | No |
+------+-------------+-------+------+
I managed to display the rank, participant and the score in the right order. However, I can't bring the tied column to work in the way I want it to. It should change the value, whenever two rows (don't) have the same value.
The table is constructed by creating the <table> and the <thead> in usual html but the <tbody> is created by requiring a php file that creates the table content dynamically.
As one can see in the createTable code I tried to solve this problem by comparing the current row to the previous one. However, this approach only ended in me getting a syntax error. My thought on that would be that I cannot use a php variable in a SQL Query, moreover my knowledge doesn't exceed far enough to fix the problem myself. I didn't find a solution for that by researching as well.
My other concern with that approach would be that it doesn't check all values against all values. It only checks one to the previous one, so it doesn't compare the first one with the third one for example.
My question would be how I could accomplish the task with my approach or, if my approach was completely wrong, how I could come to a solution on another route.
index.php
<table class="table table-hover" id="test">
<thead>
<tr>
<th>Rank</th>
<th>Participant</th>
<th>Score</th>
<th>Tied</th>
</tr>
</thead>
<tbody>
<?php
require("./php/createTable.php");
?>
</tbody>
</table>
createTable.php
<?php
// Connection
$conn = new mysqli('localhost', 'root', '', 'ax');
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// SQL Query
$sql = "SELECT * FROM names ORDER BY score DESC";
$result = $conn->query("$sql");
// Initalizing of variables
$count = 1;
$previous = '';
while($row = mysqli_fetch_array($result)) {
$current = $row['score'];
$index = $result['user_id']
if ($current == $previous) {
$update = "UPDATE names SET tied=0 WHERE user_id=$index";
$conn->query($update);
}
$previous = $current;
?>
<tr>
<td>
<?php
echo $count;
$count++;
?>
</td>
<td><?php echo $row['name'];?></td>
<td><?php echo $row['score'];?></td>
<td>
<?php
if ($row['tied'] == 0) {
echo 'No';
} else{
echo 'Yes';
}
?>
</td>
</tr>
<?php
}
?>
I think the problem is here
$index = $result['user_id'];
it should be
$index = $row['user_id'];
after updating tied you should retrieve it again from database
So I solved my question by myself, by coming up with a different approach.
First of all I deleted this part:
$current = $row['score'];
$index = $result['user_id']
if ($current == $previous) {
$update = "UPDATE names SET tied=0 WHERE user_id=$index";
$conn->query($update);
}
$previous = $current;
and the previous variable.
My new approach saves the whole table in a new array, gets the duplicate values with the array_count_values() method, proceeds to get the keys with the array_keys() method and updates the database via a SQL Query.
This is the code for the changed part:
// SQL Query
$sql = "SELECT * FROM names ORDER BY score DESC";
$result = $conn->query("$sql");
$query = "SELECT * FROM names ORDER BY score DESC";
$sol = $conn->query("$query");
// initalizing of variables
$count = 1;
$data = array();
// inputs table into an array
while($rows = mysqli_fetch_array($sol)) {
$data[$rows['user_id']] = $rows['score'];
}
// -- Tied Column Sort --
// counts duplicates
$cnt_array = array_count_values($data);
// sets true (1) or false (0) in helper-array ($dup)
$dup = array();
foreach($cnt_array as $key=>$val){
if($val == 1){
$dup[$key] = 0;
}
else{
$dup[$key] = 1;
}
}
// gets keys of duplicates (array_keys()) and updates database accordingly ($update query)
foreach($dup as $key => $val){
if ($val == 1) {
$temp = array_keys($data, $key);
foreach($temp as $k => $v){
$update = "UPDATE names SET tied=1 WHERE user_id=$v";
$conn->query($update);
}
} else{
$temp = array_keys($data, $k);
foreach($temp as $k => $v){
$update = "UPDATE names SET tied=0 WHERE user_id=$v";
$conn->query($update);
}
}
}
Thank you all for answering and helping me get to the solution.
instead of the update code you've got use something simular
$query = "select score, count(*) as c from names group by score having c > 1";
then you will have the scores which have a tie, update the records with these scores and your done. Make sure to set tie to 0 at first for all rows and then run this solution
UPDATE for an even faster solution sql based:
First reset the database:
$update = "UPDATE names SET tied=0";
$conn->query($update);
All records have a tied = 0 value now. Next update all the records which have a tie
$update = "update docs set tied = 1 where score IN (
select score from docs
group by score having count(*) > 1)";
$conn->query($update);
All records with a tie now have tied = 1 as we select all scores which have two or more records and update all the records with those scores.

How to display comments in a nested way with parent ID

I have a table comments, thats look like this, added some mockup content as well:
+------------+---------+----------+-------------------+------------------------------------+---------------------------+
| comment_id | user_id | movie_id | comment_parent_id | comment_content | comment_creation_datetime |
+------------+---------+----------+-------------------+------------------------------------+---------------------------+
| 26 | 1 | 16329 | 0 | Första | 2016-01-24 10:42:49 |
| 27 | 1 | 16329 | 26 | Svar till första | 2016-01-24 10:42:55 |
| 28 | 1 | 16329 | 26 | Andra svar till förta | 2016-01-24 10:43:06 |
| 29 | 1 | 16329 | 28 | Svar till "andra svar till första" | 2016-01-24 10:43:23 |
+------------+---------+----------+-------------------+------------------------------------+---------------------------+
Im trying to display the comments Reddit style, like this image:
Im trying to fetch all comments SELECT * FROM comments WHERE movie_id = :movie_id ORDER BY comment_creation_datetime DESC and then recursively echo them out.
I have tried a bunch of foreachloops, but none is working as expected
foreach($this->comments as $value){ ?>
<div class="comment">
Comment content <?php echo $value->comment_content; ?>
<?php if($value->comment_parent_id > 0){
foreach($value as $sub_comment){ ?>
<div class="comment">
comment comment on comment: <?php echo $value->comment_content; ?>
</div>
<?php }} ?>
</div>
<?php }
My question:
How do I echo out the comments in a nested Reddit style with foreach loop?
You need to both make a list of root comments, and hierarchically organize all of them. You can do both in one go:
$roots = [];
$all = [];
foreach($comments as $comment)
{
// Make sure all have a list of children
$comment->comments = [];
// Store all by ID in associative array
$all[$comment->comment_id] = $comment;
// Store the root comments in the roots array, and the others in their parent
if(empty($comment->comment_parent_id))
$roots[] = $comment;
else
$all[$comment->comment_parent_id]->comments[] = $comment;
}
// Check it's all done correctly!
print_r($roots);
You presorted the list by date, that's preserved in this approach. Also, as you only reorganized by reference this is lightning fast, and ready to be used in templating engines or anything - no need to print out inline like the other answers.
Working with the adjacency list model can be more problematic with SQL. You need to retrieves all the rows with a single query and store a reference of any parent's child in a lookup table.
$sth = $pdo->prepare("SELECT * FROM comments WHERE movie_id = ? ORDER BY comment_creation_datetime DESC");
$sth->execute([$movie_id]);
$comments = $sth->fetchAll(PDO::FETCH_ASSOC);
$lookup_table = [];
foreach ($comments as $comment_key => $comment) {
$lookup_table[$comment['comment_parent_id']][$comment_key] = $comment['comment_id'];
}
Now you can display them with
function recursive_child_display($comments, $lookup_table, $root = 0, $deep = 0)
{
if (isset($lookup_table[$root])) {
foreach ($lookup_table[$root] as $comment_key => $comment_id) {
// You can use $deep to test if you're in a comment of a comment
echo '<div class="comment">';
echo 'Comment content ', $comments[$comment_key]['comment_content'];
recursive_child_display($comments, $lookup_table, $comment_id, $deep+1);
echo '</div>';
}
}
}
Example:
// display all the comments from the root
recursive_child_display($comments, $lookup_table, 0);
// display all comments that are parent of comment_id 26
recursive_child_display($comments, $lookup_table, 26);
I would use some recursive function, you start with the ones with parent_id == 0 and recursively print all those who are their direct children.
This code is not tested, but you can get the idea:
function printComment($comment, $comments)
{
foreach($comments as $c)
{
if($c->parent_id == $comment->comment_id)
{
$output .= "<li>".printCommment($c)."</li>";
}
}
$output = "<ul>".$comment->comment_content."</ul>".$output;
return $output;
}
foreach($this->comments as $comment)
{
if($comment->parent_id == 0)
{
echo printComment($comment,$this->comments);
}
}

Group by common id

I am trying to fetch data from my database and would like to group common values in the column called order_ids by that id.
This is the state I currently get my data in
Order_Id | Product Name
-------------------------------
10001 | iPhone 5
10001 | Blackberry 9900
10002 | Galaxy S
10003 | Rhyme
10004 | Google Nexus
10005 | Razr
10006 | iPad Air
And this is the state I want to get it in
Order_Id | Product Name
-------------------------------
10001 | iPhone 5
Blackberry 9900
10002 | Galaxy S
10003 | Rhyme
10004 | Google Nexus
10005 | Razr
10006 | iPad Air
Here is how I get the result in my controller file
foreach($results_query as $results_custom) {
$this->data['result_custom'][] = array(
'model' => $results_custom['product_name'],
'order_number' => $results_custom['order_id']
);
}
Here is how I display it in my view file
<?php foreach ($results_custom as $result) { ?>
<li><?php echo $result['model']; ?></li> <br />
<li><?php echo $result['order_number']; ?></li><br />
<?php } ?>
Is it possible to get my data to display like that or in that state by using SQL or PHP? Please let me know if you want to see my query as well.
In php would be easier to do it. As I don't have PHP enviroment to test it I will show you some logic to do it. Not necessarily working code. Thats because you didn't provide what you did
<?
$sql = "select order_id, product name from ..... order by order_id"// rest of sql code ....
//here you iterate your results
$previousId = ""; //var to store previous id
while( $fetch... ){
if ( $fetchedID != $previousId ){
echo $fetchedId . "-" . $fetchedProductName;
}else{
echo $fetchedProductName;
}
$previousId = $fetchedID;
}
?>
This should do.
As you updated your code this is a solution for you:
<?php
$lines = ""; //to make code cleaner;
$previousModel = "";
foreach ($results_custom as $result) {
if ( $previousModel != $result['model'] ){
$line .= "<li>" . $result['model'] . "</li>";
}else{
$line .= "<li></li>";
}
$line .= "<li>" . $result['model'] . "</li><br />";
$previousModel = $result['model'];
}
echo $line;
<?php } ?>
I suggest you to use GROUP_CONCAT for getting the result
You try as follows
SELECT order_id,GROUP_CONCAT(product_name) as product_name FROM your_table GROUP BY order_id
Just look at this http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
Note : GROUP_CONCAT has a size limit. Check this link for more MySQL and GROUP_CONCAT() maximum length
you might be able to accomplish this in just MySQL, but it might be easier if you just create a php loop. most people prefer a foreach loop, but I like while loops:
$orderid = "number";
$order_query = mysql_query("SELECT * FROM ordertable WHERE Order_Id = '$orderid'");
while($order_data = mysql_fetch_array($order_query)){
$ordername = stripslashes(mysql_real_escape_string($order_data['Product Name']));
echo $ordername.'<br />';
}
if you need this for ALL orders you could remove searching for a specific order:
$order_query = mysql_query("SELECT * FROM ordertable ORDER BY Order_Id ASC");
while($order_data = mysql_fetch_array($order_query)){
$orderid = mysql_real_escape_string($order_data['Order_Id']);
$ordername = stripslashes(mysql_real_escape_string($order_data['Product Name']));
echo 'ID#: '.$orderid.' - '.$ordername.'<br />';
}

PHP tree menu, bottom-up

I'm having some issues getting a tree menu to work from bottom-up.
I already have a script to work from top-down, which works fine.
This is a very simplified version of my table:
+-----+-----------+--------------------+
| uid | parent_id | page_address |
+-----+-----------+--------------------+
| 1 | 0 | index.php |
| 2 | 0 | login.php |
| 3 | 2 | dashboard.php |
| 4 | 3 | bookings.php |
| 5 | 3 | documents.php |
| 6 | 4 | changebookings.php |
| 7 | 4 | activities.php |
+-----+-----------+--------------------+
The page_address field is unique.
I can work out what page the user is currently on, for example changebookings.php
I would then like a menu to look like this:
login.php
dashboard.php
bookings.php
changebookings.php
activities.php
documents.php
However, the closest I've got so far is the following tree:
login.php
bookings.php
changebookings.php
As you can see, my script currently only returns the actual parent, and not a list of links currently in the parent.
For those interested, the script I use in total is at the bottom of this post.
Is there any easier way to get the bottom-up tree as required?
Many thanks
Phil
EDIT:
I've finally got the code to work, for future users who stumble upon this post, I have added the functionality below:
$dataRows = $databaseQuery->fetchAll(); // Get all the tree menu records
$dataRows = $result->fetchAll(PDO::FETCH_ASSOC);
foreach($dataRows as $row)
{
if($row['link_address']==substr($_SERVER['PHP_SELF'], 1, strlen($_SERVER['PHP_SELF'])-1))
{
$startingId = $row['parent_id'];
}
}
$menuTree = $this->constructChildTree($dataRows, $startingId);
private function constructChildTree(array $rows, $parentId, $nesting = 0)
{
$menu = array();
if(!in_array($nesting, $this->nestingData))
{
$this->nestingData[] = $nesting;
}
foreach($rows as $row)
{
if($row['parent_id']==$parentId && $parentId!=0)
{
$menu[] = $row['link_address'];
$newParentId = $this->getNextParent($rows, $row['parent_id']);
$parentChildren = $this->constructChildTree($rows, $newParentId, ($nesting+1));
if(count($parentChildren)>0)
{
foreach($parentChildren as $menuItem)
{
$menu[] = 'NESTING' . $nesting . '::' . $menuItem;
}
}
}
}
return $menu;
}
private function getNextParent($rows, $parentId)
{
foreach($rows as $row)
{
if($row['uid']==$parentId)
{
return $row['parent_id'];
}
}
}
Without reading your code you should be doing:
1) Get current page, look at parent ID.
2) Load all with that parent ID.
3) Get next Parent ID using current Parent ID as ID.
4) If new parent ID != 0, goto step 2 passing in the new Parent ID.
Sounds like you just need to edit your script to include ALL pages with the given ID as their parent ID.
<?PHP
$sql = "SELECT * FROM TABLE WHERE table parent_id=0";
$result = mysql_query($sql);
while($perant_menu = mysql_fetch_array($result))
{
echo display_child($perant_menu["uid"],$perant_menu["page_address"]);
}
// Recursive function
function display_child($parent_id,$name)
{
$sql= "SELECT * FROM table where parent_id = $parent_id";
$result = mysql_query($sql);
if(mysql_num_rows($result)>0)
{
while($menu = mysql_fetch_array($result))
{
echo display_child($menu["id"],$menu["page_address"]);
}
}
else
{
echo $name;
}
}
?>

Categories