SQL DISTINCT WITH TWO VARIABLES - php

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...

Related

Showing two different values depending on SESSION value in INNER JOIN

I have two different tables, one named users, and another named transactions. Transactions contains wallet1, wallet2, amount. Users contains user details such as firstname, lastname, and wallet. I am trying to display the corresponding first name and last name, depending on whether or not the SESSION_wallet is equal to wallet1 or wallet2 within transactions. I tried searching for a while, and came up with a solution for showing the correct display name for the first and last name making the transfer, however, I am trying to make it display the correct value for "Transfer to:"
Here is some of my code to get a better understanding of what I mean:
MySQLi Query:
$result2 = mysqli_query($link, "SELECT * FROM transactions INNER JOIN users ON transactions.wallet1 = users.wallet WHERE transactions.wallet1 = '" . $_SESSION["wallet"] . "' OR transactions.wallet2 = '" . $_SESSION["wallet"] . "' Order by transactions.id DESC LIMIT 5 ");
PHP Code:
<?php
if(mysqli_num_rows($result2) > 0)
{
while($row = mysqli_fetch_array($result2))
{
?>
The table that needs to display the transfer from, and transfer to:
<?php
if ($_SESSION["wallet"] == $row["wallet1"]) {
echo "<td>Transfer to ".$row["firstname"]." ".$row["lastname"]."</td>";
}
else if ($_SESSION["wallet"] == $row["wallet2"]) {
echo "<td>Transfer from ".$row["firstname"]." ".$row["lastname"]."</td>";
}
?>
Right now my tables are only showing the first and last name of the user that made the Transfer, however, I need it to display the first and last name of the user that the transaction is made to as well. The else if code is working correct, but the first part is not showing the corresponding value.
You will need to JOIN your transactions table to your users table twice, once to get each users name. Then to avoid duplicate column names overwriting the results in the output array, you will need to use column aliases. Something like this should work:
$result2 = mysqli_query($link, "SELECT t.*,
u1.firstname AS w1_firstname,
u1.lastname AS w1_lastname,
u2.firstname AS w2_firstname,
u2.lastname AS w2_lastname
FROM transactions t
INNER JOIN users u1 ON t.wallet1 = u1.wallet
INNER JOIN users u2 ON t.wallet2 = u2.wallet
WHERE t.wallet1 = '{$_SESSION["wallet"]}'
OR t.wallet2 = '{$_SESSION["wallet"]}'
ORDER BY t.id DESC
LIMIT 5 ");
Then you can access each user's names as $row['w1_firstname'] etc.:
if ($_SESSION["wallet"] == $row["wallet1"]) {
echo "<td>Transfer to ".$row["w2_firstname"]." ".$row["w2_lastname"]."</td>";
}
else if ($_SESSION["wallet"] == $row["wallet2"]) {
echo "<td>Transfer from ".$row["w1_firstname"]." ".$row["w1_lastname"]."</td>";
}
Note that ideally you should use a prepared query for this, for example:
$stmt = $link->prepare("SELECT t.*,
u1.firstname AS w1_firstname,
u1.lastname AS w1_lastname,
u2.firstname AS w2_firstname,
u2.lastname AS w2_lastname
FROM transactions t
INNER JOIN users u1 ON t.wallet1 = u1.wallet
INNER JOIN users u2 ON t.wallet2 = u2.wallet
WHERE t.wallet1 = ?
OR t.wallet2 = ?
ORDER BY t.id DESC
LIMIT 5");
$stmt->bind_param('ss', $_SESSION["wallet"], $_SESSION["wallet"]);
$stmt->execute();
$result2 = $stmt->get_result();

PHP Retrieve information from five different tables with correct order

I develop a chat system where students and staff can exchange different messages. I have developed a database where we have five tables: the staff table, the student, the message and two mapping tables the staff_message and stu_message. These tables contain only the student/staff id and the message id.
My problem is that I cannot order the messages. I mean that I cannot figure out how can I make one SQL statement that will return all messages and be ordered by for example the ID. The code that I have made is this:
$qu = mysqli_query($con,"SELECT * FROM stu_message");
while($row7 = mysqli_fetch_assoc($qu)){
$que = mysqli_query($con, "SELECT * FROM student WHERE studentid =".$row7['stu_id']);
while($row8 = mysqli_fetch_assoc($que)) {
$username = $row8['username'];
}
$query3 = mysqli_query($con, "SELECT * FROM message WHERE id=".$row7['mid']);
while($row6 = mysqli_fetch_assoc($query3)) {
echo $row6['date']."<strong> ".$username."</strong> ".$row6['text']."<br>";
}
}
$query2 = mysqli_query($con, "SELECT * FROM staff_message");
while($row3 = mysqli_fetch_assoc($query2)){
$query = mysqli_query($con, "SELECT * FROM staff WHERE id =".$row3['staff_id']);
while($row5 = mysqli_fetch_assoc($query)) {
$username = $row5['username'];
}
$query3 = mysqli_query($con, "SELECT * FROM message WHERE id=".$row3['m_id']);
while($row6 = mysqli_fetch_assoc($query3)) {
echo $row6['date']."<strong> ".$username."</strong> ".$row6['text']."<br>";
}
}
?>
The result is different from that I want. To be more specific first are shown the messages from the students and then from the staff. My question is, is there any query that it can combine basically all these four tables in one and all messages will be shown in correct order? for example by the id?
Thank you in advance!
First, use JOIN to get the username corresponding to the stu_id or staff_id, and the text of the message, rather than separate queries.
Then use UNION to combine both queries into a single query, which you can then order with ORDER BY.
SELECT u.id, u.text, u.username
FROM (
SELECT s.username, m.text, m.id
FROM message AS m
JOIN stu_message AS sm ON m.id = sm.mid
JOIN student AS s ON s.id = sm.stu_id
UNION ALL
SELECT s.username, m.text, m.id
FROM message AS m
JOIN staff_message AS sm ON m.id = sm.m_id
JOIN staff AS s ON s.id = sm.staff_id
) AS u
ORDER BY u.id

Follow/unfollow tool PHP/mySQL

I am sure I am missing something obvious or the mySQL code I have written for this tool is incorrect.
What I have got is a site that allow people to follow each other. If they are following a user they should see updates from them in their user dashboard.
I have had to tie several tables together in mySQL query to get the relevant information.
Here are the tables
users
ID Username Password
-------------|---------------|------------------
1 User1 UserPass
2 User2 UserPass
3 User3 UserPass
user_details
ID UserID UserPhoto
-------------|---------------|------------------
1 1 User1photo.jpg
2 2 User2photo.jpg
3 3 User3photo.jpg
userstatusposts
UserStatusID UserID status
-------------|---------------|------------------
1 1 Hey My first post
2 2 Woah this is cool
3 3 It doesnt work
followers
followid followerUserID beingFollowedUserID
-------------|---------------|------------------
1 3 1
There are more cols and rows in these tables but this is a basic form for the question.
As you can see from the followers table User3 is following User1 and should therefore be able to see the posts they have made in userstatusposts, the reason user details and users also need tying in is so I can display the users photo and the users username
The SQL I have at the moment that isn't working is:
SELECT * FROM userstatusposts
JOIN followers ON userstatusposts.userid = followers.followeruserid
JOIN users ON userstatusposts.userid = users.id
JOIN user_details ON userstatusposts.userid = user_details.userid
WHERE followers.beingFollowedUserID='$userid'
ORDER BY userstatusposts.userstatusid DESC
LIMIT 10
However this is all tied together wrong as I see the posts of the wrong users when it is implemented in to my PHP code ($userid is the logged in user).
PHP Page:
<?php
$sql = "SELECT * FROM userstatusposts
JOIN followers ON userstatusposts.userid = followers.followeruserid
JOIN users ON userstatusposts.userid = users.id
JOIN user_details ON userstatusposts.userid = user_details.userid
WHERE followers.beingFollowedUserID='$userid'
ORDER BY userstatusposts.userstatusid DESC
LIMIT 10
";
$result = $conn->query($sql);
$rowcount=mysqli_num_rows($result);
if ($rowcount === 0) {
echo '<li style="list-style-type: none;"><p>Your not currently folllowing anyone.</p></li>';
} else {
while($row = $result->fetch_assoc()) {
if ($row['posttype'] == 'message') {
echo '<li style="list-style-type: none;"><img src="userimg/'.$row['userphoto'].'" height="90px" width="90px"><h3>'.$row['username'].'</h3><small>17/06/2014</small><p>'.$row['status'].'</p></li>';
}
else if ($row['posttype'] == 'map') {
echo '<li style="list-style-type: none;"><img src="userimg/'.$row['userphoto'].'" height="90px" width="90px"><h3>'.$row['username'].'</h3><p>has recently added <b>'.$row['status'].'</b> to there travel map</p></li>';
}
else if ($row['posttype'] == 'like') {
echo '<li style="list-style-type: none;"><img src="userimg/'.$row['userphoto'].'" height="90px" width="90px"><h3>'.$row['username'].'</h3><p>has recently liked a trip report called <b>'.$row['status'].'</b></p></li>';
}
else if ($row['posttype'] == 'report') {
echo '<li style="list-style-type: none;"><img src="userimg/'.$row['userphoto'].'" height="90px" width="90px"><h3>'.$row['username'].'</h3><p>has recently shared a trip report called <b>'.$row['status'].'</b></p></li>';
}
else {
echo 'We are currently expirencing a few diffculties';
}
}
}
?>
I am aware there are other cols being used here but they are in the tables listed above I have just left them out for the question.
Any suggestions why my SQL code is bringing back the wrong information, is it something glaringly obvious I have over looked?
Your query returns all the status of followers, not the status of followed.
You should change
WHERE followers.beingFollowedUserID='$userid'
to
WHERE followers.followerUserID = '$userid'
In addition, this is unrelated to your question, but your code has a security problem. You should sanitize $userid first before using it in your query.
$userid = (int)$userid
// .. now $userid is safe to use in $sql
The issue was one of the JOINS was looking to the wrong field.
The SQL should of been:
JOIN followers ON userstatusposts.userid = followers.beingFollowedUserID
So the full statement is
SELECT * FROM userstatusposts
JOIN followers ON userstatusposts.userid = followers.beingFollowedUserID
JOIN users ON userstatusposts.userid = users.id
JOIN user_details ON userstatusposts.userid = user_details.userid
WHERE followers.followerUserID = '$userid'
ORDER BY userstatusposts.userstatusid DESC
LIMIT 10
This was solved by a friend of mine not me, but thought I would share the answer for anyone interested.

php mysql query combination

I first search all questions info. from "question" table including title, content, user etc.
the Code:
$sql = "select * FROM question where id>0 ORDER BY id ASC";
$result1 = mysql_query($sql);
$res=Array();
And then I want to search the user's point from "user" table. So I must search point for each user in each row from the result1
The Code:
while($rows=mysql_fetch_assoc($result1))
{
$res[]=$rows;
$user = $rows['user'];
$sql2 = "select point from user where name='$user'";
$result2 = mysql_query($sql2);
}
My problem is how to combine all the users' point(result2) with the questions info.(result1) together so that I can return a json for each row.
Use left join, as my understanding this work for you
$sql = "SELECT q.*, u.point AS point FROM question AS q LEFT JOIN user AS u ON q.user = u.name WHERE q.id > 0 ORDER BY q.id ASC";
$result = mysql_query($sql);
It's better go with the joins here i am giving you the query.i hope it may helps you
select * from question q,user u where q.id>0 ORDER BY id ASC
try something like this:using left join
select question.*,user.point FROM question left join user on user.name= question.name where id>0 ORDER BY id ASC

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.

Categories