Following mySQL table search result - php

I have a following system where users can follow each other and search for users to follow. Here are examples of the users and following tables:
Users Table:
+-------+-----------+
| id | userName |
+-------+-----------+
| 1 | John |
| 2 | Harriet |
| 3 | Chris |
| 4 | Lisa |
| 5 | Joe |
+-------+-----------+
Following Table:
+-------+-------+-------+
| id | id_1 | id_2 |
+-------+-------+-------+
| 1 | 5 | 3 |
| 2 | 1 | 2 |
| 3 | 1 | 5 |
| 4 | 5 | 4 |
+-------+-------+-------+
I want to know how to structure a mySQL statement to join the following table with the users table where the username is like '%$search%' to return all results of this occurrence (i.e. searching 'jo' returns John and Joe) and when there are multiple results for each person (i.e. Joe will occur twice in Following) return only results where id_1 is the current logged in users id to show that the logged in user is already following this person.
$search = $_POST['search'];
$userid = $_POST['userid'];
$qry = "
SELECT u.id
, u.userName
, f.id_1
, f.id_2
FROM users u
LEFT
JOIN following f
ON IF('$userid' = f.id_1, u.id = f.id_2, u.id = f.id_1)
WHERE u.userName LIKE '%$search%';
";
This query returns every occurrence of the username in the following table but it should only return once.
Any help would be great.
Thanks.

Not absolutely sure but give it a try
SELECT u.id
, u.userName
, f.id_1
, f.id_2
FROM users u
LEFT JOIN following f
ON u.id in (f.id_1,f.id_2)
AND f.id_1 = '$userid'
WHERE u.userName LIKE '%$search%'
ORDER BY u.id
LIMIT 1;

Related

How can I restrict selecting to only rows which have common value?

