Loop through php array issues - php

I'm sure I've been staring at this WAY too long, so asking for a lifeline.
I'm pulling data from a MySQL database. In particular this:
$category[] = "$row->category";
$issue[] = "$row->issue";
I need to cycle through the data. There are 6 categories in total and could be any number of issues for each category.
I would like to echo the data for each row as follows:
Category 1
Issue 1a
Issue 1b
Issue 1c
Category 2
Issue 2a
Issue 2b
Category 3
Issue 3a
Issue 3b
Issue 3c
Issue 3d
Issue 3e
I probably need more sleep, but I cannot seem to cycle through this properly. Any help would be appreciated.
$stmt = $pdo->prepare("SELECT * FROM project INNER JOIN data1 ON project.p_key = data1.p_key_project WHERE data1.p_key_project=? AND data1.archived=? ORDER BY data1.category, data1.updated DESC");
$stmt->execute(array($passed_key,'n'));
while ($row = $stmt->fetchObject()) {
$cust[] = "$row->cust_name";
$p_key[] = "$row->p_key";
$pid[] = "$row->pid";
$account_key[] = "$row->account_key";
$p_key_data1[] = "$row->p_key_data1";
$date[] = "$row->date";
$updated[] = "$row->updated";
$category[] = "$row->category";
$ryg[] = "$row->ryg";
$issue[] = "$row->issue";
$proposed_resolution[] = "$row->proposed_resolution";
$action_items[] = "$row->action_items";
$owner[] = "$row->owner";
$status[] = "$row->status";
}

PDO version based on updates we've been talking about:
assume $issues is a multidimensional array of issues and categories you could do. i.e. $issue[] = "$row->issue, $row->category";
$numOfItems = count($issue); //counts number of times for should be run
for ($row = 0; $row < $numofItems; $row++) {
echo $issues[$row][$row] . "</br>";
$i=0;
while ($issues[$i][$row] == $issues[$row][$row]) {
echo $issues[$i][$row] . "</br>";
$i++;
} }
This is freehand - but it should work
OLD ANSWER BELOW
If you copy and paste the Database Schema (or a part of it) that would be helpful to see how Categories and Issues are related. Not seeing the exact relationship, I think this is probably how your database is structured
so lets that $category[] = "$row->category"; populates categories; now you have to match issues to each category. I assume that a row in your database has a category assigned to each issue. i.e. your database looks like
ID | Category | Issue
1 | Pizza | Bad
2 | Pizza | Good
If thats the case then below should work
foreach ($category as $key => $value) {
$query = mysqli_query($con,"SELECT * FROM project INNER JOIN data1 ON project.p_key = data1.p_key_project WHERE data1.p_key_project=? AND data1.archived=? AND data1.category='$value' ORDER BY data1.category, data1.updated DESC"); //value is the individual category
echo $value . "</br>";
while($row = mysqli_fetch_array($query)) {
echo $row['issue'] . '</br>';
}
echo "</br>"; //adds an extra space between categories
}
Updated to include your specific query

Related

Best practice for writing code in php for foreach->foreach->if(1st loop id == 2nd loop id)->result

