MySQL ORDER BY different table column but - php

I've been struggling a lot with this and it's really complicated so please focus because it's even hard to explain.
I have a table friends with columns:
id, friend1, friend2, since
And I want to display all user's friends ordered by the activity of that user from different table (table name: accinfo, column: lastact) where value of lastact is a php time.
The problem is that I don't know which column is the friend... it could either be friend1 or friend2 but that depends...
How could I find out which column is the friend's name and not the name of user? I obviously need to check it in the SQL itself to get the friends sorted out by the latest activity. Thank you.
Tables:
friends
id | friend1 | friend2 | since
1 | bob | joe | null
2 | kate | jane | null
3 | bob | robby | null
accinfo
id | username | lastact
1 | bob | 1483323711
2 | joe | 1483323701
3 | kate | 1483323642
4 | jane | 1483311256
5 | robby | 1483321234

One method is a conditional join:
select f.*, ai.lasact
from friends f join
accinfo ai
on (ai.userid = f.friend1 and friend2 = $userid) or
(ai.userid = f.friend2 and friend1 = $userid)
where $userid in (f.friend1, f.friend2)
order by lastacct desc;

Try this,
SELECT acf.username FROM friends fds, accinfo acf WHERE (acf.username=fds.friend1 OR acf.username=fds.frien2) ORDER BY acf.lastact DESC

Related

laravel recursion display referred users by level/depth

So I'm working with affiliate and doing fine with registration and saving who referred to a user,
now I'm struggling in showing those users with referrals by Level.
Level is not save in the database, I'm thinking of it as incrementing in the logic area?
users table structure
id | name | sponsor_id |
1 | John | NULL |
2 | Jane | 1 |
3 | Jess | 1 |
4 | Joe | 2 |
so the output I want should be like this:
I am John, level 1 are who's sponsor_id is mine, and level 2 are who's sponsor_id is id's of whom I invited.
ID | Name | Level |
2 | Jane | 1 |
3 | Jess | 1 |
4 | Joe | 2 |
where Jane & Jess's sponsor_id is mine, and Joe's sponsor_id is Jess
User has sponsor
public function sponsor()
{
return $this->belongsTo('App\User', 'sponsor_id');
}
User has referrals
public function referrals()
{
return $this->hasMany('App\User', 'sponsor_id');
}
If MySQL 8 (very advised with hierarchical data like yours), you can do this with a recursive CTE :
WITH RECURSIVE CTE_users_levels(id, name, level) AS
(
SELECT id, name, 0 as level
FROM users
WHERE sponsor_id IS NULL
UNION ALL
SELECT u.id, u.name, cte.level+1
FROM CTE_users_levels cte
JOIN users u ON cte.id=u.sponsor_id
)
-- To output all users' levels:
SELECT * FROM CTE_users_levels ORDER BY level;
Now you have virtual table containing the level column for all your users and you can query it
| id | name | level |
| --- | ---- | ----- |
| 1 | John | 0 |
| 2 | Jane | 1 |
| 3 | Jess | 1 |
| 4 | Joe | 2 |
DBFiddle
GOing further...
Make a view out of your CTE
CREATE VIEW VIEW_User_Levels AS
(
WITH RECURSIVE CTE_users_levels(id, name, level) AS
(
SELECT id, name, 0 as level
FROM users
WHERE sponsor_id IS NULL
UNION ALL
SELECT u.id, u.name, cte.level+1
FROM CTE_users_levels cte
JOIN users u ON cte.id=u.sponsor_id
)
SELECT * FROM CTE_users_levels ORDER BY level
)
Now it's easy to get all your users levels (no need to have the CTE statement) :
SELECT * FROM VIEW_User_Levels
Then, if you have a lot of users, it's a bit ovekilling to recompute the whole tree all the time (which the VIEW does)
Then you can fix the level of your users in a new column.
ALTER TABLE users ADD level INT;
And populate that column for all users with the help of your view:
UPDATE users u, VIEW_User_Levels v
SET u.level=v.level
WHERE u.id=v.id;
Which gives
SELECT * FROM users
id name sponsor_id level
1 John null 0
2 Jane 1 1
3 Jess 1 1
4 Joe 2 2
DBFiddle
If you have a lot of users, and your aim is to query the level column a lot, INDEX IT.
Note that you can also update the level value of only one user (for instance if its sponsor_id changes, or if the user is new)
UPDATE users u, VIEW_User_Levels v
SET u.level=v.level
WHERE u.id=v.id AND u.name='Jane';