Here is my table structure:
// users
+----+--------+
| id | name |
+----+--------+
| 1 | Jack |
| 2 | Peter |
| 3 | John |
| 4 | Barman |
| 5 | Ali |
+----+--------+
// friends
+---------+-----------+
| user_id | friend_id |
+---------+-----------+
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| 3 | 1 |
| 3 | 2 |
| 3 | 4 |
| 5 | 2 |
+---------+-----------+
-- both user_id and friend_id columns refer to the id column of users table
And here is my query:
// $id = 1;
select distinct f1.user_id, f1.friend_id
from friend f1
where user_id = $id
or
user_id in (select f2.friend_id
from friend f2
where user_id = $id);
/* output
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| 3 | 2 |
| 3 | 4 |
| 5 | 2 |
As you see, my query selects
Jack (because of $id = 1)
All Jack's friends
All friends of Jack's friends
Ok all fine. In reality, I'm trying to make a graph of the result. actually I did it. Now I want to restrict the results to only common friends. I mean I want to remove single nodes. In other word, I want to select friends who have at least two edges.
Is doing that possible by changing the query or should I do that in the PHP layer?
A visual example and its expected output:
The bellow query will return all the common friends that are not direct friends:
select distinct f.user_id, f2.friend_id common_friend
from friends f
inner join friends f2
on f.friend_id = f2.user_id
left join friends f3
on f.user_id = f3.user_id
and f2.friend_id = f3.friend_id
where f3.user_id is null
and f.user_id <> f2.friend_id
#and f.user_id = 1 Jack
The first 'inner' join returns the circle of friends and the second 'left' join joins the first-order friends from the circle -> the where f3.user_id is null removes the first-order friends.
The last f.user_id <> f2.friend_id is to remove a user being a common friend to himself.
Try this
SELECT DISTINCT f1.user_id, f1.friend_id
FROM friend f1
WHERE (
user_id = $id
OR user_id IN (
SELECT f2.friend_id
FROM friend f2
WHERE user_id = $id))
AND (friend_id IN (
SELECT f3.friend_id
FROM friend f3
WHERE user_id = $id))

How can I check two conditions before inserting?

I have three tables:
// Posts
+----+----------+---------------+-----------+
| id | title | content | id_author |
+----+----------+---------------+-----------+
| 1 | title1 | content1 | 1234 |
| 2 | title2 | content2 | 5678 |
+----+----------+---------------+-----------+
// Users
+----+--------+--------+
| id | name | active |
+----+--------+--------+
| 1 | jack | 1 |
| 2 | peter | 0 |
| 3 | John | 1 |
+----+--------+--------+
// Votes
+----+---------+---------+
| id | id_post | id_user |
+----+---------+---------+
| 1 | 32 | 1234 |
| 2 | 634 | 5678 |
| 3 | 352 | 1234 |
+----+---------+---------+
Now I need to check two conditions before inserting a new vote into Votes table:
The id of author and what I have passed are the same? Posts.id_user = :author (I know I can do that by a FK, but I don't want)
The account of current user is active? Users.active = 1
Also here is my query:
INSERT INTO Votes (id_post,id_user)
SELECT ?,?
FROM Posts p
WHERE p.id_user = :author limit 1;
How can I add second condition Users.active = 1 to my query?
EDIT: Actually I'm trying to don't let people be able to vote who are inactive (active = 0). For example if SO bans men, then I cannot vote to post anymore, because I (current user) am banned. So I'm pretty sure $_SESSION['id'] should be used in the query.
INSERT INTO Votes (id_post,id_user)
SELECT p.id,u.id
FROM Posts p, Users u
WHERE p.id_user = :author
AND u.id = :user
AND u.active = 1 limit 1;
then you set parameter user equal to the current user id.
EDIT: I suppose id_user in table Votes must be the voter's id, not the author of the post (correct?), so I fixed the query eliminating the JOIN.
Use and with where
INSERT INTO Votes (id_post,id_user)
SELECT ?,?
FROM Posts p, Users u
WHERE p.id_user = :author and u.active = 1 limit 1;
INSERT INTO Votes (id_post,id_user)
SELECT p.id, u.id
FROM Posts p
INNER JOIN Users u ON 1 = 1
WHERE p.id_user = :author
AND u.id = :current_user_id
AND u.active = 1
LIMIT 1;

Mysql loop data from 2 table

I have 2 table as below:
Table 1: common_member
+-----------+-----------+
| uid | username |
+-----------+-----------+
| 1 | haha |
| 2 | walao |
| 3 | alamak |
| 4 | hero |
| 5 | theone |
| 6 | nobody |
+-----------+-----------+
Table 2: labour_slog
+--------------+-------------+--------------+-------------+
| uid | slaveid | masterid | bytime |
+--------------+-------------+--------------+-------------+
| 1 | 2 | 3 | 123456 |
| 4 | 5 | 6 | 456789 |
+--------------+-------------+--------------+-------------+
I fetch the data as script below:
$queryLabourSlog = DB::query("SELECT * FROM ".DB::table('labour_slog')." ORDER BY id desc");
while($rowLabourSlog = DB::fetch($queryLabourSlog)) {
$user_list_slog[] = $rowLabourSlog;
};
array_multisort($idss, SORT_DESC, $user_list_slog);
In my html, I use
<!--{loop $user_list_slog $value}-->{$value[uid]} on {$value[bytime]} forced hire {$value[masterid]}'s employee {$value[slaveid]}.<!--{/loop}-->
The html will display:
1 on 123456 forced hire 3's employee 2.
4 on 456789 forced hire 6's employee 5.
How do I join the Table 1's username data to get the loop display as below?
haha on 123456 forced hire alamak's employee walao.
hero on 456789 forced hire nobody's employee theone.
Thanks.
SELECT table_slog.*, u1.`name`, u2.`name` FROM `table_slog` LEFT JOIN `common_member` AS u1 ON `table_slog`.`uid`=u1.`uid` LEFT JOIN `common_member` AS u2 ON `table_slog`.`slaveid`=u2.`uid` LEFT JOIN `common_member` AS u3 ON `table_slog`.`masterid`=u3.uid ORDER BY `id` DESC
Something like that:
SELECT `uid_main`.`username` AS `main_username`,
`uid_main`.`uid` AS `main_uid`,
`uid_master`.`username` AS `master_username`,
`uid_master`.`uid` AS `master_uid`,
`uid_slave`.`username` AS `slave_username`,
`uid_slave`.`uid` AS `slave_uid`,
`ls`.`bytime` AS `bytime`
FROM `labour_slog` AS `ls`
LEFT JOIN `common_member` AS `uid_main` ON (`ls`.`uid` = `cm`.uid)
LEFT JOIN `common_member` AS `uid_master` ON (`ls`.`master_id` = `cm`.uid)
LEFT JOIN `common_member` AS `uid_master` ON (`ls`.`slave_id` = `cm`.uid)
ORDER BY `cm`.`uid` DESC

JOIN multiple MySQL tables in query

I'm not sure if this is even possible, or if my JOIN-fu just isn't strong enough(it's pretty wimpy to tell you the truth). I have 3 tables which are tied together with a UID. I'm trying to get information from a result from all of them into one query, except I'm having trouble with making sure the result is what I want.
users
========= USERS ==========
| uid | nickname |
--------------------------
| testusr1 | Test User 1 |
| testusr2 | Test User 2 |
| testusr3 | Test User 3 |
| testusr4 | Test User 4 |
============= GALLERY ===========
| id | uid | ext | profile |
---------------------------------
| 1 | testusr1 | png | 1 |
| 2 | testusr2 | jpg | 1 |
| 3 | testusr3 | png | 1 |
| 4 | testusr4 | png | 1 |
| 5 | testusr4 | jpg | 0 |
============= FRIENDS =============
| sender | reciever | status |
-----------------------------------
| testusr1 | testusr3 | 0 |
| testusr2 | testusr3 | 1 |
| testusr2 | testusr1 | 1 |
| testusr3 | testusr4 | 1 |
What I'm trying to do is get all of a user's friends. Friends are in the friends table where the status = 1. The uid can be either the sender or the reciever. In the table above, testusr3's friends are: testusr2 and testusr4
From here I want to snag the nickname from users, and the id from gallery WHERE profile = 1 AND uid = (that friend's ID).
So far, my query looks like:
$query = "SELECT u.uid AS USERID, g.id, g.ext, f.sender, f.reciever
FROM friends f
LEFT JOIN gallery g ON g.uid = f.sender AND g.profile = 1
LEFT JOIN users u ON u.uid = f.sender
WHERE f.status = 1
AND (f.sender = '$sentuid' OR f.reciever = '$sentuid')";
But, it labels all of the results as f.sender...and I'm pretty sure the g.profile = 1 isn't working. It does grab the friends accurately though. Any help would be greatly appreciated.
Untested Solution
Best place to start is to get the matching records in a single column, with UNION. Then you have all the UIDs you need, in one place.
SELECT f.uid, u.nickname, g.id
FROM
(
(SELECT reciever as uid FROM friends where status=1 and sender='$sentuid')
UNION
(SELECT sender as uid FROM friends where status=1 and reciever='$sentuid')
) f
LEFT JOIN gallery g ON f.uid = g.uid and profile=1
LEFT Join users u ON f.uid = u.uid
Side notes:
Generally a bad idea to use char for an ID field.
For performance reasons, you may be better off actually using more storage space, and doubling up on the 'friends' records. i.e.: two entries for each friendship.
Seems to me that you're really close, but a SQLfiddle would help. I believe you are right, g.profile = 1 is not working because you have no table reference for it, might as well take it out. But because of the join, you should be able to select it.
$query = "SELECT u.uid AS USERID, g.id, g.ext, g.profile, f.sender, f.reciever
FROM friends f
LEFT JOIN gallery g ON g.uid = f.sender
RIGHT JOIN users u ON u.uid = f.sender
WHERE f.status = 1
AND (f.sender = '$sentuid' OR f.reciever = '$sentuid')";

Check if records exists in join and assign and count it

Im making an application where its possible to vote on pictures.
Im doing some joins and would like to check each picture i get, if the user logged in has voted on it.
My votes table setup is like this:
+-------------------------+
| id | user_id | photo_id |
+-------------------------+
| 1 | 2 | 6 |
+-------------------------+
| 2 | 4 | 5 |
+-------------------------+
| 3 | 3 | 5 |
+-------------------------+
| 4 | 1 | 6 |
+-------------------------+
Im joining 3 tables:
users, photos and votes
SELECT
users.*,
photos.*,
users.id as user_userid,
photos.id as photo_photoid,
COUNT(votes.id) as totalvotes
FROM
photos
LEFT JOIN
votes
ON
votes.photo_id = photos.id
LEFT JOIN
users
ON
users.id = photos.author_id
GROUP BY
photos.id
ORDER BY
totalvotes
DESC
I would like to make a query inside this sql that does something like this:
+---------------------------------------------------------------------------------+
| photo_photoid | user_userid | totalVotes | currentUserHasVotetThisAmountOfTime |
+---------------------------------------------------------------------------------+
| 6 | 1 | 2 | 1 |
+---------------------------------------------------------------------------------+
| 5 | 1 | 2 | 0 |
+---------------------------------------------------------------------------------+
So i guess im looking for a count of the records, where votes.user_id = $MyLoggedInUser AND votes.photo_id = photo.id
Any suggestions?
Here is your request :
SELECT
v.photo_id,
COUNT(v.id) AS total_votes,
(SELECT COUNT(id) FROM vote WHERE photo_id = v.photo_id AND user_id = 1) AS currentUserHasVotetThisAmountOfTime
FROM
vote AS v
GROUP BY
v.photo_id
ORDER BY
total_votes
DESC
Just replace user_id = 1 by your own ID (in the sub-request line 4).
I get ride of the user_id column, since this is your something you provide there is imo no point to return this in the query as well.
If you want to test it by yourself : http://sqlfiddle.com/#!2/ba2a1/16/0

Categories