I have the following table:
Comments
--------
id PK
cid
content
uid
comment
If the content is image /i want it to print ?imgID=$cid and get the data from the row title from the table images and if it's a thread I want it to print ?threadID=$cid and get the title from the table threads and so on. How should I do this?
<h3>Latest comments</h3>
<?php
$rs = mysql_query("
SELECT *
FROM comments
LEFT JOIN threads
ON threads.id = comments.cid
WHERE comments.uid = $id
");
while ($row = mysql_fetch_assoc($rs)) {
echo $row['title'];
}
while ($row = mysql_fetch_assoc($rs)) {
if($row['content'] == "image") {
echo "?imgID={$cid}";
$title = mysql_fetch_assoc(mysql_query("SELECT title from images WHERE id = '$cid'");
} elseif ($row['content'] == "thread") {
echo "?threadID={$cid}";
$title = $row['title']; // Will only work as long as there is no title field in comments, oherwise use threads.title
}
}
echo $title;
There you go. The curly brackets around the $cid aren't strictly nessecary, but they help avoid issues where if you are trying to print text afterwards, and it reads the variable name as something else.
$q="SELECT c.id, c.cid, c.content, c.uid, c.comment,
COALESCE(t.title,i.title) AS the_title
FROM comments c LEFT JOIN threads t ON (c.cid=t.id AND c.content='thread')
LEFT JOIN images i ON (c.cid=i.id AND c.content='image');
The above combines your two queries together and puts the title attribute in one column.
Related
I have this code, that fetches data from two tables in MySQLi.
It first has to get the title, description, status and project_id from table 1, and then get the name from table 2 using the id from table 1.
Is there a better/faster way to do this? I have about 600 rows in the tables, and it takes about 5 sec to run this query. I will also add that this example is a bit simplified, so please don't comment on the db-structure.
<?php
$results = $connect()->db_connection->query(
'SELECT title, description, status, project_id
FROM table
WHERE created_by ='.$user_id
);
if ($results) {
while ($result = $results->fetch_object()) {
$res = $connect()->db_connection->query(
"SELECT name FROM projects WHERE id = ".$result->project_id
);
if ($res) {
while ($r = $res->fetch_object()) {
echo $r->name;
}
}
echo $result->title;
echo $result->status;
}
}
?>
Use Query:
SELECT title,description,status,project_id
FROM table tb
inner join projects pr on pr.id = tb.project_id
WHERE created_by = $user_id
Try to use JOIN in your query.
You can find examples and description of this command here: http://www.w3schools.com/sql/sql_join.asp
Check out also this infographics:
http://www.codeproject.com/KB/database/Visual_SQL_Joins/Visual_SQL_JOINS_orig.jpg
You can use JOIN on project_id:
$results = $connect()->db_connection->query('SELECT t.title title,t.description,t.status status,t.project_id, p.name name FROM `table` t JOIN projects p ON p.id= t.project_id WHERE t.created_by ='.$user_id);
if($results){
while($result = $results->fetch_object()){
echo $result->name;
echo $result->title;
echo $result->status;
}
}
tables have aliases here - t for table and p for projects.
Also to make it faster, add index to project_id in table table, if you haven't done it yet:
$connect()->db_connection->query('ALTER TABLE `table` ADD INDEX `product_id`');
I have two table records in my database which look like this:
Table 1 with the column 1:
topic_id name
21 my computer
table 2 with columns as follows:
reply_id topic_id message
1 21 blabla
2 21 blue
In which the topic_id column in the table 2 is the foreign key of the table 1
I wanted to echo all replies in the table 2 along with the topic name (#21) in the table 1. So, I made the query like this
$q="SELECT name, message
FROM table1
LEFT JOIN table2
ON table1.topic_id = table2.topic_id
";
However, the result/ output returns the topic's name and ONLY ONE reply, but not 2 (or all) as expected. Did I miss something?
I used LEFT JOIN because some topics are still waiting for replies. In case that there is not any reply, the topic's name is still printed in browsers.
I also tried adding
GROUP BY table1.topic_id
but still NO LUCK!
Can you help? Thanks
EDIT: To clarify the question I add the php code to fetch records as follows:
As you know, The name needs to be printed only once. So, I code like this:
$tid = FALSE;
if(isset($_GET['qid']) && filter_var($_GET['qid'], FILTER_VALIDATE_INT, array('min_range'=>1) ) ){
// create the shorthand of the question ID:
$tid = $_GET['tid'];
// run query ($q) as shown above
$r = mysqli_query($dbc, $q) or die("MySQL error: " . mysqli_error($dbc) . "<hr>\nQuery: $q");
if (!(mysqli_num_rows($r) > 0) ){
$tid = FALSE; // valid topic id
}
}//isset($_GET['qid']
if ($tid) { //OK
$printtopic = FALSE; // flag variable to print topic once
while($content = mysqli_fetch_array($r, MYSQLI_ASSOC)){
if (!$printtopic) {
echo $content['name'];
$printtopic= TRUE;
}
}
} // end of $tid
// Print the messages if any:
echo $content['message'];
Try this with inner join
$q="SELECT name, message
FROM table1
INNER JOIN table2
ON table1.topic_id = table2.topic_id";
Try:
$q="SELECT table2.reply_id, table1.name, table2.message
FROM table2
LEFT JOIN table1
ON table1.topic_id = table2.topic_id
";
After struggling with this issue, I can find out that the problem is that I had to change the query to INNER JOIN and add the WHERE clause like this:
WHERE table2.reply_id = {the given topic_id}
Then it works well!
Sorry to disturb you all!
I have this sql statement joining 3 tables:
SELECT * FROM `int_news`
LEFT JOIN tl_member ON int_news.member_id = tl_member.id
LEFT JOIN tl_news ON int_news.news_id = tl_news.id
The 3 Tables are like this:
Table 1 (int_news)
ID, member_id, news_id
Table 2 (tl_member)
id, firstname, lastname
Table 3 (tl_news)
id, headline
So far so good, but it seems i have a big blackhole in my head making me unable to solve how to output the result like this
For each "headline" i want ALL lastnames e.g.
headline 1 Jonny
Walker
Jim
headline 2 Knopf
Jon
Doe
It sounds your looking something like a pivot so if you group your query by headline, it will display each lastname as a column.
I found this good tutorial on pivots for mysql that might help you http://www.artfulsoftware.com/infotree/queries.php#78
headline 1 Jonny Walker Jim
headline 2 Knopf Jon Doe
Here is a loop that would do that *Forgive my php it's been a while.
$curHeadline = "";
while ( $db_field = mysql_fetch_assoc($result) ) {
if($curHeadline != $db_field['headline'])
{
$curHeadline = $db_field['headline'];
print $curHeadline . $db_field['ID']
}
print $db_field['lastName'] . "<BR>";
}
Try this for mysql :
SELECT tlnews.headline, GROUP_CONCAT(tl_member.last_name)
FROM `int_news` LEFT JOIN tl_member ON int_news.member_id = tl_member.id
LEFT JOIN tl_news ON int_news.news_id = tl_news.id
GROUP BY 1;
Expected Output:
headline1 Johnny,Walker,Jim
headline2 Knopf,Jon,Doe
...
Would something like this vaguely reflect your situation?
<?php
$sql = "
SELECT
`int_news`.`ID` AS `int_news_ID`,
`int_news`.`member_id`,
`int_news`.`news_id`,
`t1_member`.`id` AS `t1_member_id`,
`t1_member`.`firstname`,
`t1_member`.`lastname`, /* desired */
`t1_news`.`id` AS `t1_news_id`,
`t1_news`.`headline` /* desired */
FROM
`int_news`
LEFT JOIN `tl_member` ON `int_news`.`member_id` = `tl_member`.`id`
LEFT JOIN `tl_news` ON `int_news`.`news_id` = `tl_news`.`id`
";
$res = mysql_query($query);
$arrHeadings = array();
while($row = mysql_fetch_assoc($res)) {
// We want to output the results in groups of headings
$arrHeadings[$row['heading']][] = $row;
}
// Don't forget to cleanse for html output (unlike below)
// Loop through the headers
foreach($arrHeadings as $heading=>$arrRow) {
echo '<dl>';
echo '<dt>'.$heading.'</dt>';
echo '<dd>';
// Loop through rows with the same header
foreach($arrRow as $index=>$dbRow) {
echo $dbRow['lastname'].'<br />';
}
echo '</dd>';
echo '</dl>';
}
?>
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>';
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>';
}