Arranging JOIN database results - php

I am currently getting details from my 'social_posts' table, and then adding it's tags, the number of likes, and the number of answers it has to the resulting object. Is there a way I can be doing this without having to do extra queries in a loop?
$query = "SELECT * FROM social_posts JOIN users ON social_posts.user_id = users.id";
$posts = $this->db->query($query);
if ($posts->num_rows() > 0) {
foreach ($posts->result() as $p => $post) {
// Get the question's tags
$tags = $this->db->query("SELECT * FROM social_tags
WHERE post_id = ?", $post->post_id);
// Get the number of likes
$likes = $this->db->query("SELECT id FROM social_likes
WHERE post_id = ?", $post->post_id);
// Get the number of answers
$answers = $this->db->query("SELECT id FROM social_responses
WHERE post_id = ?", $post->post_id);
$post->tags = $tags->result();
$post->likes = $likes->num_rows();
$post->answers = $answers->num_rows();
$post->author = array(
"firstname" => $post->firstname,
"thumbnail" => $post->thumbnail,
);
}
return $posts->result();
} else {
return FALSE;
}

You may try this SQL:
SELECT
social_posts.*,
users.*,
GROUP_CONCAT(social_tags.name) AS tags,
COUNT(social_likes.id) AS likes,
COUNT(social_responses.id) AS answers
FROM
social_posts
JOIN users ON social_posts.user_id = users.id
LEFT JOIN social_tags ON social_tags.post_id = social_posts.id
LEFT JOIN social_likes ON social_likes.post_id = social_posts.id
LEFT JOIN social_responses ON social_responses.post_id = social_posts.id
GROUP BY
social_posts.id
You will get the tags as comma delimited string. Of course you need to adjust the column names to fit your database.

Related

How to add where not equal to in Query [duplicate]

This question already has answers here:
When to use single quotes, double quotes, and backticks in MySQL
(13 answers)
Closed 3 years ago.
I'm trying to add a condition as active is not qual to 1, but I can't figure it out how it's working correctly in my query.
Here is my query
$career_solutions_data = DB::select("
SELECT
career_solutions.id,
role_users.role_id,
career_solutions.user_id,
career_solutions.subject,
career_solutions.date,
career_solutions.public,
career_solutions.views,
career_solutions.optional,
career_solutions.on_offer,
career_solutions.active,
users.username,
users.profile_picture,
categories.category,
categories.category_url,
categories.color,
career_solutions_categories.category as sub_category,
career_solutions_format.category as event_format,
career_solutions_certification.category as certification
FROM career_solutions
INNER JOIN categories
ON categories.id = career_solutions.topic_category_id
INNER JOIN career_solutions_format
ON career_solutions_format.id = career_solutions.topic_format_id
INNER JOIN career_solutions_certification
ON career_solutions_certification.id = career_solutions.topic_certification_id
INNER JOIN career_solutions_categories
ON career_solutions_categories.id = career_solutions.topic_subcategory_id
INNER JOIN users
ON users.id = career_solutions.user_id
LEFT JOIN role_users on role_users.role_id = users.id
INNER JOIN privacy_settings
ON privacy_settings.user_id = users.id
WHERE users.deleted_at IS NULL
AND (
(privacy_settings.career_solutions = 0 AND public = 1 )
OR (users.id IN (
SELECT contacts.contact_id
FROM contacts
WHERE contacts.user_id = $id
)
)
)
OR users.id = $id
ORDER BY date desc limit 5000
");
$role = User::with('role')
->where ('id', '=', $id)
->first();
// $career_solutions_data;
foreach ($career_solutions_data as $career_solution)
{
preg_match('/<img.+src=[\'"](?P<src>.+?)[\'"].*>/i', $career_solution->optional, $image);
if(isset($image['src']))
{
$type_picture = $image['src'];
}
else{
$type_picture = "";
}
$temp_soluation = array();
$temp_soluation['type'] = 'Career Solution';
$temp_soluation['typee'] = 'briefcase';
$temp_soluation['subject'] = $career_solution->subject;
$temp_soluation['information'] = $career_solution->optional;
$temp_soluation['category'] = $career_solution->category;
$temp_soluation['category_url'] = $career_solution->category_url;
$temp_soluation['color'] = $career_solution->color;
$temp_soluation['all_url'] = 'search-career-solutions';
$temp_soluation['type_url'] = 'view-career-solutions';
$temp_soluation['id'] = $career_solution->id;
$temp_soluation['date'] = $career_solution->date;
$temp_soluation['public'] = $career_solution->public;
$temp_soluation['active'] = $career_solution->active;
$temp_soluation['sub_category'] = $career_solution->sub_category;
$temp_soluation['event_format'] = $career_solution->event_format;
$temp_soluation['certification'] = $career_solution->certification;
$temp_soluation['on_offer'] = $career_solution->on_offer;
$temp_soluation['username'] = $career_solution->username;
$temp_soluation['roleMe'] = $career_solution->optional;
$temp_soluation['role'] = $role->role[0]->id;
$temp_soluation['profile_picture'] = $career_solution->profile_picture;
$temp_soluation['type_picture'] = $type_picture;
// $news_events_opinions[] = $temp_soluation;
$my_career_solution[] = $temp_soluation;
}
}
This is what I have tried to add :
WHERE `career_solutions.active` <> `1`
or
WHERE `active` <> `1`
or
WHERE `active` != `1`
but didn't working.So, I need to not displaying the posts with active = 1.I have another 3 queries, different of that, where I have used this : ->where("active","!=",1);, but here I can't use it.
The problem are the backticks around the 1: This instructs MySQL to search for a column name 1.
Try WHERE career_solutions.active <> 1

MySQLi - return two dimensional array

Is there a way I could get MySQLi to return a multi-dimensional array?
Let's say I'm selecing blog posts from the database, and each post has multiple tags. With my knowledge, I would do this:
$r = $mysqli->query("SELECT * FROM posts");
while ($post = $r->fetch_assoc()) {
//echo blog posts
$t = $mysqli->query("SELECT * FROM blog_tags INNER JOIN tags ON tags.id = blog_tags.tag_id WHERE post_tags.post_id = ".$post['id']);
while($tag = $t->fetch_assoc()){
//echo tags
}
}
But what I'd prefer is doing it like this:
$r = $mysqli->query("SELECT * FROM posts INNER JOIN post_tags ON posts.id = post_tags.post_id INNER JOIN tags ON tags.id = post_tags.tag_id");
while($post = $r->fetch_assoc()){
//echo post
foreach($post['tags'] as $tag){
//echo tags
}
}
So the return would be:
$posts = array(
"id" => 1,
"title" => "Blog post 1",
"content" => "Lorem ipsum...",
"tags" =>
array(
"tag1",
"tag2",
"tag3"
),
"posted" => "1-1-2010 11:11:11"
);
You need to use GROUP BY and GROUP_CONCAT. I'm guessing the tag name field is called name
SELECT posts.*, GROUP_CONCAT(tags.name) as tagnames FROM posts
INNER JOIN post_tags ON posts.id = post_tags.post_id
INNER JOIN tags ON tags.id = post_tags.tag_id
GROUP BY posts.id
Then when you get the results, you can explode(",", $t->tagnames) to get an array of tags.

Why does my query return the same row multiple times?

I'm trying to join two tables which share a common id, and it keeps returning a single row multiple times. Am working with codeigniter
This is the function from the model:
function get_latest_pheeds() {
$data = $this->user_keywords($this->ion_auth->user_id);
$keyword = $data;
$user_id = $this->ion_auth->user_id;
foreach($keyword as $key => $word) {
$q = "SELECT *,COUNT(pheed_comments.comment_id) as comments
FROM pheeds
LEFT JOIN pheed_comments ON pheed_comments.P_id=pheeds.pheed_id
WHERE pheed LIKE '%$word%' OR user_id='$user_id'
ORDER BY datetime DESC";
$result = $this->db->query($q);
$rows[] = $result->result();
}
return $rows;
}
Is my query wrong?
You are missing a GROUP BY for your COUNT()
$q = "SELECT *,COUNT(pheed_comments.comment_id) as comments
FROM pheeds
LEFT JOIN pheed_comments ON pheed_comments.P_id=pheeds.pheed_id
WHERE pheed LIKE '%$word%' OR user_id='$user_id'
GROUP BY pheed_id, pheed
ORDER BY datetime DESC";
Now, since you are using SELECT *, there may be more columns returned with the COUNT(). For accurate results, you also must list them in the GROUP BY:
GROUP BY pheed_id, pheed, othercol1, othercol2, othercol3

How can I improve this code?

Could I somehow only use only 1 sql query for this?
showthread.php
// Get Topic subject etc
$threadID = isset($_GET['threadID']) ? intval($_GET['threadID']) : 0;
$result = mysql_query("SELECT * FROM topics WHERE id = $threadID");
// Fetch rows
$row = mysql_fetch_assoc($result);
$subject = htmlspecialchars($row['subject']);
echo '<h2>'.$subject.'</h2>';
// Get posts that belong to this topic!
$posts = mysql_query("SELECT * FROM posts INNER JOIN users ON users.id = posts.user_id WHERE posts.topic_id = $threadID");
// posts.....
while ($post = mysql_fetch_assoc($posts)) {
echo '<br>'.$post['message'].'';
}
From my understanding, you should be able to get all the information you need from something like this? (Plus or minus any missing columns)
SELECT topics.subject, posts.message
FROM posts
INNER JOIN users ON users.id = posts.user_id
INNER JOIN topics ON topics.id = posts.topic_id
WHERE posts.topic_id = $threadID
Use mysqli
Use real_escape_string
Use Prepared statement or PDO

PHP: Active record table joins

I have an app that uses the codeigniter CXTags tagging library.
The database structure is as follows:
posts
id
tags_ref
row_id
table
tag_id
tags
id
safe_tag
tag
My query basically goes if $safe_tag is not null then join tags_ref on post.id = tags_ref.row_id, join tags on tags_ref.tag_id = tags.id, where tags_ref.table = 'posts' and tags.safe_tag = 'food'
SELECT * FROM posts
JOIN tags_ref ON posts.id = tags_ref.row_id
JOIN tags ON tags_ref.tag_id = tags.id
WHERE tags.safe_tag = $safe_id
Unfortunately the query I've written in active record is not functioning properly. The query works perfectly when £safe_tag is null but when it's not I get wrong results.
function get_posts($id = NULL, $safe_tag = NULL) {
if($safe_tag != NULL){
echo $safe_tag;//debugging
$table = 'posts';
$this->db->join('tags_ref', 'posts.id = tags_ref.row_id');
$this->db->join('tags', 'tags_ref.tag_id = tags.id');
$this->db->where('tags_ref.table', $table);
$this->db->where('tags.safe_tag',$safe_tag);
}
//if an id was supplied
if ( $id != NULL ) {
$this->db->where('posts.city_id',$id);
}
// execute query
$query = $this->db->get('posts');
...
Here is the query with profiling on:
SELECT *
FROM (`posts`)
INNER JOIN `tags_ref` ON `posts`.`id` = `tags_ref`.`row_id`
INNER JOIN `tags` ON `tags_ref`.`tag_id` = `tags`.`id`
WHERE `tags_ref`.`table` = 'posts'
AND `tags`.`safe_tag` = 'food'
AND `posts`.`city_id` = '2'
Can someone have a look? I think I need a fresh set of eyes on it.
Your forgot to actually run the query inside your first if{}
if($safe_tag != NULL){
echo $safe_tag;//debugging
$table = 'posts';
$this->db->join('tags_ref', 'posts.id = tags_ref.row_id');
$this->db->join('tags', 'tags_ref.tag_id = tags.id');
$this->db->where('tags_ref.table', $table);
$this->db->where('tags.safe_tag',$safe_tag);
$this->db->get(); // here
}

Categories