First loop table
user_id | fname | lname
1 | first | emp
2 | second| emp
3 | third | emp
Second loop table
shift_id | employee_id
1 | 1
2 | 2
3 | 2
if($employees)
{
foreach ($employees as $employee)
{
if($employee['user_id'] == $shift['employee_id'])
{
echo ucwords($employee['fname']. ' ' .$employee['lname']);
}
}
}
I am getting the right result but I think there is some better way of writing this.
You can use joins in table. Left join means that the user line has to exists (because: LEFT) and the shifts enty is optional.
SELECT user.user_id, user.fname, user.lname, shifts.shift_id
FROM yourUserTable AS user
LEFT JOIN yourShiftsTable AS shifts ON(user.user_id = shifts.employee_id)
Now you get it in your initial array, as if you'd select it as one row from a table and no longer need to do tricks in PHP to combine information. If you can, always try to get the database to manage data, it does that way faster than PHP can.
Please note, the query could be a little off, I just wrote this out of the top of my head.
Just some test code I whipped up to test this from the information provided for this "Demonstration Code".
Note: I have used the mysqli class for the database (instantiating $db ) and have excluded the SQL Table setup.
What you would have had is something along the lines of this...
Case 1 - The original
$db = new mysqli('localhost', 'root', 'test', 'phptutorials_st26');
echo '<h2>Create $employees </h2>';
$query = "SELECT * FROM users";
$result = $db->query($query);
$employees = $result->fetch_all(MYSQL_ASSOC);
var_dump($employees);
echo '<h2>Create $shifts </h2>';
$query = "SELECT * FROM shifts";
$result = $db->query($query);
$shifts = $result->fetch_all(MYSQL_ASSOC);
var_dump($shifts);
echo '<h2>Using foreach on $employees and $shifts</h2>';
if ($employees) {
foreach ($employees as $employee) {
foreach ($shifts as $shift) {
if ($employee['user_id'] == $shift['employee_id']) {
echo ucwords($employee['fname'] . ' ' . $employee['lname']);
echo '<br>';
}
}
}
}
The Result from the above is
First Emp
Second Emp
Second Emp
Case 2 - Using a Join
Well using a join, as everyone has already stated, is the way to go...
$sql = "SELECT u.user_id, u.fname, u.lname, s.shift_id
FROM users AS u
JOIN shifts AS s ON(u.user_id = s.employee_id)
";
$result = $db->query($sql);
$employees = $result->fetch_all(MYSQL_ASSOC);
// To see what comes out because we always check things.
var_dump($joined_result);
(Don't ask me why I love using very abbreviated aliases for the table names! It's just "a thing".)
Then your "loop" simply becomes...
echo '<h2>Using foreach on join</h2>';
foreach ($employees as $employee) {
echo ucwords($employee['fname'] . ' ' . $employee['lname']);
echo '<br>';
}
And the result is...
First Emp
Second Emp
Second Emp
Case 2 - has reduced the code and only requires 1 Trip to the Database.
Does that help you any?
You could do it this way also. Its a little shorter.
SELECT TABLE1.FNAME, TABLE1.LNAME, TABLE2.EMPLOYEE_ID
FROM TABLE1, TABLE2
WHERE TABLE1.USER_ID = TABLE2.EMPLOYEE_ID;

Most Efficient way to MySQL Query inside query

i'm just learning PHP, and i have a question
Let just say, i have MySQL table "A"
Name | Job
--------|---------
Jynx | 1
Micah | 4
Nancy | 3
Turah | 1
And another table "B"
JobId | JobName
-------|-----------
1 | Lawyer
2 | Architec
3 | Farmer
4 | Mage
5 | Warrior
So supposedly in php i want to draw table that showed the content of table "A", but instead of displaying number at the "Job" colomn, they each display Job names from Table "B".
What is the most efficient way to do that?
For now, i just thinking of using
$conn = My database connect setting
$sql = "SELECT * FROM tableA ORDER BY Name";
$result = $conn->query($sql);
while($row = mysqli_fetch_assoc($result)) {
echo "<tr><td>". $row['Name'] ."</td><td>";
$sql2 = "SELECT * FROM tableB WHERE JobId=$row['Job']";
$result2 = $conn->query($sql2);
while($row2 = mysqli_fetch_assoc($result2)) {
echo "<td>". $row2['JobName'] ."</td></tr>;
}
}
But wouldn't it take a lot of calculating proccess if there is multiple similliar colomn with hundreed of rows?
Is there any more efficient way to do this?
Sorry for my bad english
Thank you for your attention.
A join is definitely the way to go here.
SELECT a.Name, b.JobName
FROM tableA a
JOIN tableB b on (a.Job = b.JobId)
ORDER BY a.Name
Well, it is not easy to learn about JOIN, no time for now, but i will get to learn it latter.
As for now, i just get the idea to just use ARRAY instead
So before i draw the main table, i assign the supportive table (Table B) into associative array
$sql = "SELECT * FROM tableB ORDER BY Id";
$result = $conn->query($sql);
while($row = mysqli_fetch_assoc($result)) {
$job[$row['JobId']] = $row['JobName'];
}
And at the main table
$sql = "SELECT * FROM tableA ORDER BY Name";
$result = $conn->query($sql);
while($row = mysqli_fetch_assoc($result)) {
echo "<tr><td>". $row['Name'] ."</td><td>". $job[$row['Job']];
}