Issue with order by and group by with two foreign keys in same table

I need to develop chat application in php for this i have created two tables likes users and message. every user details will be stored in users table and every message will be stored in messages table.I have done storing part it is working fine. Now i need to display messages.So as per my requirement.
when any user logs into his portal he/she will be able to see latest messaged users list.And if he want to message any of other users ,he just clicks on there profile pic than a message panel will be opened .Untill here i completed everything.
But my issue is i need to display
latest messaged users list,
in this i need to show user first name, profile picture,last message, last message date.
And one more condition is i need to display the list like latest messaged user first.
I have tried in many ways but i got users list with first message i don't want like that i need last message for that user
My tables are
Users table
uid | firstname | email | mobile
---------------------------------------------
1 | kumar | kumar#gmail.com | 9876543210
----------------------------------------------
2 | jack | jack#gmail.com | 8876543216
----------------------------------------------
3 | rams | rams#gmail.com | 7876543215
----------------------------------------------
4 | devid | devid#gmail.com | 9876543220
----------------------------------------------
5 | joe | joe#gmail.com | 8876543212
----------------------------------------------
messages table
mid| from_id | to_id | message | created_at
----------------------------------------------------------------
1 | 1 | 2 | hello jack | 2017-02-03 09:00:52
----------------------------------------------------------------
2 | 2 | 1 | hi kumar | 2017-02-03 09:10:30
----------------------------------------------------------------
3 | 2 | 3 | ram where are you | 2017-02-03 09:15:02
----------------------------------------------------------------
4 | 3 | 2 | at home | 2017-02-03 09:35:20
----------------------------------------------------------------
5 | 1 | 2 | hello how are you | 2017-02-03 09:42:55
----------------------------------------------------------------
6 | 4 | 2 | good morning | 2017-02-03 09:50:45
----------------------------------------------------------------
8 | 1 | 3 | hi | 2017-02-03 09:54:22
----------------------------------------------------------------
7 | 3 | 1 | hello kumar | 2017-02-03 09:58:38
----------------------------------------------------------------
For example i have logged in as kumar(uid=1)
Expected output:
firstname | message | mid | uid
-----------------------------------------
rams | hello kumar | 7 | 3
-----------------------------------------
jack | hello how are you | 5 | 2
-----------------------------------------
I have tried like this :
SELECT DISTINCT
`u`.`firstname`,
`u`.`profile_photo`,
`u`.`uid`,
`u2`.`firstname`,
`u2`.`profile_photo`,
`u2`.`uid`,
`message`,
`messages`.`created_at`,
`messages`.`from_id`,
`messages`.`to_id`,
`messages`.`mid`
FROM
`messages`
INNER JOIN
`users` AS `u` ON `u`.`uid` = `messages`.`from_id`
INNER JOIN
`users` AS `u2` ON `u2`.`uid` = `messages`.`to_id`
WHERE
(from_id = 1 OR to_id = 1)
GROUP BY
`u`.`uid`,
`u2`.`uid`
ORDER BY
`messages`.`mid` DESC
But got output like this
firstname | message | mid | uid
-----------------------------------------
jack | hello jack | 1 | 2
-----------------------------------------
rams | hi | 5 | 2
-----------------------------------------
Thanks in advance
try this way
SELECT DISTINCT `u`.`firstname`,`u`.`profile_photo`, `u`.`uid`, `u2`.`firstname`,`u2`.`profile_photo`,`u2`.`uid`, `message`,`messages`.`created_at`, `messages`.`from_id`,`messages`.`to_id`,`messages`.`mid`
FROM `messages`
INNER JOIN `users` AS `u` ON `u`.`uid` = `messages`.`from_id`
INNER JOIN `users` AS `u2` ON `u2`.`uid` = `messages`.`to_id`
WHERE (from_id = 1 OR to_id = 1)
GROUP BY `u`.`uid`, `u2`.`uid`
ORDER BY `messages`.`created_at` DESC
It appears that you want to put messages in the same group if they're between the same two users, regardless of the direction. To do this, change your GROUP BY to:
GROUP BY GREATEST(u.uid, u2.uid), LEAST(u.uid, u2.uid)
Use this along with the solutions in SQL Select only rows with Max Value on a Column to get the first or last message in each conversation found using this grouping.
You should also give aliases to the columns from u and u2 in the SELECT clause, so you can distinguish the sender and receiver information in the result.
SELECT u.firstname AS sender_name, u.profile_photo AS sender_photo, ...
Or since one of the users is always kumar, you could just select only the information about the other user:
SELECT IF(from_id = 1, u2.firstname, u1.firstname) AS firstname,
IF(from_id = 1, u2.profile_photo, u1.profile_photo) AS profile_photo,
...

