Query database with comment meta - php

I have a wordpress comment box with 2 custom files, name and country, which get written to the database with the meta_key tag as comment_name and comment_country. What I need to do is display these comments which needs to include the actual comment, as well as the values of the 2 custom fields. I need to query the database as I need to retrieve ALL comments, not just comments for that particular page.
The code I (kind of) have is:
<?php
global $wpdb;
$querystr = " SELECT comment_content FROM $wpdb->comments INNER JOIN $wpdb->commentmeta ON meta_key = 'comment_name'";
$comment_info = $wpdb->get_results($querystr, OBJECT);
echo '<ul>';
// display the results
foreach($comment_info as $info) {
echo '<li class="commentBox"><p>'. $info->comment_content .'</p><h6>'. $info->meta_value .'</h6></li>';
}
echo '</ul>';
?>
As you can probably see, I need to get the comment_content field which is in wp_comments, but also combine that with the meta_value of 2 meta_keys. I obviously haven't figured out how to try and add the second meta_key/value to my code.
Can anybody help me please as I am at my wits end with this!
UPDATE:
I can now query the info I need. I had to use aliases so I can query 2 different meta_keys with corresponding values. The code:
$querystr =
" SELECT * FROM $wpdb->comments, $wpdb->commentmeta AS commentmeta1, $wpdb->commentmeta AS commentmeta2
WHERE $wpdb->comments.comment_ID = commentmeta1.comment_id
AND $wpdb->comments.comment_ID = commentmeta2.comment_id
AND commentmeta1.meta_key = 'comment_name'
AND commentmeta2.meta_key = 'comment_country'
ORDER BY $wpdb->comments.comment_date DESC";
$comment_info = $wpdb->get_results($querystr, OBJECT);
So what I now need to do is reference commentmeta1 and commentmeta2 in my loop to output the 2 different values. The code I am using:
echo '<ul>';
// display the results
foreach($comment_info as $info) {
echo '<li class="commentBox"><p>' . $info->comment_content . '</p><h6>' . $info->meta_value['commentmeta1'] . ', ' . $info->meta_value['commentmeta2'] . '</h6></li>';
}
echo '</ul>';
The meta values don't output as they should, it basically takes the first letter only of my commentmeta2 ('comment_country'), and duplicates it for each instance (pic below). If I query only one meta key I can display the value in my loop fine by simply running $info->meta_value. How can I simply my meta_values as per my query?

How about specifying the columns you need in your SELECT statement:
SELECT comment_content, comment_name, comment_country FROM ...
Then reference them in your HTML as $info->comment_name and so on.
If you need more direction, you need to share the database schemas for your comments tables.

Sussed it! Final working code is as follows:
$querystr = " SELECT comment_content, commentmeta1.meta_value AS comment_name, commentmeta2.meta_value AS comment_country
FROM $wpdb->comments, $wpdb->commentmeta AS commentmeta1, $wpdb->commentmeta AS commentmeta2
WHERE $wpdb->comments.comment_ID = commentmeta1.comment_id
AND $wpdb->comments.comment_ID = commentmeta2.comment_id
AND commentmeta1.meta_key = 'comment_name'
AND commentmeta2.meta_key = 'comment_country' ORDER BY $wpdb->comments.comment_date DESC";
$comment_info = $wpdb->get_results($querystr, OBJECT);
echo '<ul>';
// display the results
foreach($comment_info as $info) {
echo '<li class="commentBox"><p>' . $info->comment_content . '</p>
<h6>' . $info->comment_name . ', ' . $info->comment_country . '</h6></li>';
}
echo '</ul>';
I basically needed to pass the alias into SELECT and assign a new alias which I could reference in my loop.

Related

inner join gives back multiple values

I have products, All of these products have for example. An id, name and price. All of these products are connected in the database like this:
Since I don't have 10 reputation... Here is a link to a picture http://puu.sh/oS95c/b7b5b17427.png
What I want to achieve is to have products that are connected to another product show up on the screen using inner join. However instead of getting the connected items back I get back every item of the right column even if they are not connected.
Here is a link to get a better view of the database: http://puu.sh/oSBF2/1af1ce3751.png
$sql = "SELECT AFBEELDING_KLEIN, PRODUCTNAAM, PRIJS
FROM PRODUCT
inner JOIN PRODUCT_GERELATEERD_PRODUCT
ON PRODUCT.PRODUCTNUMMER=PRODUCT_GERELATEERD_PRODUCT.PRODUCTNUMMER_GERELATEERD_PRODUCT";
$result = sqlsrv_query($db, $sql);
$data = sqlsrv_fetch_array($result);
while($data = sqlsrv_fetch_array($result)) {
$big_picture = '<img src="../' . $data["AFBEELDING_KLEIN"] . '"' . 'alt="product">';
$link = '<a href="../productpaginas/' . $data["PRODUCTNAAM"] . '.php"<p> ' . $data["PRODUCTNAAM"] . '</p></a>';
$price = '<h2> €' . $data["PRIJS"] . '</h2>';
echo '<div class="product">';
echo $big_picture;
echo $link;
echo $price;
echo '</div>';
}
Since you immune to questions and don't provide more information, we can only guess.
You might want a m:n link back to the product table itself.
SELECT
p1.PRODUCTNUMMER, p2.AFBEELDING_KLEIN, p2.PRODUCTNAAM, p2.PRIJS
FROM
PRODUCT AS p1
INNER JOIN
PRODUCT_GERELATEERD_PRODUCT AS pgp
ON
p1.PRODUCTNUMMER = pgp.PRODUCTNUMMER
INNER JOIN
PRODUCT AS p2
ON
pgp.PRODUCTNUMMER_GERELATEERD_PRODUCT = p2.PRODUCTNUMMER
;