How performance is affected by storing categories as comma delimited array and extracting each in a loop?

Namastey!
I'm currently working on one of my projects where I get to one doubt.
What I'm doing is:
I have got 4 tables called:
1: project_degree
2: project_department
3: project_category
4: Projects
project_degree have got four top level degrees which are: B.tech, M.tech, M.C.A. & M.B.A.
project_department have got their respective departments such as: C.S.E, I.T., E.E.E. and so on.
Now, project_category have some categories like PHP, .NET, SAP etc.
What I'm trying to do is, I'm adding a project to database called "projects" where I'm assigning it to its degree, department and category.
Structure of projects table is as follows:
id | project name | degree_id | Dept_id | Cat_id
1 | Sample project | 1 | 3 | 4,3,6,5,9
Now as you can see above, field "cat_id" have got multiple categories where each categories ID have been separated by a comma.
Now when I call a query get all projects from the table called "projects", I want to list of categories related to that particular project and my code goes like this:
$query = mysql_query("SELECT * from projects ORDER BY id DESC");
while($row = mysql_fetch_array($query)) {
$categories = $row['cat_id'];
$cat_arr = explode(',',$categories);
$cat_size = sizeof($cat_arr);
for($i=0;$i<$cat_size;$i++) {
$get_cat = mysql_query("SELECT * from project_category WHERE id='".$cat_arr['$i']."'");
$cat_row = mysql_fetch_array($get_cat);
echo $cat_row['name']; // Here finally I'm getting categories name
}
}
So, finally I'm running nested loop and two queries to get a category name. I doubt it affect the page load time when it comes to huge data.
Is there any better alternative to this situation?
Here should be work
$query = mysql_query("SELECT * from projects ORDER BY id DESC");
while($row = mysql_fetch_array($query)) {
$get_cat = mysql_query("SELECT * from project_category WHERE id IN (" . $row['cat_id'] . ")");
$cat_row = mysql_fetch_array($get_cat);
echo $cat_row['name']; // Here finally I'm getting categories name
}
But normalization is better.
It's better to add a new table, project_has_catID where you can store project.id and cat.id as two columns (project_id and cat_id). Remove the Cat_id column in the project table.
Once done, simply select the name by the next query;
$query = mysql_query("SELECT project_category.name from project_category INNER JOIN project_has_catID phc ON phc.cat_id = project_category.id ORDER BY phc.project_id DESC");
By this, you have a list of category names. You don't have to loop with multiple database communications.
You could load all category names into an associative array first, then look up category names in this array when looping through the projects.
$categoryNames = array();
$query = mysql_query("SELECT id, name FROM project_category");
while ($row = mysql_fetch_array($query))
{
$categoryNames[$row['id']] = $row['name'];
}
$query = mysql_query("SELECT * FROM projects ORDER BY id DESC");
while ($row = mysql_fetch_array($query))
{
$categoryIds = explode(',', $row['cat_id']);
foreach ($categoryIds as $cat_id)
{
$cat_name = $categoryNames[$cat_id];
//do what you want with the name here
}
}
This way, you don't have to change your database structure, or the structure of your code. And you only have to execute two queries in total, so this is by far the simplest solution.
Needless to say, normalization is always better as others have indicated (never use a column that contains multiple comma-separated values), but you probably knew that and had your reasons for setting up your database tables this way.

Iterate list values from table

