I am trying to display comments below updates. Please help me know how to bring all the comments as an array from the database. The code below will give me only one comment when I call $article->comments as shown below, I only get one result. Counting the rows gives a correct count, but displaying brings only one result.
$articlesQuery = $db->query("
SELECT
updates.id,
updates.update_text,
updates.posted_at,
updates.user_id,
updates.the_group,
members_comments.comment AS comments,
COUNT(articles_likes.id) AS likes,
GROUP_CONCAT(members.id SEPARATOR '|') AS liked_by
FROM updates
LEFT JOIN articles_likes
ON updates.id = articles_likes.article
LEFT JOIN members
ON articles_likes.user = members.id
RIGHT JOIN members_comments
ON members_comments.update_id = updates.id
GROUP BY updates.id
ORDER BY updates.id DESC
LIMIT 3
");
while ($row = $articlesQuery->fetch_object()){
$row->liked_by = $row->liked_by ? explode('|', $row->liked_by) : [];
$articles[] = $row;
}
then to display, this brings errors, but it explains what i'm trying to do.
foreach($articles as $article):
echo $article->update_text;
foreach ($article->comments as $comment){
echo $article->comment;
}
endforeach;
I think the loops are incorrect.
Foreach $article (This is now 1 row)
foreach comment in $article echo comment
So this comment will only be a comment from 1 row?
Unless I have misunderstood this should be your code:
foreach($articles as $article) {
print $article->update_text."\n";
print $article->comment."\n";
}
Related
SELECT i.itemsname
, i.itemsprice
, i.itemsdescrip
, c.catname
, c.catdes
, c.status
, c.collapse
, c.catid
FROM items i
LEFT
JOIN categories c
ON c.catid = i.catid
WHERE i.restid
AND c.restid =12
GROUP
BY c.catid
that is my query at the moment but I would like to have something like this....
but this is what I'm getting:
Ok, I lied in the comments, so With PDO (haven't tested it)
$stmt = $PDO->prepare('SELECT
categories.catname,
items.itemsname,
items.itemsprice,
items.itemsdescrip,
categories.catdes,
categories.status,
categories.collapse,
categories.catid
FROM items
LEFT JOIN categories ON items.catid=categories.catid
WHERE items.restid AND categories.restid = :restid');
$stmt->execute([':restid' => 12]);
$data = $stmt->fetchAll(\PDO::FETCH_GROUP);
foreach($data as $catname => $rows){
//echo group html stuff
//echo "<dl>";
//echo "<dt>$catname</dt>".;
foreach($rows as $row){
//echo row data stuff
// echo "<dd> {stuff} </dd>";
}
//echo "</dl>";
}
I'll leave the html up to you. But as I said you want a data structure like this
[
'BREAKFASTS' => [
0 => [ name => "wimpy hamburger", description => "bla bla", price => "$100,000"],
1 => [ ... ]
],
'SINGLE BURGERS' => [ ...]
]
note that the first field after "SELECT" is by default the field used by FETCH_GROUP
See in this way, the first foreach can output the title of the category, which is BREAKFASTS for example. Then the inner foreach can do the individual rows in the table.
Personally I would use a dl, dt, dd tag setup as my structure (hinted in the comments, i really am to lazy today to code all the html, <sigh>)
https://www.w3schools.com/tags/tag_dt.asp
UPDATE
You may want to check your query
...
WHERE
items.restid AND ...
Seems to be flawed, just saying. I saw this while optomizing the query for sorting.
SELECT
c.catname,
i.itemsname,
i.itemsprice,
i.itemsdescrip,
c.catdes,
c.status,
c.collapse,
c.catid
FROM
(
SELECT c0.catid FROM categories AS c0 WHERE c0.restid = :restid SORT BY c0.catname
) AS t
JOIN
categories AS c ON t.catid=c.catid
LEFT JOIN
items AS i ON items.catid=categories.catid
WHERE
items.restid = ? //< this is the error/omission/strangeness i pointed out above.
So a few things to note, first you should base the query off the categories, as an empty category should be shown, while an item without a category will blow it all to bits ( basically, ie how can you group them by the category if they have none ) You'll wind up with some hodgepoge of items with no category at the end, of course based on your example I'm assuming a Many to One relationship. For example One category can have Many items, and Many items can belong to a category. (it's probably more ideal to do a Many to Many, but that's another story for another day)
The reason the above query is more optimized is the inner query, creates only a small temp table using the catid, And sorts on just the data from the cat table and only the data that is pulled by the where.
Then as we move to the outer query, they basically inherent the sort from the join, and we can pull the rest of the data from that. It's typically about 2-10x faster this way (of course I haven't test this particular query) in theory. Of course this is a bit more complex/advanced query and is optional, but it should improve sort performance if my mind is in the right place tonight... lol
Also I abbreviated your table names (alias), as I said I am lazy like that. Sadly my answers are always so long, dont ask me how I see all these issues, it's just experience or how my dyslexic brain works?
Lastly, if you really must use mysqli, you can manually group them with something like this.
$data = [];
while(false !== ($row = $res->fetch_assoc())){
$key = $row['catname'];
if(!isset($data[$key])) $data[$key] = [];
$data[$key][] = $row;
}
It's all so prosaic (common place, non-poetic) at this point for me.
Good luck.
$cat = mysqli_query($connect, "SELECT
categories.catname,
items.itemsname,
items.itemsprice,
items.itemsdescrip,
categories.catdes,
categories.catid
FROM items
LEFT JOIN categories ON items.catid=categories.catid
WHERE items.restid AND categories.restid = 12");
if($cat === FALSE) {
die(mysqli_error());
}
$data = [];
while ($rowb = mysqli_fetch_array($cat)) {
$key = $rowb['catname'];
if(!isset($data[$key])) $data[$key] = [];
$data[$key][] = $rowb;
foreach($data as $catname => $rowbs){
echo "
<dl><button class='accordiontry'><dt>$catname</dt></button>";
<div class='panel1'>
foreach($rowbs as $rowb){
echo"<div class='rmenu'>
<dd><span class='item'>{$rowb['itemsname']}</span>
<span class='price'>£{$rowb['itemsprice']}</span><br>
<span class='des'>{$rowb['itemsdescrip']}</span> ";
}
echo"</div></dd>
</div></dl>";
}
}
}
I have a MySQL query that shows a list of items after joining two tables:
SELECT contenidos.tituloContenido FROM contenidos
JOIN cursosContenidos ON cursosContenidos.contenidoID = contenidos.contenidoID
WHERE cursosContenidos.cursoID = ?;
There's no problem with this query, but, when I change it to show another field of the contenidos table, the results are duplicated.
So they get duplicated when doing:
SELECT contenidos.contenidoID, contenidos.tituloContenido FROM contenidos
JOIN cursosContenidos ON cursosContenidos.contenidoID = contenidos.contenidoID
WHERE cursosContenidos.cursoID = ?;
I've tried adding a GROUP BY cursosContenidos.contenidoID clause, and DISTINCT as well, but they keep appearing duplicated. Any idea on why?
To retrieve the results, I'm using PHP:
$mostrarContenidos = $conectar1->prepare("
SELECT contenidos.tituloContenido FROM contenidos
JOIN cursosContenidos ON cursosContenidos.contenidoID = contenidos.contenidoID
WHERE cursosContenidos.cursoID = ?;
");
$mostrarContenidos->bindParam(1, $cursoID);
$mostrarContenidos->execute();
$contenidos = $mostrarContenidos->fetch(PDO::FETCH_ASSOC);
if ($contenidos) {
echo '<h2>Contenidos del Curso</h2>';
foreach ($contenidos as $value) {
echo 'Id: '.$contenidos['contenidoID'].'<br>';
echo 'Title: '.$contenidos['tituloContenido'].'<br>';
}
} else {
echo 'error retrieving results';
}
The expected result is:
Id: 1
Title This is my super title
What I get:
Id: 1
Title This is my super title
Id: 1
Title This is my super title
Your SQL query is most likely not returning multiple rows - you are only outputting it twice. This is because your foreach statement loops over each column in the single row you've fetched, rather than each row of the result set.
To clarify a bit further, this line just fetches the first (and probably only) row:
$contenidos = $mostrarContenidos->fetch(PDO::FETCH_ASSOC);
The foreach loop goes through each column in the row, and outputs info about the whole row for each column.
If you want $contenidos to be an array of all rows, you could do this instead:
$contenidos = $mostrarContenidos->fetchAll(PDO::FETCH_ASSOC);
The problem is not in the query, but in the php.
In your foreach-loop you assign the result-array-elements to $value, but then you don't use $value.
You should use :
echo 'Id: '.$value['contenidoID'].'<br>';
echo 'Title: '.$value['tituloContenido'].'<br>';
This should do it: GROUP BY contenidos.contenidoID, contenidos.tituloContenido
Should work with distinct
SELECT distinct contenidos.contenidoID, contenidos.tituloContenido FROM contenidos
JOIN cursosContenidos ON cursosContenidos.contenidoID = contenidos.contenidoID
WHERE cursosContenidos.cursoID = ?;
I am sure that somewhere in the web this question has been already asked but i have not found it, because i don't know for what exactly i should search. So i will try to describe the problem:
I have a Blog written in PHP and a SQL-database, where i receive the needed data.
Each Blog entry contains 1 image and 1 text-field and has its own id.
To get this data i execute this query (pseudo-code) -> this is working fine:
foreach($db->query("SELECT news.id, news.position, news_text.date, news_text.text, news_images.image
FROM news
LEFT OUTER JOIN news_text ON news.id=news_text.id
LEFT OUTER JOIN news_images ON news_images.id = news.id
ORDER BY position") as $row){
echo "{$row['id']}";
echo "{$row['position']}";
echo "{$row['date']}";
echo "{$row['text']}";
echo "{$row['image']}";
}
Now the problem starts. I want to add a comment field, where users can add a message. So for each blog-entry there can be several comments (would probably be a 1:n connection).
- I tried to add a foreach loop in a foreach loop (stupid)
- I tried with several SQL-query but only get rubbish as a result
- I don't see the logic how to connect the database news_comment with the others
Here is my simplified database:
Can someone give me a hint how i could solve this problem. Result should be:
foreach($db->query("SELECT news.id, news.position, news_text.date, news_text.text, news_images.image
FROM news
LEFT OUTER JOIN news_text ON news.id=news_text.id
LEFT OUTER JOIN news_images ON news_images.id = news.id
ORDER BY position") as $row){
echo "{$row['id']}";
echo "{$row['position']}";
echo "{$row['date']}";
echo "{$row['text']}";
echo "{$row['image']}";
Here i get for each blog-entry the corresponding comments..
}
Thank you.
Misch
You should retrieve comments in another one query (not in loop) using the same conditions as for retrieving news. So that after executing both queries you will have to arrays: news and comments.
Then you just need to take appropriate comments for each news item.
To do that you might need to rebuild comments array so that comment news_id will be an index of array where comments are stored.
Finally it'd look like this:
$news = [
[
'id' => ...,
'position' => ...
<so on>
]
];
$comments = [
$news[0]['id'] = [<comment array>],
<so on>
];
That's the way most framework use to have data bound in result set.
Solved it with the help of Alex(thx) and MulipleIterator. This is how it worked for me (maybe someone has a better solution).
foreach($db->query("SELECT news.id, news.position, news_text.date, news_text.text, news_images.image
FROM news
LEFT OUTER JOIN news_text ON news.id=news_text.id
LEFT OUTER JOIN news_images ON news_images.id = news.id
ORDER BY position") as $row)
{
$news_id[] = $row['id'];
$news_text[] = $row['news_text'];
$news_images[] = $row['news_images'];
$values = new MultipleIterator();
$values->attachIterator(new ArrayIterator($news_id));
$values->attachIterator(new ArrayIterator($news_text));
$values->attachIterator(new ArrayIterator($news_images));
}
foreach($values as $value)
{
list($news_text, $news_images, $news_id) = $value;
{
echo '$news_text';
echo '$news_images';
foreach($db->query("SELECT comment FROM news_comment WHERE id = $news_id ") as $row)
{
echo "{$row['comment']}";
}
}
}
I have a sql query that groups results. The print_r shows the results I would like are there. Now I would like to display these results in table groups i.e. Table One with a list of all the seats with that table, Table Two etc.
I have tried all kinds of things to get this done to no avail... here is the code. I can easily display the records - but would like to display them by groups arghhh
$seatings = $wpdb->get_results("SELECT
bb_cl_seating.table,
bb_cl_seating.seat,
bb_cl_seating.seat_id,
bb_events_attendee.fname,
bb_events_attendee.lname,
bb_events_attendee.email
FROM bb_cl_seating
LEFT JOIN bb_events_attendee
ON bb_cl_seating.id = bb_events_attendee.id
WHERE bb_cl_seating.event_id = '1' ");
foreach ($seatings as $seating) {
} // Ends foreach
$seatings = $wpdb->get_results("SELECT
bb_cl_seating.table,
bb_cl_seating.seat,
bb_cl_seating.seat_id,
bb_events_attendee.fname,
bb_events_attendee.lname,
bb_events_attendee.email
FROM bb_cl_seating
LEFT JOIN bb_events_attendee
ON bb_cl_seating.id = bb_events_attendee.id
WHERE bb_cl_seating.event_id = '1' ");
foreach ($seatings as $seating => $group) {
//$data[table] = seat,seat2,seat3...
$data[$group[1]] = $data[$group[1]].','.$group[2];
} // Ends foreach
In this example create one array $data of tables with yours seats sort by ','.
Its help?
This did the trick - hope it helps someone else:-)
$seatings = $wpdb->get_results("SELECT bb_cl_seating.table, bb_cl_seating.seat, bb_cl_seating.seat_id, bb_events_attendee.fname, bb_events_attendee.lname, bb_events_attendee.email
FROM bb_cl_seating
LEFT JOIN bb_events_attendee ON bb_cl_seating.id = bb_events_attendee.id
WHERE bb_cl_seating.event_id = '1'
ORDER BY bb_cl_seating.table, bb_cl_seating.seat
");
$table_title = '';
foreach($seatings as $result => $col) {
if($table_title !== $col->table) {
$table_title = $col->table;
echo "<strong>$table_title</strong>";
echo "<br />";
}
I'm building a simple web app at the moment that I'll one day open source. As it stands at the moment, the nav is generated on every page load (which will change to be cached one day) but for the moment, it's being made with the code below. Using PHP 5.2.6 and MySQLi 5.0.7.7, how more efficient can the code below be? I think joins might help, but I'm after advice. Any tips would be greatly appreciated.
<?php
$navQuery = $mysqli->query("SELECT id,slug,name FROM categories WHERE live=1 ORDER BY name ASC") or die(mysqli_error($mysqli));
while($nav = $navQuery->fetch_object()) {
echo '<li>';
echo ''. $nav->name .'';
echo '<ul>';
$subNavQuery = $mysqli->query("SELECT id,name FROM snippets WHERE category='$nav->id' ORDER BY name ASC") or die(mysqli_error($mysqli));
while($subNav = $subNavQuery->fetch_object()) {
echo '<li>';
echo ''. $subNav->name .'';
echo '</li>';
}
echo '</ul>';
echo '</li>';
}
?>
You can run this query:
SELECT c.id AS cid, c.slug AS cslug, c.name AS cname,
s.id AS sid, s.name AS sname
FROM categories AS c
LEFT JOIN snippets AS s ON s.category = c.id
WHERE c.live=1
ORDER BY c.name, s.name
Then iterate thru the results to create the proper heading like:
// last category ID
$lastcid = 0;
while ($r = $navQuery->fetch_object ()) {
if ($r->cid != $lastcid) {
// new category
// let's close the last open category (if any)
if ($lastcid)
printf ('</li></ul>');
// save current category
$lastcid = $r->cid;
// display category
printf ('<li>%s', $r->cslug, $r->cname);
// display first snippet
printf ('<li>%s</li>', $r->cslug, $r->sname, $r->sname);
} else {
// category already processed, just display snippet
// display snippet
printf ('<li>%s</a>', $r->cslug, $r->sname, $r->sname);
}
}
// let's close the last open category (if any)
if ($lastcid)
printf ('</li></ul>');
Note that I used printf but you should use your own function instead which wraps around printf, but runs htmlspecialchars thru the parameters (except the first of course).
Disclaimer: I do not necessarily encourage such use of <ul>s.
This code is just here to show the basic idea of processing hierarchical data got with one query.
First off, you shouldn't query your database in your view. That would be mixing your business logic and your presentation logic. Just assign the query results to a variable in your controller and iterate through it.
As for the query, yup a join can do that in 1 query.
SELECT * -- Make sure you only select the fields you want. Might need to use aliases to avoid conflict
FROM snippets S LEFT JOIN categiries C ON S.category = C.id
WHERE live = 1
ORDER BY S.category, C.name
This will get you an initial result set. But this won't give you the data nicely ordered like you expect. You'll need to use a bit of PHP to group it into some arrays that you can use in your loops.
Something along the lines of
$categories = array();
foreach ($results as $result) {
$snippet = array();
//assign all the snippet related data into this var
if (isset($categories[$result['snippets.category']])) {
$categories[$result['snippets.category']]['snippet'][] = $snippet;
} else {
$category = array();
//assign all the category related data into this var;
$categories[$result['snippets.category']]['snippet'] = array($snippet);
$categories[$result['snippets.category']]['category'] = $category;
}
}
This should give you an array of categories which have all the related snippets in an array. You can simply loop through this array to reproduce your list.
I'd try this one:
SELECT
c.slug,c.name,s.name
FROM
categories c
LEFT JOIN snippets s
ON s.category = c.id
WHERE live=1 ORDER BY c.name, s.name
I didnt test it, though. Also check the indexes using the EXPLAIN statement so MySQL doesnt do a full scan of the table.
With these results, you can loop the results in PHP and check when the category name changes, and build your output as you wish.
Besides a single combined query you can use two separate ones.
You have a basic tree-structure here with branch elements (categories table) and leaf elements (snippets table). The shortcoming of the single-query solution is that you get owner brach-element repeatedly for every single leaf element. This is redundant information and depending on the number of leafs and the amount of information you query from each branch element can produce large amount of additional traffic.
The two-query solution looks like:
$navQuery = $mysqli->query ("SELECT id, slug, name FROM categories WHERE live=1 ORDER BY name")
or die (mysqli_error ($mysqli));
$subNavQuery = $mysqli->query ("SELECT c.id AS cid, s.id, s.name FROM categories AS c LEFT JOIN snippets AS s ON s.category=c.id WHERE c.live=1 ORDER BY c.name, s.name")
or die (mysqli_error ($mysqli));
$sub = $subNavQuery->fetch_object (); // pre-reading one record
while ($nav = $navQuery->fetch_object ()) {
echo '<li>';
echo ''. $nav->name .'';
echo '<ul>';
while ($sub->cid == $nav->id) {
echo '<li>';
echo ''. $sub->name .'';
echo '</li>';
$sub = $subNavQuery->fetch_object ();
}
echo '</ul>';
}
It should print completely the same code as your example
$navQuery = $mysqli->query("SELECT t1.id AS cat_id,t1.slug,t1.name AS cat_name,t2.id,t2.name
FROM categories AS t1
LEFT JOIN snippets AS t2 ON t1.id = t2.category
WHERE t1.live=1
ORDER BY t1.name ASC, t2.name ASC") or die(mysqli_error($mysqli));
$current = false;
while($nav = $navQuery->fetch_object()) {
if ($current != $nav->cat_id) {
if ($current) echo '</ul>';
echo ''. $nav->cat_name .'<ul>';
$current = $nav->cat_id;
}
if ($nav->id) { //check for empty category
echo '<li>'. $nav->name .'</li>';
}
}
//last category
if ($current) echo '</ul>';