Display Multiple PHP Queries

I need to display multiple queries (they can't be combined into one large query, at least I don't think so) together in a webpage. I'll explain a little about the queries to give an idea of the problem. I have a database in MySQL with 3 question tables of the same format linked to a response table via a classid. The response table is linked to an instructor table via an instructorid. I need to display a table showing all 3 question scores for each record existing for an instructor, with each table followed by some text indicating which question had the highest value as well as the least. I created a uniontbl view in MySQL which is a union query with fields ClassID, Average and TableName. What I have so far is:
$query2 = "SELECT `tbl_instructor`.`FirstName`,
`tbl_instructor`.`LastName`,
`tbl_term`.`TermID`,
`tbl_ucourse`.`Abbreviation`,
`tbl_ucourse`.`Series`,
`tbl_uquestion01`.`Average` AS `Q1`,
`tbl_uquestion02`.`Average` AS `Q2`,
`tbl_uquestion03`.`Average` AS `Q3`
FROM `tbl_instructor`
LEFT JOIN `undergrad`.`tbl_uresponse` ON `tbl_instructor`.`InstructorID` = `tbl_uresponse`.`InstructorID`
LEFT JOIN `undergrad`.`tbl_ucourse` ON `tbl_uresponse`.`CourseID` = `tbl_ucourse`.`CourseID`
LEFT JOIN `undergrad`.`tbl_Term` ON `tbl_UResponse`.`TermID` = `tbl_Term`.`TermID`
LEFT JOIN `undergrad`.`tbl_uquestion01` ON `tbl_uresponse`.`ClassID` = `tbl_uquestion01`.`ClassID`
LEFT JOIN `undergrad`.`tbl_uquestion02` ON `tbl_uresponse`.`ClassID` = `tbl_uquestion02`.`ClassID`
LEFT JOIN `undergrad`.`tbl_uquestion03` ON `tbl_uresponse`.`ClassID` = `tbl_uquestion03`.`ClassID`
WHERE CONCAT(LastName, ', ', FirstName, ' (', UserID, ')') = '{$instructor}'";
$query3 = "SELECT `tbl_instructor`.`FirstName`,
`tbl_instructor`.`LastName`,
`uniontbl`.`ClassID`,
`uniontbl`.`TableName`,
`tbl_uresponse`.`InstructorID`
FROM `tbl_Instructor`
LEFT JOIN `undergrad`.`tbl_uresponse` ON `tbl_instructor`.`InstructorID` = `tbl_uresponse`.`InstructorID`
LEFT JOIN `undergrad`.`uniontbl` ON `tbl_uresponse`.`ClassID` = `uniontbl`.`ClassID`
WHERE CONCAT(LastName, ', ', FirstName, ' (', UserID, ')') = '{$instructor}'
ORDER BY `uniontbl`.`Average` DESC
LIMIT 1";
$query4 = "SELECT `tbl_instructor`.`FirstName`,
`tbl_instructor`.`LastName`,
`uniontbl`.`ClassID`,
`uniontbl`.`TableName`,
`tbl_uresponse`.`InstructorID`
FROM `tbl_Instructor`
LEFT JOIN `undergrad`.`tbl_uresponse` ON `tbl_instructor`.`InstructorID` = `tbl_uresponse`.`InstructorID`
LEFT JOIN `undergrad`.`uniontbl` ON `tbl_uresponse`.`ClassID` = `uniontbl`.`ClassID`
WHERE CONCAT(LastName, ', ', FirstName, ' (', UserID, ')') = '{$instructor}'
ORDER BY `uniontbl`.`Average` ASC
LIMIT 1";
$result2 = mysqli_query($query2);
$result3 = mysqli_query($query3);
$result4 = mysqli_query($query4);
while($row2 = mysqli_fetch_assoc($result2))
{
echo "<br>";
echo"<table>";
echo "<tr>";
echo "<th>Q1</th>";
echo "<th>Q2</th>";
echo "<th>Q3</th>";
echo "</tr>";
echo "<tr>";
echo "<td>" . $row2['Q1'] . "</td>";
echo "<td>" . $row2['Q2'] . "</td>";
echo "<td>" . $row2['Q3'] . "</td>";
echo "</tr>";
echo"<br>";
echo "</table>";
while($row3 = mysqli_fetch_assoc($result3))
{
echo $row3['TableName'];
}
echo "<br>";
while($row4 = mysqli_fetch_assoc($result4))
{
echo $row4['TableName'];
}
echo "<br>";
}
So, how I've tried to tackle the problem is using the second and third queries to determine which questions had the highest and lowest score from the uniontbl view and displaying that after each table containing the question scores. The problem is that the second and third queries ONLY display after the first table (or record) and do not show at all after that. I have a feeling that the problem lies in the actual queries themselves but I can't think of another way to solve the problem. P.S. I know my code isn't the best (echoing HTML and such) but I'm just trying to get it to work...
After you print the first row of $result2, you fetch all the rows of $result3 and $result4. So after you print the second row of $result2, there's nothing left to fetch from the second and third queries.
Since the second and third queries use LIMIT 1, there's just one row for each of them. You could fetch them each once, and then display that row after each row of the first query. But I'm not sure why you need to display the same thing multiple times. Maybe you should just show the output of these two queries once, at the beginning or end, rather than after each row.
Also, do you really want to create a whole new table for each row of $result2? Usually each row is just a row in one big table, not a separate table with just one row for each row from the DB.