Get all users who is not friend with login user

i have a little problem with MySql query. I have two tables:
Table name "users"
id, profilephoto, sex, name, lastname
Table name "friends"
id, idSender, idReceiver
idSender and idReceiver is value of id users who send friend request, and who get friend request.
Now i need get all users who is not friend with some login user (for example - User ID - 12)
I make this query:
SELECT DISTINCT users.id, users.profilephoto,users.sex,users.name,users.lastname FROM users INNER JOIN friends ON users.id=friends.idSender WHERE (friends.idSender!=12 OR friends.idReceiver!=12)
And I get wrong informations.
If someone have any idea, I will be thankful.
Simple data from table>
Table Users:
id | profilephoto | sex | name | lastname
1 | image1.jpg | 1 | John | Snow
2 | image2.jpg | 2 | Lisa | Test
3 | image3.jpg | 1 | Patric | Test
4 | image4.jpg | 2 | Elizabet | Test
Table friends:
id | idReceiver | idSender
1 | 1 | 2 // Lisa send friend request to John
2 | 2 | 3 // Patric send friend request to Lisa
For Lisa I want to display only Elizabet
For Elizabet I want to display Lisa, John and Patric
For John I need Patric and Elizabet
For Patric I need John and Elizabet
You need to make left join
SELECT * from users u
LEFT JOIN friends f ON u.id = f.idSender OR u.id = f.idReceiver
WHERE u.id = 12
AND f.idSender IS NULL
OR f.idReciever IS NULL
Hope it helps.
I think trying this query will select user has no friends
select u.*
from user u
left join friends f on f.idSender= u.id or f.idReceiver= u.id
where f.id is null

Comparing values of columns from 3 tables - MySQL

