PHP Mysql Relations - php

id message round date user_id video_id
1 TextMsg 1 2018-01-26 1 1
2 TextMsg 1 2018-01-26 2 1
3 TextMsg 2 2018-01-26 2 6
I have this table 'messages 'on my Mysql database,
with relations user_id to my users table and video_id to my videos table
using php how can I make a loop that shows
the messages like a chat.
All the messages related to the video
SELECT * FROM messages WHERE $id = videos.id // I doubt
then
SELECT * FROM messages WHERE round = 1 // need to make the rounds as tabs
then
SELECT * FROM users WHERE user_id = id
I'm completely lost, any help would be awesome,
Appreciate.

You just need to do a left join.
SELECT * FROM messages
LEFT JOIN videos ON videos.id=messages.video_id
LEFT JOIN users ON users.id=messages.user_id
WHERE video_id={$id} GROUP BY rounds ORDER BY date DESC
Take note of the duplicate columns, rename if necessary.

Related

Sort the results of the first table by the id of the second

I'm sorting some users by id (oldest to newest).
This is my accounts table:
Accounts
id
name
1
James
2
Kirk
3
Roberto
4
Lars
However, I need to improve this ordering by relating a second messages table.
Accounts_Messages
id
sender_id
receiver_id
1
1
4
2
1
2
3
1
3
In this case, users in Accounts table should be ordered by last messages.
This is the expected result:
Roberto;
Kirk;
Lars;
The question is: How can I sort the results of the first table by the id of the second?
I read that I need to use `JOIN` to relate these two tables, but I didn't know how to apply it in this specific case.
Thank you, guys!
Hey use this MySQL query for your aspected result
Select Accounts.name from Accounts_Messages left join Accounts on Accounts.id = Accounts_Messages.receiver_id order by Accounts_Messages.id DESC
this is what I understand by your question you need to sort the accounts by the id of the accounts_Message
I think you should try
SELECT acc.* FROM Accounts_Message am LEFT OUTER JOIN Accounts acc USING(id) ORDER BY id ASC
if both Accounts and Accounts_Message has same column name id use USING(id) or the column name is different use ON acc.id = am.id instead

MySql Statement across different rows

Im trying to query a wordpress mySQL database where the values pertaining to each user is spread across different rows (only god knows why they did it that way, why didnt they just put all the user information on one row)
For example
ID USER_ID FIELD_ID VALUE
1 1 2 my name is paul smith
2 1 3 books
3 1 4 loggedin
4 1 5 state=busy
5 2 2 my name is big boy
5 2 3 pens
6 2 4 offline
7 2 5 state=idle
here you can see each row has a different meaning based on the FIELD_ID for the same user
FIELD_ID=2 contains the user name
FIELD_ID=3 contains mean what they bought
FIELD_ID=4 means logged in
FIELD_ID=5 is busy or idle
I need to make ONE query that will return all users that are LOGGED IN and STATE=IDLE and bought BOOKS (or bought some other item like pens whatever they want to search for)
so i started off with this php statement
$find="pens";
$q = "SELECT * FROM table
WHERE FIELD_ID='4' AND VALUE='loggedin'
AND FIELD_ID='5' AND VALUE='idle'
AND USER_ID IN
(SELECT USER_ID FROM table WHERE FIELD_ID ='3' AND VALUE LIKE '%$find%')
But i dont think this will work because how can
FIELD_ID = '4' AND VALUE='loggedin' AND FIELD_ID='5' AND VALUE='idle' all at the same time because they are on different rows.
Does anybody know how to make ONE mySQL statement to do it?
you could use a self join
SELECT distinct a.user_id
FROM table a
inner join table b on a.user_id = b.user_id and b.field_id = 5 and b.value='idle'
inner join table c on a.user_id = c.user_id and c.field_id = 4 and c.value = 'loggedin'
where a.field_id=3 and a.value='BOOK'

Improve performance of SQL Query to select ids from different tables in multiple columns

