How can I improve this code? - php

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

Related

PHP search box issuse

I have a problem with some php code. So, when I write some text inside search box I should get more results, but I only get 1. This happened to my when I added second query with INNER JOIN. I have no idea why I'm getting only 1 result instead of more, anyone can help?
When I remove second query, it shows me all results.
$STH = $DBH->prepare('SELECT * FROM tv_shows WHERE title like :q ORDER BY title ASC LIMIT 5');
$STH->setFetchMode(PDO::FETCH_OBJ);
$STH->execute(array(
':q' => "%$q%"
));
if($STH->rowCount()) {
while($row = $STH->fetch()) {
$poster = $row->poster;
$mtitle = $row->title;
$mrd = $row->release_date;
$mid = $row->id;
$genres = "";
$STH = $DBH->prepare('SELECT g.title from genres g INNER JOIN tv_show_genres tg ON g.id = tg.genre_id INNER JOIN tv_shows t ON t.id = tg.tv_show_id WHERE t.id = :tid');
$STH->setFetchMode(PDO::FETCH_OBJ);
$STH->execute(array(
':tid' => $mid
));
if($STH->rowCount()) {
while($row = $STH->fetch()) {
$genres .= $row->title.", ";
}
echo
'<li>
<span class="search-poster"><img src="'.$poster.'"></span>
<span class="search-title">'.$mtitle.' ('.$mrd.')</span>
<span class="search-genre">'.substr($genres,0,-2).'</span>
</li>';
}
}
}
You're using the same variable $STH for both queries. So when the outer loop gets back to the
while ($row = $STH->fetch())
line, $STH now refers to the second query. Since you've reached the end of the results from that query, calling fetch() here returns false, so this loop ends as well.
Just use different variable names, e.g. $show_STH and $genre_STH.
However, an even better solution is to use a single query.
SELECT s.poster, s.title AS show_title, s.release_date, g.title AS genre_title
FROM (SELECT *
FROM tv_shows
WHERE title like :q
ORDER BY title ASC
LIMIT 5) AS s
INNER JOIN tv_show_genres tg ON s.id = tg.tv_show_id
INNER JOIN genres g ON tg.genre_id = g.id
ORDER BY s.title
Most of the time when you find yourself performing queries in nested loops like this, you can replace it with a single query that joins the two queries.

combining two mysql queries in php

I am creating a dashboard to keep me updated on call agent status.an agent will have multiple records in the log. I need to pull the most recent status from the agent log. The only way I have found is to query the agent table to pull the agents with status changes made today and then query the agent log table to pull the most recent status.
is there a way to combine the two queries.? Here are my queries
$sql_get_agents = "SELECT id FROM agent WHERE lastchange LIKE '{$today}%'";
if($dta = mysql_query($sql_get_agents)){
while($agent = mysql_fetch_assoc($dta)){
$curr_agent[] = $agent;
}
foreach($curr_agent as $agents_online){
$get_status_sql = "SELECT a.firstname,a.lastname,al.agentid,al.agent_statusid,s.id as statusid,s.status,MAX(al.datetime) as datetime FROM agent_log al
INNER JOIN agent a ON al.agentid = a.id
INNER JOIN agent_status s ON a.agent_statusid = s.id
WHERE al.agentid = '{$agents_online['id']}'";
if($dta2 = mysql_query($get_status_sql)){
while($agent_status = mysql_fetch_assoc($dta2)){
$curr_status[] = $agent_status;
}
}
}//end for each
return $curr_status;
}//end if
Why don't you join the 2 queries into one adding the WHERE lastchange LIKE '{$today}%' condition in the second query?
Using the IN clause should work :
"SELECT a.firstname,a.lastname,al.agentid,al.agent_statusid,s.id as statusid,s.status,MAX(al.datetime) as datetime FROM agent_log al
INNER JOIN agent a ON al.agentid = a.id
INNER JOIN agent_status s ON a.agent_statusid = s.id
WHERE al.agentid IN (SELECT id FROM agent WHERE lastchange LIKE '{$today}%');
You were close with what you have. This will get rid of the need to do both queries, or query in a loop.
edit: adding example code to loop over the results as well.
edit2: changed query.
$query = "SELECT
a.firstname,
a.lastname,
al.agentid,
al.agent_statusid,
s.id as statusid,
s.status,
MAX(al.datetime) as datetime
FROM agent a
LEFT JOIN agent_log al ON al.agentid = a.id
LEFT JOIN agent_status s ON a.agent_statusid = s.id
WHERE a.lastchange LIKE '{$today}%'";
$status = array();
$results = mysql_query( $query );
while( $agent = mysql_fetch_assoc( $results ) )
$status[] = $agent;
print_r( $status );

Arranging JOIN database results

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.

Mysql Join two Id's to get there Usernames

Im trying to get in Array that contains the results from a MYSQL query.
I have 2 ids stored in the table hitlist user_id and mark_id
they need to join in the table users to retrieve there usernames that match there id's and in the future other variables.
i have this working in a weird way and was hopeing to get this working in a more efficent simple way similar to this
$Hitlists = $db->query("SELECT * FROM hitlist JOIN users ON hitlist.user_id = users.id AND hitlist.mark_id = users.id")->fetchAll();
This is the code i have that is working...for now it looks like it might give me problems later on.
<?php
$index = 0;
$Hitlists = array();
$st = $db->query("SELECT * FROM hitlist JOIN users ON hitlist.user_id = users.id")->fetchAll();
$sth = $db->query("SELECT * FROM hitlist JOIN users ON hitlist.mark_id = users.id")->fetchAll();
foreach($st as $id)
{
$Hitlists[] = $id;
}
foreach($sth as $id)
{
$Hitlists[$index]['markedby'] = $id['username'];
$Hitlists[$index]['mark_id'] = $id['mark_id'];
$index++;
}
The way you are joining the table is wrong. You can get the exact records you want, you need to join users table twice to get the username of each ID
SELECT a.*,
b.username User_name,
c.username mark_name
FROM hitlist a
INNER JOIN users b
ON a.user_id = b.id
INNER JOIN users c
ON a.mark_id = c.id
and you can access
$result['User_name']
$result['mark_name']

One query instead of two?

Here I'm making two queries with PHP. Is there something more simple? One query instead of two?
$id = mysql_real_escape_string($_GET["id"]);
$result = mysql_query("SELECT * FROM questionstable WHERE id=$id");
$row = mysql_fetch_assoc($result);
$category = $row['category'];
$main = mysql_query("SELECT name FROM categorytable WHERE id=$category");
SELECT questionstable.*, categorytable.name
FROM questionstable
INNER JOIN categorytable
ON categorytable.id = questionstable.category
WHERE questionstable.id=$id
As an aside, assuming your questionstable.id is numeric, you could use $id = (int)$_GET["id"] and save some writing. (It's also probably a safer bet. Just because it's escaped doesn't mean it's completely safe--especially when it's not within quotes [gives you a LOT of options for SQL injection]. ;-))
Please try:
SELECT name
FROM categorytable
WHERE id = (
SELECT category
FROM questionstable
WHERE id = $id
)
$id = mysql_real_escape_string($_GET["id"]);
$main = mysql_query("SELECT c.name FROM categorytable c inner join questionstable q on c.category = q.category WHERE q.id = $id");
Do not use inner join use left join instead, it won't return any result if the category is not found
SELECT questionstable.*, categorytable.name
FROM questionstable
LEFT JOIN categorytable
ON categorytable.id = questionstable.category
WHERE id=$id

Categories