Mysql - How to get Newsfeed from users you follow - php

I've been working on this for some hours now and it's getting tiring. I want to get users posts from people I follow and myself, just like twitter does.
So there's a table users_posts that has all users' posts with column user_id to determine who made the post.
Another table users_followers that contains all followers ie. user_id follows following_id
So here's my query:
User ID = 2271
SELECT users_followers.following_id AS following_id, users_posts.id
FROM users_followers, users_posts
WHERE users_posts.user_id = users_followers.following_id
AND (users_followers.user_id =2271)
This query works but the problem is, it's kinda slow. Is there a faster way to do this?
Also, as you can see, I can only get posts from those I follow, and not myself.
Any help?

If I'm understanding your tables properly, I would do this with an explicit JOIN. I'm not sure how much that would speed things up versus the implicit JOIN you're using though.
SELECT following_id, p.id
FROM users_followers f
LEFT JOIN users_posts p
ON (p.user_id = f.following_id)
WHERE f.user_id = 2271
Chances are, adding an index or two to your tables would help.
Using the MySQL EXPLAIN command (just put it in front of your SELECT query) will show the indexes, temporary tables, and other resources that are used for a query. It should give you an idea when one query is faster or more efficient than another.

Your query is fine as written, provided you have properly indexed your tables. At a minimum you need an index on users_posts.user_id and users_followers.following_id.
A query can also be slowed by large numbers of records, even when it is fully indexed. In that case, I find phpmyadmin to be an invaluable tool. From the server page (maybe localhost) select the Status tab to see a wealth of information about how your mysql server is performing and suggestions for how to improve it.

Related

How to write/optimize sql query that need to select data from 6 related tables until it get what it need

I am writing PHP application built on MySQL database made for 5-6 application sharing it. Because of that, I can not alter database structure, and I know many of you will say to do that first, but unfortunately I can't.
Here is my SQL fiddle of database schema, query that I am using, and desired output:
http://sqlfiddle.com/#!2/de7493/1
My solution is working on this example database, but on real production one, where some of these tables have more than 1m rows, when I try to run it my DB crash. Even if I cut down this sql to select only from 3-4 tables it will still crash. Maybe this is not possible to do, maybe I am doing it wrong. Here is what I have to do:
I am dynamically getting cpv_id from url. In my example, cpv_id is 66113000. Based on that value, I have to discover which club offers are related with that cpv_id. Then based on those offers I have to discover which club members are having some of those offers. ( club members are companies ). Then based on club member id, I have to discover some informations about company that is a member of the club, among that data I have to discover company special_id. And based on that special_id I have to read company reports.
So basically: based on cpv_id I have to discover company reports for the company having club offers related to that id ( simple right ? ). As you can see from the way my tables are related in SQLFiddle, I need to get through 6 tables to get what I really need. Once again, I can not alter database structure.
This is very complex thing going on, I am afraid that you will not understand what I need. I hope that SQLFiddle will help. And if you have any more questions please ask me.
So considering that my solution, my query, fail since database crash if I run it. Is there any way to get desired result ? Can I optimize this query somehow, or do I need to write some other one, or do anything else ? I am pretty lost, since I never had to go this deep and read data from so many tables just to get desired result.
Thanks,
Anita
This seems to do the same thing:
SELECT DISTINCT company_report.*
FROM company_report,
company,
users,
club,
club_offer,
club_offer_cpv
WHERE company_report.company_special_id = company.special_id AND
company.id = users.company_id AND
users.id = club.users_id AND
club.id = club_offer.club_id AND
club_offer.id = club_offer_id AND
club_offer_cpv.cpv_id = 66113000
Other people will prefer joins, but I find this easier to read, and they are equivalent. It would look something like this:
SELECT DISTINCT company_report.*
FROM company_report
JOIN company ON company_report.company_special_id = company.special_id
JOIN users ON company.id = users.company_id
JOIN club ON users.id = club.users_id
JOIN club_offer ON club.id = club_offer.club_id
JOIN club_offer_cpv ON club_offer.id = club_offer_id AND
club_offer_cpv.cpv_id = 66113000
Actually, that's not bad, I mean I might even prefer this last one.
Add index to your table relationships id's, then try to add one by one table using left outer joins

Selecting just one row from a joined MySQL query

I am trying to make a social networking site in PHP/MySQL. I am currently developing status update and comments on status's system. I am trying to show all status of mine and comments on certain status. For doing that I have two tables: comment and user_status.
I have used this MySQL query,
SELECT * FROM user_status LEFT JOIN
comment ON id_status = comment.status_id
WHERE sender_id = '$id2'
OR receive_id = '$id2'
/* $id2 is my id */
I have successfully showed status and one comment. But the problem is, when the number of comments are more than one, then the status shows more than one times. How much same status will be showed depends on how much comments available on certain status. But I would like to be able to display same status only one time, and display more than one comments (if available) on certain status.
This isn't so much a PHP problem as it is confusion about how SQL joins work.
It sounds as if what you really want is not so much a join but a distinct set of records from two tables. Until your SQL skils develop a little more, consider simplifying things by making two queries -- one each for comment and user_status. Also consider requesting just the specific fields you're interested rather than using SELECT *.
Here is a visual explanation of different SQL joins, in case you want to pursue this with a single query.
I assume that you are not displaying the raw results from the query, but rather are piping them to an html page to display. Display only the most recent status in a textbox. then display thin a table or list an ordered list of the comments.
Your query is correct.

Complex mysql search query with few conditions