Let us just imagine I have the following table structure
Table: images
id path
1 x
2 x
3 x
4 x
5 x
6 x
7 x
8 x
Table: user
id image imageSmall
1 1 1
2 2 2
3 4 4
Table: books
id image imageSmall
1 5 5
2 6 6
3 8 8
I now want to get the ID of every image used in other tables. I made this query here
SELECT id FROM images WHERE id IN (SELECT image FROM user) OR id IN (SELECT imageSmall FROM user) OR id IN (SELECT image FROM books) OR id IN (SELECT imageSmall FROM books);
The problem I see here, is that, when I have a large amount of data, this query could be very time consuming and not performant at all because of the many IN parts of the query. Is there a way to improve the performance of this query?
I would phrase this using exists rather than in:
SELECT id
FROM images i
WHERE EXISTS (SELECT 1 FROM user u WHERE u.image = i.id) OR
EXiSTS (SELECT 1 FROM user u WHERE u.imageSmall = i.id) OR
EXISTS (SELECT 1 FROM books b WHERE b.image = i.id);
For performance, be sure that you have the following indexes:
create index idx_user_image on user(image);
create index idx_user_imageSmall on user(imageSmall);
create index idx_books_image on books(image);
Use joins instead of that many select in selects, and DISTINCT to return unique values:
SELECT DISTINCT(i.id) FROM images i
INNER JOIN `user` u
INNER JOIN `books` b
WHERE b.image=i.id OR b.imageSmall=i.id OR u.image=i.id OR u.imageSmall=i.id

Selecting N rows from each group in MYSQL