I have two tables, who are joined and the ID of each table and element underneath are similar.
parentID | objectName | subID ID| className| subName |
_____________________________ ________________________
84 | Test | 14 14| BOM | Test
84 | More | 16 14| PDF | Test
84 | Sub | 15 15| Schematics | Test2
I want to list the categoryname and the subID of the related elements. Several ObjectNames will have several related classes.
PHP code:
$objects = mysqli_query($con,"SELECT * from subobject");
$join = mysqli_query($con, "SELECT * FROM subrelation AS subrelation INNER JOIN subobject AS subobject ON subobject.subId = subrelation.ID;");
echo "<ul>";
while($obj = mysqli_fetch_array($objects) and $row = mysqli_fetch_array($join))
{
echo "<li>". $obj['objectName'];
echo "<ul>";
//ITERATION GOES HERE
if($obj['objectName'] == $row['subName'])
echo "<li>". "$row[className]" . "</li>";
//END OF ITTERATION
echo "</ul>";
echo "</li>";
}
echo "</ul>";
?>
and output list:
-Test
-BOM
-Sub
-Schematics
-More
under each field there are supposed to be more listed values.
It looks like you need to simplify your code a bit. My guess is that your problem is occurring because you have different amounts of rows in each result set. This makes your while loop exit when it finishes going through the smaller result set (probably $objects), even though there's still more elements in the larger set.
A solution is to sort the results of your query, use just one condition in your while loop, and keep track of which objectName you're currently on using a string $curr_objectName:
$join = mysqli_query($con, 'SELECT * FROM subrelation AS subrelation INNER JOIN subobject AS subobject ON subobject.subId = subrelation.ID ORDER BY subobject.objectName;');
$curr_objectName = '';
echo '<ul>';
while($row = mysqli_fetch_array($join)) {
$subName = $row['subName'];
if($subName != $curr_objectName)) {
if($curr_objectName != '') {
#close the previous list
#will be skipped on the first loop iteration
echo '</ul>';
echo '</li>';
}
#start a new list
$curr_objectName = $subName;
echo '<li>'. $obj['objectName'];
echo '<ul>';
} else {
echo '<li>'. $row['className'] . '</li>';
}
}
echo '</ul>';

SQL to show all entries within a number of categories

I'm writing an sql query on three tables which finds and displays categories and all the entries within each category
For example
Category 1
post 1
post 2
post 3
post 4
Category 2
post 5
post 6
Category 3
post 7
post 8
etc
I have the categories displaying but can only get one item from each. Can anyone suggest a better approach?
$sql = "SELECT c.CategoryDescription, f.Description, l.FileID, l.CategoryID FROM
FileCategories c, Files f, FilesLK l WHERE
c.PictureCategoryID IN (58, 59, 60, 61, 62, 63) AND
c.PictureCategoryID = l.CategoryID AND
f.ID = l.FileID
GROUP BY c.CategoryDescription";
while($row = mysql_fetch_array($result)) {
$html .= '<h3>'.$row['CategoryDescription'].'</h3>
<div>'.$row['Description'].'</div>';
}
Thanks
Well your GROUP BY c.CategoryDescription is making sure you only have one post per category. Can't really cut down the rows like that. Why not put some logic in the loop to make it smarter.
$thiscat = '';
while($row = mysql_fetch_array($result)) {
if($thiscat != $row['CategoryDescription']) {
$thiscat = $row['CategoryDescription'];
$html .= '<h3>'.$thiscat.'</h3>';
}
$html .= '<div>'.$row['Description'].'</div>';
}
If you remove the group by from your SQL and change your loop to this it will print the header row only when the category description changes.
Tho personally I would recommend writing it like this:
$thiscat = '';
while(list($cat,$desc,$fileid,$catid) = mysql_fetch_row($result)) {
if($thiscat != $cat) {
$thiscat = $cat;
$html .= "<h3>$thiscat</h3>";
}
$html .= "<div>$desc</div>";
}
Just have to use escaped double quotes or single quotes for tag attributes is all but is a lot neater and easier to read/troubleshoot... IMHO.
HTH :)
Sorry, this is the basic layout with some irrelevant fields omitted:
FileCategories
ID | CategoryDescription
Files
ID | Description
FilesLK
FileID | CategoryID

Categories