Mysql query returning too many rows - php

so I have 3 tables all inner joined, I am trying to put discussions with the discussion topic on my main page, with the users name and the latest discussion message on the main page as well.
THE PROBLEM: The query is returning all messages attached to all the discussions.....I just need the last message associated with the discussion returned.
I have been at this all day and cant figure it out. I have tried group by but that just gave me an error on mysqli_fetch_array
Here is my code
$discussionquery = "SELECT discussion_messages.discussion_id, user_profile.first_name, user_profile.last_name, discussion_messages.message_text, case_discussion.discussion_title
FROM `user_profile`
INNER JOIN discussion_messages
ON (user_profile.user_id = discussion_messages.user_id)
INNER JOIN case_discussion
ON (case_discussion.discussion_id = discussion_messages.discussion_id)
WHERE discussion_messages.case_id = '$thecaseid'
ORDER BY discussion_messages.message_id DESC";
$discussionquerydata = mysqli_query($dbc, $discussionquery);
while ($row2 = mysqli_fetch_array($discussionquerydata)) {
$discussion_id = $row2['discussion_id'];
?>
<!-- Begin Recent Discussions -->
<div class="row">
<a href="discussion.php?newfact=$thecaseid'>">
<div class="col-xs-4 col-md-2">
<img src="img/client4.jpg" class="profile_picture img-rounded">
<?php echo '<h6 class="discussionname">' . $row2['first_name'] . ' ' . $row2['last_name'] . '</h6>';?>
</div>
</a>
<div class="col-xs-8 col-md-10 discussion_title">
<?php echo '<h5> '.$row2['discussion_title'].' -'. $row2['message_text'];?></h5>
<h6 class="pull-right">Dec. 25</h6>
</div>
</div>
<?php
};

You need logic to find the last message for each discussion. There is more than one way to write this condition.
The following does it using a not exists clause. This checks that there are no messages with a larger id for the discussion:
SELECT dm.discussion_id, up.first_name, up.last_name, dm.message_text, cd.discussion_title
FROM `user_profile` up INNER JOIN
discussion_messages dm
ON (user_profile.user_id = dm.user_id) INNER JOIN
case_discussion cd
ON (cd.discussion_id = dm.discussion_id)
WHERE dm.case_id = '$thecaseid' and
not exists (select 1
from discussion_messages dm2
where dm2.discussion_id = dm.discussion_id and
dm2.message_id > dm.message_id
)
ORDER BY dm.message_id DESC;

One suggestion, use table aliases. The amount of total code will be smaller and easier to understand. Use the limit clause to return 1 row.
$discussionquery = "
SELECT
m.discussion_id,
u.first_name,
u.last_name,
d.message_text,
c.discussion_title
FROM `user_profile` as u
INNER JOIN discussion_messages as m
ON (u.user_id = m.user_id)
INNER JOIN case_discussion c
ON (m.discussion_id = c.discussion_id)
WHERE
m.case_id = '$thecaseid'
ORDER BY
m.message_id DESC
LIMIT 1";

Related

SQL DISTINCT WITH TWO VARIABLES