I need to search for the updates sent by the friends of a giving user.
There is a table called friendship. It has a column called profile1 and another one called profile2. It represents the friendship between two users in this websystem, and a friendship is the presence of two giving ids, no matter in what position. So the profile with id 1 may have 2 friends, profile with id 2 and with id 3 as following:
friendship
profile1 profile2
1 2 <--
3 1 <--
2 5
...
Now I want to search for the updates sent by some user's friends. There is this table update
update
id content time profile
1 A text ... 2
2 A text ... 2
3 A text ... 3
4 A text ... 2
5 A text ... 3
6 A text ... 2
7 A text ... 10
8 A text ... 11
If my profile/user is identified by the id 1, and it has only 2 friends (the profiles identified by id 2 and 3) and also I need my search to return only 2 results by each user, my SELECT has to return updates 1,2,3 and 5.
Preferably updates should be grouped by its author and it would be great if I could set the number of different profiles to be considered in this search (for example, if profile 1 had 10 friends and I wanted only updates from 3 profiles, the most recent must appear first).
Do you know how can I achieve this??
thank you very much!
#EDIT
This returns all updates sent by friends of profile 1. But i'm not sure whether or not i'm in the right direction
SELECT u.*
FROM `update` u
INNER JOIN friendship f1 ON f1.profile1 = u.author
WHERE f1.profile2 =1
UNION
SELECT u.*
FROM `update` u
INNER JOIN friendship f2 ON f2.profile2 = u.author
WHERE f2.profile1 =1
If you are willing to do it in two queries, you can do it like this. First, get three profiles who have most recently posted based on your constraints:
-- Get the three latest updated profiles from here.
-- (we can't use a CTE because MySQL doesn't support
-- them yet).
SELECT DISTINCT p.profile FROM
(
SELECT ui.profile, ui.time FROM
(
SELECT u.profile, u.time
FROM `update` u
INNER JOIN `friendship` f ON f.profile2 = u.profile
WHERE f.profile1 = 1
UNION ALL
SELECT u.profile, u.time
FROM `update` u
INNER JOIN `friendship` f ON f.profile1 = u.profile
WHERE f.profile2 = 1
) ui ORDER BY ui.time DESC
) p LIMIT 0, 3;
From that query, get the three profile IDs out and put them in place of <id1>, <id2> and <id3> in the following query
-- Use a union to get the result set back
(SELECT a.content, a.time, a.profile FROM `update` a
WHERE a.profile = <id1>
ORDER BY a.time DESC
LIMIT 0, 2)
UNION ALL
(SELECT a.content, a.time, a.profile FROM `update` a
WHERE a.profile = <id2>
ORDER BY a.time DESC
LIMIT 0, 2)
UNION ALL
(SELECT a.content, a.time, a.profile FROM `update` a
WHERE a.profile = <id3>
ORDER BY a.time DESC
LIMIT 0, 2);
If you get less than three profiles back, either remove parts of the query in your PHP code, or set the WHERE clause to something like 0 so it always evaluates to fault (assuming you don't have a profile ID of zero)
The 2 in the limit clauses above can be changed if you want more or fewer results per profile.
Sample SQL fiddle: http://sqlfiddle.com/#!2/22e57/1 (updated fiddle to make the content more meaningful and to use times)
I would suggest doing a series of queries for each author within one transaction, that way there would not be a need for grouping - you could simply append results together outside of your SQL.
SELECT * FROM `update` WHERE
profile IN (SELECT profile2 FROM `friendship` WHERE profile1=1) OR
profile IN (SELECT profile1 FROM `friendship` WHERE profile2=1);
try this sqlFiddle
SELECT T1.profile,T1.content,T1.time
FROM
(SELECT UPD.profile,UPD.content,UPD.time,
IF (#prevProfile != UPD.profile,#timeRank:=1,#timeRank:=#timeRank+1) as timeRank,
#prevProfile := UPD.profile
FROM
(SELECT UP.profile,UP.content,UP.time
FROM
(SELECT profile,max(time) as latestUpdateTime
FROM friendship F INNER JOIN updates U
ON (F.profile1 = 1 AND U.profile = profile2) /* <-- specify profile on this line */
OR(F.profile2 = 1 AND U.profile = profile1) /* <-- specify profile on this line */
GROUP BY profile
ORDER BY latestUpdateTime DESC
LIMIT 3 /* limit to 3 friends profiles that have the most recent updates */
)as LU
INNER JOIN updates UP
ON (UP.profile = LU.profile)
ORDER BY profile,time DESC
)as UPD,(SELECT #prevProfile:=0,#timeRank:=0)variables
)T1
WHERE T1.timeRank BETWEEN 1 AND 2 /* grab 2 lastest updates for each profile */
ORDER BY T1.time DESC
in my example, profile id 1 has more than 3 friends, but i am only grabbing 3 friends that made the most recent updates.
explanation of above query.
LU grabs 3 profiles that are friends with profile id 1 that made the latest updates.
UPD grabs all contents that belong to these 3 friends.
T1 returns the contents along with a timeRank number for each content in order from 1 counting upward order by time DESCENDING for each profile
and finally the WHERE we only grab 2 content updates for each profile
then we finally ORDER these updates based on TIME starting from most recent.

Select records from table1 depending on table2

I am trying to build a project where you can like other people's pictures, and when the other person likes your picture too, you have a match. Like the Tinder app if you know.
Now, I fetch 1 photo like so:
SELECT id, picture_path, profile_picture, username
FROM tusers
WHERE profile_picture IS NOT NULL
AND settings LIKE '1,%'
AND sex = :sex
AND last_visit BETWEEN CURDATE() - INTERVAL 21 DAY AND CURDATE()
AND dob BETWEEN :dob - INTERVAL 5 YEAR AND :dob2 + INTERVAL 5 YEAR
LIMIT 1
However, if you've already LIKED or PASSED someone's photo, I don't want to show it to you again. I am not sure how to do this part yet (right now, I have alreadyLiked() and alreadyPassed() functions and I am only doing a header("Location") redirect if they return true, but that will fail when you have liked/passed all the photos).
I have another table with these columns: id, user1_id, user2_id, liked, passed, matched
When you like or pass a picture, a 1 is inserted in the corresponding column.
user1_id is your ID. user2_id is the other person's ID.
Knowing the above information, what kind of query (or logic) would you use to make sure that you only show the right people (that you haven't liked or passed already) ?
suppose you have 2 tables
usr
id username
1 a
2 b
3 c
4 d
liked
id user1 user2 liked
1 1 4 1
2 1 3 1
assuming your id is 1 , from table liked it seems you have liked c,d . since 1(a) is your own id you need only b as output, your query goes as below
SELECT *
FROM usr
WHERE id NOT
IN (
SELECT user2
FROM liked
WHERE user1 =1
)
and id!=1
assuming 1 will come from session
You can use mysql join to get data from one table based on the another
In the upper case you can have join on the first tables id with the other tables user1_id, user2_id putting where clause on the liked, passed, matched
To know more about mysql joins
Try this as join is much better than a inner query suggested by ersumit $loggedINuser_id='2';//take from session $sql="SELECT tu.id, tu.picture_path, tu.profile_picture, tu.username FROM tusers tu LEFT JOIN secondtable st ON tu.id=st.user2_id WHERE tu.profile_picture IS NOT NULL AND tu.settings LIKE '1,%' AND tu.sex = :sex AND tu.last_visit BETWEEN CURDATE() - INTERVAL 21 DAY AND CURDATE() AND tu.dob BETWEEN :dob - INTERVAL 5 YEAR AND :dob2 + INTERVAL 5 YEAR AND st.user1_id != '".$loggedINuser_id."' LIMIT 1";

Categories