following question:
I'm working with 3 tables = actors, movies, roles. I'm trying to find all the movies a given actor, say 'Robin Williams' has been in by comparing the specific actor id since there be may more than one actor with the same name. The actors table has the following relevant columns: first_name, last_name, id - the movies table has columns: id (the movie's id) - and the roles table has: actor_id and movie_id.
Do I JOIN the tables or use UNION? How do I compare columns from different tables when the columns have different names?
Thank you!
Just for reference:
Table actors:
mysql> SELECT *
-> FROM actors;
+--------+--------------------+------------------------+--------+------------+
| id | first_name | last_name | gender | film_count |
+--------+--------------------+------------------------+--------+------------+
| 933 | Lewis | Abernathy | M | 1 |
| 2547 | Andrew | Adamson | M | 1 |
| 2700 | William | Addy | M | 1 |
Table movies:
mysql> SELECT *
-> FROM movies;
+--------+------------------------------+------+------+
| id | name | year | rank |
+--------+------------------------------+------+------+
| 10920 | Aliens | 1986 | 8.2 |
| 17173 | Animal House | 1978 | 7.5 |
| 18979 | Apollo 13 | 1995 | 7.5 |
Table roles:
mysql> SELECT *
-> FROM roles;
+----------+----------+-------------------------------+
| actor_id | movie_id | role |
+----------+----------+-------------------------------+
| 16844 | 10920 | Lydecker |
| 36641 | 10920 | Russ Jorden |
| 42278 | 10920 | Cpl. Dwayne Hicks |
At first I tried setting each check equal to a PHP variable and comparing them but that seemed wrong, then I tried:
mysql> SELECT roles.actor_id, roles.movie_id, movies.id, actors.id
-> FROM roles
-> JOIN movies, actors
-> ON roles.actor_id = actors.id && roles.movie_id =movies.id;
which again does not work.
Finally figured it out..
>SELECT m.name, m.year
-> FROM movies m
->JOIN roles r ON m.id = r.movie_id
->JOIN actors a ON a.id = r.actor_id
->WHERE a.first_name = "whatever actor's first name"
->AND a.last_name = "whatever actor's last name"
This will then give you two columns with the corresponding name and year! hazzah!
First Read this answer - it made it click for me finally after years of unions when should join and vice versa.
In this case you should definitely JOIN as you want the result to act as a single row.
(think of it like this - I want to see Movie, Actor -> together as one result)
PS
You don't need your film count field any more as once you have the joins worked out you can just use MySQL COUNT -> it will make it easier to maintain.
You need a join. Try this:
SELECT A.first_name,A.last_name,A.gender,M.name,M.year,M.rank,R.role
FROM roles R INNER JOIN
Movies M ON R.movie_id = M.movie_id INNER JOIN
Actors A ON R.actory_id = A.id

mySQL: Showing data from one table using id from another

I want my users to be able to make a favourite list.
I have two tables in a database in mySQL. One stores information about businesses and the other stores the unique user ids as well as the ids from the first table that the user has marked a favourite.
Table 1
<pre>
ID | NAME | EMAIL | PHONE |
1 | Joe | a#mail.com | 25634565 |
2 | John | b#mail.com | 43634565 |
3 | Jack | c#mail.com | 65634565 |
4 | James| d#mail.com | 43634565 |
5 | Julie| e#mail.com | 65634565 |
...
</pre>
Table 2
<pre>
USERID | FAV1 | FAV2 | FAV3 | FAV...
2565325489 | 1 | 3 | 5 |
8596854785 | 3 | 2 | NULL |
2356256263 | 5 | NULL | NULL |
...
</pre>
The output I want for a user (in this example the first in table2):
<pre>
Joe | a#mail.com | 25634565 |
Jack | c#mail.com | 65634565 |
Julie| e#mail.com | 65634565 |
</pre>
I have looked into JOIN LEFT and minus query calls, but I just can't make it work. I have a basic understanding of mySQL and PHP, but not a lot.
I would highly appreciate any help with what approach to take.
Ps. If there are better ways to structures my databases, I would love to know.
I'd use a table with two fields - userID and fav - make one entry for each entry. And then...
SELECT table1.name, table1.email, table1.phone FROM table1,table2 WHERE table2.fav = table1.id AND table2.userid = 2565325489
Select * from table1 InnerJoin (Select * from table2) as t4 on table1.ID=t4.FAV1
$result = mysqli_query('SELECT name,email,phone FROM t1 table1 LEFT JOIN table2 t2 ON t1.ID = t2.fav1');
//iterate the results
while ($row = mysqli_fetch_array($result))
{
echo $row['name']." ".$row['email']." "$row['phone'];
}

Categories