Return a single MySQL results with multiple values from a row

I'm trying to do a simple search query in php with:
SELECT * FROM `books` NATURAL JOIN `authors` WHERE `books`.`title` LIKE '%$search%
In the returned result I expect the same book title to have more then one author. I would like to display the title just once with multiple authors, and can't seem to find an elegant solution to print the wanted values without doing at least 2 loops with multiple counters like so:
$last = ""; $i = 0;
while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
$current = $row['title'];
if ($current != $last) {
$i += 1;
$books[$i]['title'] = $current;
$books[$i]['author'][] = $row['author'];
$books[$i]['pages'] = $row['pages'];
} else {
$books[$i]['author'][] = $row['author'];
}
$last = $current;
}
foreach ($books as $book) {
$return_result .= 'Title: ' . $book['title'] . '<br />';
foreach ($book['author'] as $author) {
$return_result .= 'Author: ' . $author . '<br />';
}
$return_result .= 'Pages: ' . $book['pages'] . '<br />';
$return_result .= '<br />';
}
Please tell me if there's a better way to do this, maybe in MySQL ?
The GROUP_CONCAT function will give a delimited list of authors.
SELECT b.title, b.pages, GROUP_CONCAT(a.author)
FROM books b
NATURAL JOIN authors a
WHERE b.title like '%$search%'
GROUP BY b.title, b.pages;
This can be accomplished with GROUP_CONCAT()
SELECT *, GROUP_CONCAT(`authors`.`author`) AS `authors`
FROM `books`
NATURAL JOIN `authors`
WHERE `books`.`title` LIKE '%$search%'
GROUP BY `books`.`title`
Now your list of authors for each book will be comma separated under the field name authors for each book if you want them hyphen separated or another delimiter then use
GROUP_CONCAT(`authors`.`author` SEPARATOR ' - ')
NOTE: Grouping by title is not be the best way to group your search of books as many books can have the same title thus messing up the results. It'd be best to group by ISBN number or some other unique identifier for each book.

Inefficient SQL Query

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>';

PHP MYSQL showing posts with comments

I dont know where to start let me make it simple...
I have 2 tables posts and comments, posts consisting 2 fields: id and post_name and comments consisting of 3 fields: id, comment and post_id. I have some posts with few comments on those.
How can I display all posts with the related comments using while loop?
Thanks in advance....
SELECT `p`.`post_name`, `c`.`comment`
FROM `posts` AS `p`
JOIN `comments` AS `c` ON(`p`.`id` = `c`.`post_id`)
GROUP BY `p`.`id`;
This will give you a resultset where each row contains a comment and the name of the post that goes with that comment.
You'll need a nested loop to accomplish what you are looking for. Here's a sample that should help get you started.
$posts_result = mysql_query("SELECT your, columns FROM poststable");
if(mysql_num_rows($posts_result) > 0){
$comments_result = mysql_query("SELECT comments FROM commentstable WHERE comments.post_id = $post_id");
while($post = mysql_fetch_array($posts_result){
// print post details
if(mysql_num_rows($comments_result) > 0){
while($comment = mysql_fetch_array($comments_result)) {
// print comment details
}
} else {
// print comments default for when there are no comments
}
} // End posts while
} else {
// print no posts found
}
Run query
select * from posts p, comments c where p.id=c.post_id group by p.id;
and iterate over the results and display them as you want.
This should get you started:
$sql = 'SELECT c.*, p.post_name FROM posts p INNER JOIN comments c ON p.id = c.post_id ORDER BY p.id DESC, c.post_id DESC';
$result = mysql_query($sql);
$previous_post = 0;
while ($data = mysql_fetch_assoc($result)) {
if ($previous_post != $data['post_id']) {
echo '<h1>' . $data['post_name'] . '</h1>';
$previous_post = $data['post_id'];
}
echo '<p>' . $data['comment'] . '</p>';
}

Categories