I have no idea if that is possible, but i have search for users and i want to bring results on after every typed letter, so I'm trying to make that search work as fast as possible, but my ambitious a too high for my knowledge.
I have users db, relations (id, user_id, follower_id, status) which one i including using LEFT JOIN twice, first as followers and than as following.
So what i would like to do, i to bring result in order, like first i want to get people which user is following and are followed back, than just people which user is following, than people who's following user and finally others. And i want to limit all search to max 10 rows. If that is possible to do somehow only in mysql? i already done that in php, but that involves way to many queries to database.
Also im interesting if there is any way to set know if from what contidion that row is.
UPDATE
what i need to get and in what order:
users under following conditions:
by search query & user following and they following back.
by search query & user following.
by search query & people who's following user.
by search query
Order:
user following and they following back.
user following.
people who's following user.
others.
Limit: 0, 10
I believe there is no way i can simply order result in that particular way, so i think about using subquery or something more complex, but my mysql knowledge is too low, and im not sure if that is possible to do in one query, or i just have to use separate query under each condition.
I didn't test it, but I would try something like that:
select distinct u.* from users u, relations r where u.id = r.user_id or u.id = r.follower_id order by u.id = r.user_id

Problem with getting specific data based on several factors in MySQL

I have a system where a user is part of a series of "runs", to each "run", can be added courses, teachers(users), classes and so on.
Each teacher(user) has chosen his/her classes & courses.
Here's a run-down of the tables I have that are relevant:
lam_run - The run in it self.
lam_run_course - Relational table that shows what runs has what courses
lam_teacher_course - Relational table that shows which teacher has which courses
lam_run_teacher - Relational table that shows what teachers are in what courses
What I want to do is show each teacher which runs that are relevant to them (based on which courses they have selected seen in lam_teacher_course) but in which they are not already participating.
Here's the MySQL code I have so far that does not work:
$query_relevant_runs = "
SELECT DISTINCT
lam_run_course.run_id
FROM
lam_teacher_course,
lam_run_course,
lam_run, lam_run_teacher
WHERE
lam_teacher_course.user_id = '1'
AND
lam_teacher_course.course_id = lam_run_course.course_id
AND
lam_run_teacher.user_id != '1'";
Instead this code shows all runs that are relevant, but it doesn't exclude the runs the user is already in..
What can I do to fix this?
Ps. Sorry for bad title, no idea what I should've called it :S
Here is a link to part of the databases (the relevant part): Link!
I think what you're looking for is:
LEFT JOIN `lam_run_teacher` `lam_run_teach_exclude`
ON `lam_run_teacher_exclude`.`user_id` = `lam_teacher_user`.`user_id`
...
WHERE `lam_run_teacher`.`user_id` IS NULL
The LEFT JOIN takes your current query, and appends the additional data to it. However, unlike the INNER JOIN you are using now (using the kinda-strange multiple-from syntax), the LEFT JOIN does not limit your resultset to just those where there is data for the righthand side. The righthand columns will be NULL. By filtering on that NULL, you can find all runs that are interesting, and for which there is not yet a relation to the teacher.
Does this help?
I'd recommend always using the normal join syntax (INNER JOIN target on target.id = source.id) - that way you're more aware of the idea that there are other kinds of join as well, and all your joins will look identical. It takes some getting used to, but definitely helps when your queries get more complex.
Also, in your cross-referencing tables, you can drop the primary key columns. If the only purpose of a table is to define a link between two tables, make the primary key consist of the two keys you've got. Unless you want to be able to related the same teacher to a run multiple times...
OK, took me way longer than it should have, but here's the complete thing:
SELECT
DISTINCT `lam_run_course`.run_id
FROM
`lam_run_course`
INNER JOIN
`lam_teacher_course`
ON `lam_teacher_course`.course_id = `lam_teacher_course`.course_id
LEFT JOIN
`lam_run_teacher` ON (`lam_run_teacher`.`run_id` = `lam_run_course`.`run_id` AND `lam_run_teacher`.`user_id` = 3)
WHERE
`lam_teacher_course`.user_id = 3
and `lam_run_teacher`.`run_id` IS NULL

using joins or multiple queries in php/mysql

Here i need help with joins.
I have two tables say articles and users.
while displaying articles i need to display also the user info like username, etc.
So will it be better if i just use joins to join the articles and user tables to fetch the user info while displaying articles like below.
SELECT a.*,u.username,u.id FROM articles a JOIN users u ON u.id=a.user_id
OR can this one in php.
First i get the articles with below sql
SELECT * FROM articles
Then after i get the articles array i loop though it and get the user info inside each loop like below
SELECT username, id FROM users WHERE id='".$articles->user_id."';
Which is better can i have explanation on why too.
Thank you for any reply or views
There is a third option. You could first get the articles:
SELECT * FROM articles
Then get all the relevant user names in one go:
SELECT id, username FROM users WHERE id IN (3, 7, 19, 34, ...)
This way you only have to hit the database twice instead of many times, but you don't get duplicated data. Having said that, it seems that you don't have that much duplicated data in your queries anyway so the first query would work fine too in this specific case.
I'd probably choose your first option in this specific case because of its simplicity, but if you need more information for each user then go with the third option. I'd probably not choose your second option as it is neither the fastest nor the simplest.
It depends how much data the queries are returning - if you'll be getting a lot of duplicate data (i.e. one user has written many articles) you are better off doing the queries separately.
If you don't have a lot of duplicated data, joins are always preferable as you only have to make one visit to the database server.
The first approach is better if applicable/possible:
SELECT a.*, u.username, u.id
FROM articles a
JOIN users u ON u.id = a.user_id
You have to write less code
There is no need to run multiple queries
Using joins is ideal when possible
Get the articles with one query, then get each username once and not every time you display it (cache them in an array or whatever).

Categories