I am creating a messaging site, with php and ajax.
there is a problem on getting conversations.
The problem is that whenever two user chat between them there is two distinct rows with id;
example
A and B is chattting and only written 4 messages to each other
messages database is like this
id senderid recieverid
1 a.id b.id
2 b.id a.id
3 b.id a.id
4 a.id b.id
My aim is getting records with this code
SELECT DISTINCT senderid, recieverid from messages WHERE (senderid = '".$pageowner."' OR recieverid='".$pageowner."')
the $pageowner is the user who logged in;
with this method i get two same conversations
a<->b and b<->a
and the code gives me two conversations on the page i want to only get one result;
my whole php code is like this
if(isset($_POST['id'])){
include 'config.php';
$pageowner = $_POST['id'];
$sql = "SELECT DISTINCT senderid, recieverid from messages WHERE (senderid = '".$pageowner."' OR recieverid='".$pageowner."')";
$result = mysqli_query($connect, $sql);
$conversations = mysqli_fetch_all($result);
$output = "";
foreach($conversations as $conversation){
$senderonmessages = $conversation[0];
$recieveronmessages = $conversation[1];
if($pageowner == $senderonmessages){
$convname = $recieveronmessages;
}else{
$convname = $senderonmessages;
}
$sql = "SELECT id, name, surname, userimage FROM users WHERE id='".$convname."' ORDER BY id" ;
$resconv = mysqli_query($connect, $sql);
$user = mysqli_fetch_assoc($resconv);
$output .= '
<div class="conversationuser" id='.$user['id'].'>
<img src="'.$user['userimage'].'">
<span id="status"></span>
<div class="conv-info">
<h4>'.$user['name'].' '.$user['surname'].'</h4>
<p>Axirinici yazdigim mesaj <span id="time">10:34 AM</span></p>
</div>
<div class="conv-additional-info">
<span id="notif">1</span>
<i class="fas fa-ellipsis-v"></i>
</div>
</div>';
}
echo $output;
}
You need to fix your sql injection problem first. If you don't do that, you won't have any data in your database to worry about because somebody will drop it.
https://www.php.net/manual/en/security.database.sql-injection.php
Also, your query gives you exactly what you are asking for: DISTINCT senderid, recieverid
For a solution to your question, I'd create a view that is something like:
create view conversations as
SELECT senderid, recieverid FROM messages GROUP BY 1, 2
UNION
SELECT receiverid, senderid FROM messages GROUP BY 1, 2
Then, you can select from this view and get what you want.
As mentioned in the comment the UNION will give you distinct so you don't even need that...

PHP mysql Select query calling more than specified data

I've been working and testing with queries, and I came across this issue which I don't understand why it's happening.
I have this code:
<?php
$query = "
SELECT sc.course_code
, c.course_name
FROM student_course sc
, courses c
WHERE sc.course_code= 'MC 101'
AND sc.id_num='A0001'
";
$result = mysqli_query($conn, $query);
if(mysqli_num_rows($result) > 0)
{
while($row = mysqli_fetch_array($result))
{
?>
<p> <h4 style="w3-wide"> <?php echo $row["course_name"];?> </h3>
<h4 style="w3-wide"><?php echo $row["course_code"];?> </h3>
<button type="button" class="w3-button w3-theme-d2 w3-margin-bottom" style = "float:right"><i></i> View Course</button></p>
<br>
And based on what I know, it should call a single data which satisfies the conditions student_course.course_code = 'MC 101' and student_course.id_num='A0001' which should only be
Statistics in Computing
MC 101
However, this is what I'm getting:
The course names are correct, but all of them have the same code. Does anyone know why this is happening? Much appreciated!
You missed a join condition,
it must me something like ON sc.course_id = c.id
SELECT sc.course_code, c.course_name
FROM student_course sc
JOIN courses c ON sc.course_id = c.id
WHERE sc.course_code= 'MC 101'
AND sc.id_num='A0001'

Inner join doesn't work with PDO and fetch assoc

For my news en post comment system I can't get the query get results from 2 tables (tbl_news and tbl_comments). In another program I made with mysqli the inner join worked but now this time with PDO I can't get it to work.
This is my code:
$newsQuery = $db->prepare("SELECT *
FROM tbl_news
INNER JOIN tbl_comments ON tbl_news.news_id = tbl_comments.news_id
ORDER BY news_id DESC
LIMIT 5");
$newsQuery -> execute();
while($newsFetch = $newsQuery->fetch(PDO::FETCH_OBJ)) {
echo "<div class='news-post'><h3 class='post-title'>" . $newsFetch->title . "</h3>
<p style='float:left'>By: <span class='post-author'>" . $newsFetch->author . "</span></p>
<p style='float:right'>Date: <span class='post-date' style='font-style:italic;'>" . $newsFetch->date . "</span></p>
<br><p>" . $newsFetch->text . "</p></div>";
if(isset($_SESSION['user']) && ($newsFetch->comments == '1')) {
echo "Comments(";
echo "<div id='commentClick'>Click <a href='#' id='openForm'>here</a> to post a comment</div>";
echo "<form class='navbar-form' id='commentForm'><input style='margin-right:5px' type='text' size='80%' name='commentText' placeholder='Type your comment here'><input type='submit' class='btn btn-primary btn-xs' value='Send'></form>";
}elseif(!isset($_SESSION['user']) && ($newsFetch->comments == '1')) {
echo "Click here to view comments. If you want to post comments please login first";
}else{
echo "Comments are disabled for this news item";
}
}
In the database I have the following values:
in tbl_news there is a news_id and in tbl_comments are comment_id, news_id and user_id.
Thanks in advance!
You need to use alias for your database table names, ex:
SELECT n.*, c.* FROM tbl_news n
INNER JOIN tbl_comments c ON n.news_id = c.news_id
ORDER BY n.news_id DESC LIMIT 5
Your inner join query should be like this
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
I mean you need to specify the tablename.columnname instead of using all (*)
EDIT
1052 Column 'news_id' in order clause is ambiguous'
This error happens when you are joining 2 or more tables in a statement and there are columns among these tables that have the same name and you didn’t prefix the column name with the table name when referencing the column in your statement.

PHP/MySQL INNER JOIN Triples the amount of rows?

I have a system where I getting images out of my database, but when it does that, there is 3x of the same images.
I have tried with different ways, DISTINCT and such, but I have no clue how I fix this.
Here is my query code:
<?php
$id = $_GET['id'];
$query = "SELECT DISTINCT * FROM billeder INNER JOIN album ON fk_album_ID = $id";
$result = mysqli_query($con, $query);
while($row = mysqli_fetch_assoc($result))
{
$thumb_src = 'billeder/thumb_'.$row['billeder_sti'];
$full_src = 'billeder/'.$row['billeder_sti'];
echo "
<div class='ikon'>
<a href='$full_src'>
<img src='$thumb_src' alt='' />
</a>
</div>
";
}
?>
Hope someone can help me on the way to fix this :)
Without being able to see your table structure I won't be able to give an exact answer but the likely reason is because your INNER JOIN is not setup correctly.
SELECT DISTINCT *
FROM billeder
INNER JOIN album
ON (billeder.fk_album_ID = album.pk_album_ID)
WHERE
billeder.fk_album_ID = $id
Something like the above would be the correct way to JOIN a table and using a WHERE clause to then limit the date received.
JOIN must be used with two tables columns. See example:
SELECT * FROM tableA a INNER JOIN tableB b ON a.id = b.a_id;
What you're trying to make is something like this:
"SELECT DISTINCT * FROM billeder INNER JOIN album ON
billeder.fk_album_ID = album.album_id WHERE billeder.id = $id"
You shouldn't pass an argument to the JOIN. The arguments must be used on the WHERE clause.

combining 2 mysql queries into 1

i am having trouble creating a single mysql query for what i am trying to do here.
first off, i will show you the table structures and fields of the tables i am using for this particular query:
users:
- id
- name
- photo_name
- photo_ext
user_attacks:
- id
- level
user_news_feed:
- id
- id_user
- id_status
- id_attack
- id_profile
- id_wall
- the_date
user_status:
- id
- status
user_wall:
- id
- id_user
- id_poster
- post
whenever the user posts an attack, or status update, updates their profile, or posts on someones wall, it inserts the relevant data into its respective table and also inserts a new row into the user_news_feed table.
now, what i want to do is select the last 10 news feed items from the database. these news feed items need to grab relevant data from other tables as long as their value is not 0. so if the news feed is for a status update, the id_status would be the id of the status update in the user_status table, and the "status" would be the data needing to be selected via a left join. hope that makes sense.
heres my first mysql query:
$sql = mysql_query("select n.id_user, n.id_status, n.id_attack, n.id_profile, n.id_wall, n.the_date, u.id, u.name, u.photo_name, u.photo_ext, s.status
from `user_news_feed` as n
left join `users` u on (u.id = n.id_user)
left join `user_status` s on (s.id = n.id_status)
where n.id_user='".$_GET['id']."'
order by n.id desc
limit 10
");
now this works great, except for 1 problem. as you can see the user_wall table contains the id's for 2 different users. id_user is the user id the post is being made for, and id_poster is the user id of the person making that wall post. if the user makes a wall post on his/her own wall, it is inserted into the database as a status update into the user_status table instead.
so i have a conditional statement within the while loop for the first query, which has another sql query within it. here is the whole code for the while loop and second sql query:
while ($row = mysql_fetch_assoc($sql))
{
if ($row['id_wall'] != 0)
{
$sql_u = mysql_query("select u.id, u.name, u.photo_name, u.photo_ext, w.post
from `user_wall` as w
left join `users` u on (u.id = w.id_poster)
where w.id='".$row['id_wall']."'
");
while ($row_u = mysql_fetch_assoc($sql_u))
{
$row['photo_name'] = $row_u['photo_name'];
$row['photo_ext'] = $row_u['photo_ext'];
$row['id_user'] = $row_u['id'];
$row['name'] = $row_u['name'];
$content = $row_u['post'];
}
}
else
{
if ($row['id_status'] != 0)
$content = $row['status'];
else if ($row['id_attack'] != 0)
$content = '<i>Had an attack</i>';
else if ($row['id_profile'] != 0)
$content = '<i>Updated profile</i>';
}
echo '<li'.(($count == $total_count) ? ' class="last"' : '').'>';
echo '<img src="images/profile/'.$row['photo_name'].'_thumb.'.$row['photo_ext'].'" alt="" />';
echo '<div class="content">';
echo '<b>'.$row['name'].'</b>';
echo '<span>'.$content.'</span>';
echo '<small>'.date('F j, Y \a\t g:ia', $row['the_date']).'</small>';
echo '</div>';
echo '<div style="clear: both;"></div>';
echo '</li>';
}
i hope what i am trying to do here makes sense. so basically i want to have both sql queries ($sql, and $sql_u) combined into a single query so i do not have to query the database every single time when the user_news_feed item is a wall post.
any help would be greatly appreciated and i apologise if this is confusing.
SELECT n.id_user, n.id_status, n.id_attack, n.id_profile, n.id_wall, n.the_date,
u.id, u.name, u.photo_name, u.photo_ext, s.status,
w.id AS wall_user_id, w.name AS wall_user_name,
w.photo_name AS wall_user_photo_name,
w.photo_ext AS wall_user_photo_ext,
w.post
FROM user_news_feed AS n
LEFT JOIN users AS u ON (u.id = n.id_user)
LEFT JOIN user_status s ON (s.id = n.id_status)
LEFT JOIN (SELECT a.id AS id_wall, b.id, b.name, b.photo_name, b.photo_ext, a.post
FROM user_wall AS a
LEFT JOIN users AS b ON (b.id = a.id_poster)
) AS w ON w.id_wall = n.id_wall
WHERE n.id_user = ?
ORDER BY n.id desc
LIMIT 10
The '?' is a placeholder where you can provide the value of $_GET['id'].
Basically, this adds an extra outer join, to the main query (and some extra columns, which will be NULL if the news feed event is not a wall posting), but the outer join is itself the result of an outer join.
Back again ;)
Anyway, forget about merging the queries in my opinion.
What you should do instead is to do the first query, loop through all the results and store all "id_wall"s in a separate array... then rather than doing a separate query per "id_wall" you do this:
$wallids = array();
while ($row = mysql_fetch_assoc($sql))
{
$wallids[] = $row['id_wall'];
// also store the row wherever you want
}
$sql_u = mysql_query("select u.id, u.name, u.photo_name, u.photo_ext, w.post
from `user_wall` as w
left join `users` u on (u.id = w.id_poster)
where w.id IN ('".implode(',', $wallids) ."')
");
$wallids being an array with all the "id_wall"s. So now you have a total of 2 queries.

Categories