I am developing a Friend Request system and currently stuck at one point. I have two tables i.e. member and requests. requests table stores user_id and friend_id of two users and I want to display names of current friends that are to be fetched from member table. For example, request table:
request_id | user_id(to) | friend_id(from) | status
2 | 2 | 3 | 1
3 | 3 | 1 | 1
6 | 4 | 2 | 1
7 | 2 | 1 | 1
I have achieved the current partners with the query below;
SELECT * FROM requests WHERE user_id='2' OR x.friend_id='2' AND x.status='1'
but all I can display for now are id's. What I am trying to achieve is getting the correct names according to the id's as well which are stored in the member table. Data stored in member table is;
member_id | name
1 | John
2 | Steve
3 | Sarah
4 | Stuart
So, if id no. 2 & 3 are friends, the name of the added friend should be displayed in user's profile who accepted the request.
What I am trying to do:
SELECT
x.*,
y.*
FROM
requests x,
member y
WHERE
x.user_id='$member_id' OR
x.friend_id='$member_id' AND
y.member_id = '$member_id' AND
x.status='1'
The result of this query gets a list of other members as well regardless of the member_id I'd specify. Can anybody please point out what I am doing wrong here?
This should return the list you are looking for:
SELECT *
FROM requests x
JOIN member y
ON x.user_id = y.`member_id` OR x.friend_id = y.`member_id`
WHERE x.status = '1' AND y.member_id = '$member_id'
It works by using an inner join on the two tables, getting all of the rows that match the user_id or member_id, and then limiting the list to the is in $member_id.
Although you do not include any other code in your question, I suspect you are using PHP and mysqli to run this query. I would suggest using prepared queries instead of simple variable substitution so you can avoid SQL Injection.
SELECT name from member where user_id IN (select friend_id from request where user_id='$member_id' AND status=1);
Hope this will works!
Related
I'm building a simple website to let people at my work easily match employees names to their baby pictures, using Jquery draggable script.
I have two tables (USERS and ENTRIES). There is a 3rd table called PEOPLE but it's not important for this question.
In entries, the userid of "0" has the CORRECT ordering (i.e. personid 1 should be 4th. personid 2 should be 3rd, etc. And again, personid is from another table called PEOPLE that shouldn't matter for this question).
+----------+---------+--------------+
| userid |firstname| lastname
+----------+---------+--------------+
| 1 | Bob | Wilson |
| 2 | Charlie | Jackson |
| 3 | Jim | Smith |
| 4 | Doug | Jones |
+----------+---------+--------------+
+----------+---------+--------------+
| userid | personid| ordering
+----------+---------+--------------+
| 0 | 1 | 4 |
| 0 | 2 | 3 |
| 0 | 3 | 1 |
| 0 | 4 | 2 |
| 1 | 1 | 2 |
| 1 | 2 | 4 |
| 1 | 3 | 1 |
| 1 | 4 | 3 |
| 2 | 1 | 1 |
| 2 | 2 | 3 |
| 2 | 3 | 4 |
| 2 | 4 | 2 |
+----------+---------+--------------+
I will actually have probably 100 users with entries in the entries table. And each user will have 100 personids with an ordering. What I want to do is, in the most efficient, logical way, loop through all of the entries and compare each one to the CORRECT answer (i.e. userid 0).
So my thinking is probably to get all of the entries in arrays and then compare array for userid 1 to the array for userid 0. Then compare the array for userid2 to the array for userid 0. And so on.
I just want to compare how many right answers each subsequent user has. So in my example tables, userid 1 has ONE correct answer (Personid 3 matching with ordering 1) and userid 2 has TWO correct answers (personid 2 matching with ordering 3 and personid 4 matching with ordering 2).
I first did this...
$sql = "SELECT * FROM entries";
$getpeople = mysqli_query($connection, $sql);
if (!$getpeople) {
die("Database query failed: " . mysqli_error($connection));
} else {
while ($row = mysqli_fetch_array($getpeople)) {
$entriesarray[$row['userid']][$row['personid']]=$row['ordering'];
}
}
That would give me a bunch of arrays for all users with their entries.
Then I did this as a test...
$result_array = array_intersect_assoc($entriesarray[1], $entriesarray[0]);
print_r($result_array);
echo "COUNTRIGHT=".count($result_array);
And that essentially does what I want by giving me COUNTRIGHT of "1". It sees how many from the array for userid 1 match value AND key from the array for userid 0 (again, the correct answer array).
But now I'm stumped as to how to do this efficiently in a nice loop, rather than having to do it one by one. Again, I'd probably have 100 users to loop through. And I'm questioning whether my initial mySQL query above is correct or should be done differently.
And ultimately, I'd want to list out all users firstname, lastname and the number they got right. And order them DESC by the number they got right. In essence, it'd be a leaderboard that would look like...
Jim Smith 2
Charlie Wilson 1
and so on (but on a much greater scale where the person in first place will probably have around 80 or 90 correct).
Because I want to show names too on the "leaderboard", I know I need a JOIN somewhere in here to get that info from the USERS table, so it gets even more convoluted for my tiny brain :)
I hope this makes sense to someone. If anyone can point me in the right direction, that would be fantastic. I'm losing my mind and it's probably fairly simple at the end of the day.
Thanks!
The query below will give you a count of correct entries per user by left joining to user 0 and counting the ordering matches for each person
select t1.userid, count(t2.*)
from entries t1
left join entries t2 on t2.userid = 0
and t2.personid = t1.personid
and t2.ordering = t1.ordering
group by t1.userid
If you need names from the user table you can join it
select u.*, count(t2.*)
from entries t1
join users u on u.userid = t1.userid
left join entries t2 on t2.userid = 0
and t2.personid = t1.personid
and t2.ordering = t1.ordering
group by u.userid
You're on the right track. Comparing all the users in your $entriesarray in a loop is not going to be much more complicated than what you've already done.
First, shift user 0 from the $entriesarray to get the correct set to match against. Then you can just iterate over the rest of the entries array calculating the correct matches like so...
$correctSet = $entriesarray[0];
unset($entriesarray[0]); // we don't want to check this against itself
$leaderBoard = []; // initialize an empty leaderboard array
foreach($entriesarray as $userId => $entries) {
$correctMatches = count(array_intersect_assoc($entries, $correctSet));
$leaderBoard[$userId] = $correctMatches;
}
As far as doing this in SQL, it's also possible by just doing a JOIN against user_id 0 as already answered above (so I won't bother repeating). The user information can also be obtained separately and looked up by user_id since you already have that information in your $leaderboard array in this approach.
I run a management system where people who work different shifts are registered.
I'd like to be able to make a display of how many times each worker/volunteer worked same shifts, like this:
|Amy|Carl|Max|
|---|----|---|
Amy | X | 2 | 6 |
Carl| 2 | X | 5 |
Max | 6 | 5 | X |
I was hoping you had some ideas how to form the query.
The only idea I've come up with so far is to make PHP create a custom query for each user.
Select count(common between user 1 and 2), count(common between user 1 and ...)
Select count(common between user 2 and 1), count(common between user 2 and ...)
etc..
I consider this an ugly way to do it and I am hoping there is some way of retrieving this data within a single query.
The database is stored like this:
Shifts
ID
From
To
Working
ID
ShiftID
UserID
Users
ID
Name
You'll have to self-join the Working table:
SELECT a.UserID, b.UserID, count(a.ShiftID) AS common_shifts
FROM Working AS a
INNER JOIN Working AS b ON ((a.ShiftID = b.ShiftID) AND (a.UserID <> b.UserID))
HAVING common_shifts > 0
Couldn't you do a cross join where each row is compared to the other, and handle the case of userid=userid to put an X instead?
I am attempting at making a site that has a polling section in it. The users need to be able to take previous polls if they have not voted in them yet. So for each poll they take, it adds a note into the cell.
The table looks something like this:
userid | poll1 | poll2 | poll3 | poll4 /
---------+--------+--------+-------+--------/
001 | Y | Y | | /
---------+--------+--------+-------+--------/
002 | Y | | Y | /
--------------------------------------------/
So now, the code would have to select poll 3 and 4 for user 001, and present that to the user on the page. I have been trying a couple different approaches to this but can't seem to find the right code.
I have looked for something for help online and haven't found anything that addresses this issue.
Users
id | name
---+-------
1 | tyrion
2 | cersei
Polls
id | name
---+-------
1 | first poll
2 | second poll
UserPolls
user_id | poll_id
--------+-------
1 | 1
1 | 2
2 | 2
In the above table structure, you have the two main object tables, and one relational table, called UserPolls. This will scale pretty well, for any number of polls you want.
Then, if you want to know which polls were taken by a given user, you can do:
SELECT poll_id FROM UserPolls WHERE user_id = 1
Or if you want the opposite. Polls not taken by a given user:
SELECT id FROM Polls WHERE Polls.id NOT IN (SELECT poll_id FROM UserPolls WHERE user_id = 1)
Note: this is not tested code, but you get the general idea on how to go about designing and normalizing your tables.
Alright, I'm not the best with JOIN's and after all these years of working with mySQL you think I would be by now at the least minimally decent. Guess I've never really worked on anything superbly complex til now worth needing to join a table. So here I am, confused ever so slightly in need of a helpful example to get me on a roll, something that's pertinent to my actual data that I can make heads or tales of cause all the reading I'm doing online else where just gives me headaches for the moment. I think I might be stuck on the mythology of JOIN's being a hard thing to do, they don't seem like it but when ever I've tried I fail. So anyway I am working with PHP as my server side coding, and I believe MySQL 5.
So heres the construct to an extent.
I have table information and table connections.
Connections has: member_id, connection_id, active
Information has: firstname, lastname, gender, member_id
I should say the tables contain more data per table, but as I understand it I need write a query that I can use the member_id as the connector/foreign key. Where I can use both sides of the information. I need to know if active is 1, and then I need to know all of the columns above mentioned for information.
I tried
SELECT member_id,
connection_id,
active,
firstname,
lastname,
gender,
member_id
FROM connections, information
WHERE connection.member_id = information.member_id AND
connection.active = 1
and I've tried
SELECT * FROM connections, information
WHERE connection.member_id = information.member_id AND
connection.active = 1
With the first one I get member_id is ambitious which is understandable to a point i think cause of the matching columns between the two tables. Then the second query doesn't server me well as it only results with one person.
My Ultimate goal is to find all the connections for a specific member_id in the connections table, while gathering all the information about those connections from the information table using the connection_id as its the same thing as the member_id in the in the information table.
So in laymans terms if I am not making sense lets say I wanted to list out all my friends in from the DB. My connection table lets me know which people I am connected to where member_id is my id and connection_id is my friends member_id on another table. Hopefully that makes more sense. And this is where I am having trouble with my query and trying to write it correctly. If I could get a working sane sample of that I think I might be able to make better sense of JOIN's doesnt help that I also can't figure out what type of JOIN is best suited for my needs either I suppose.
EDIT....
Ok as per request from comment below. Sample data expected output from tables that look similar to this:
Connections Table
member_id, connection_id, active
1 | 2 | 1
1 | 3 | 1
1 | 4 | 1
1 | 5 | 1
2 | 1 | 1
2 | 5 | 1
3 | 1 | 1
Information Table
member_id, firstname, lastname, gender, ...other unimportant rows for this query
1 | Chris | Something | m | ....
2 | Tony | Something | m | ....
3 | Brandon | Something | m | ....
4 | Cassie | Something | f | ....
5 | Jeff | Something | m | ....
6 | John | Something | m | ....
now from the connections table I need to gather all the connection_id's associated with my member_id where active is 1 then from the information table gather everyone firstname, lastname, gender.. Now I know I can do this 2 step where I pool all the connection_id's from connections then run them through a loop of some sort and one by one get the resulting id's from the first query but to me that seems a bit obscure and process intensive which I want to avoid, which brings me here.. Currently from my original query posted to the many shared thus far trying to help my results are to the effect of
1 | Chris | Something | m | 2
1 | Chris | Something | m | 3
1 | Chris | Something | m | 4
1 | Chris | Something | m | 5
what I'd like to see returned is something like
2 | Tony | Something | m
3 | Brandon | Something | m
4 | Cassie | Something | f
5 | Jeff | Something | m
After looking at this I suppose I would also need to know the friendID column that matches my member_id as well but thats something to figure out after this initial hurdle
The error is in your WHERE Clause because instead of Connections you wrote it Connection which then the server generates the error.
...
WHERE connection.member_id = information.member_id AND
connection.active = 1
try this:
SELECT a.Member_ID,
a.FirstName,
a.LastName, a.gender,
b.Connection_ID
FROM Information a INNER JOIN Connections b
on a.Member_ID = b.Member_ID
WHERE b.`Active` = 1
UPDATE
if that's the case then you will most likely have a SELF JOIN
SELECT DISTINCT b.Connection_ID,
c.*
FROM Information a INNER JOIN Connections b ON
a.Member_ID = b.Member_ID
INNER JOIN Information c ON
b.Connection_ID = c.Member_ID
WHERE b.`Active` = 1
AND a.Member_ID = 'ID HERE' -- If you want to get for specific member
The error in the first is "ambiguous" not ambitious. Ambiguous means that the SQL engine doesn't know which column you are talking about, because you have two columns with the same name (different tables but still).
You can fix that by specifying the table name along with the column name where you list the columns for select.
For example
SELECT connections.member_id, connection_id, active, firstname, lastname, gender, information.member_id FROM connections, information WHERE connections.member_id = information.member_id AND connections.active = 1
The problem with returning only one suggests that there is only one record that matches your query but it's hard to guess.
Try changing to:
SELECT * FROM connections c JOIN information i ON i.member_id = c.member_id WHERE c.active = 1
Try this:
SELECT *
FROM information
LEFT OUTER JOIN connections
ON information.member_id = connections.member_id
WHERE connections.active = 1;
You're joining on the wrong tables. You said:
where member_id is my id and connection_id is my friends member_id on another table
Then, what you have to match is connections.connection_id with information.member_id. The simplest solution is:
select c.member_id, c.connection_id, c.active from connections c
join information i on c.connection_id = i.member_id
where c.active = 1 and c.member_id = #yourId
That's all :)
Two clarifications:
I'm going to actually be doing pagination with this, so ideally it can be one SQL statement...
If this helps, what I'm trying to do is: Get all content for user, BUT if content item has criteria in content_criteria table, check that user also has criteria in users_criteria table, OTHERWISE, content is valid for user
So this might be hard to explain. Let's start with the main tables:
content:
| contentIdNum | contentStr | programIdNum |
A piece of content (unlike users) can only be associated with one program.
A typical record would be like this. Both are associated with a program with id of 1.
| 1 | Zelda | 1 |
| 2 | Mario | 1 |
content_criteria:
| contentIdNum | criteriaIdNum |
A typical record would be like this: (this basically a table that associates content with criteria. Not all content is associated with criteria.)
| 1 | 5 |
** user_criteria: **
| userIdNum | criteriaIdNum |
A typical record would be like this: (this basically a table that associates users with criteria. Not all content is associated with criteria.) Note that userIdNum 1 has the same criteria as contentIdNum 1
| 1 | 5 |
** program_users: **
| userIdNum | criteriaIdNum |
A typical record would be like this (both user 1 and 2 are associated with program 1)
| 1 | 1 |
| 2 | 1 |
So here's what I need to do:
Create a MySQL call that returns all pieces of content a user has access to
By default, a user has access to all content associated with the programs he is assigned to
If a piece of content has criteria associated with it in the content_criteria table, ONLY users with that corresponding criteria in the user_criteria table have access to that content
For example, if I pass in userIdNum 1, I should get both pieces of content
If I pass in userIdNum of 2, I should only get one piece of content (the one with contentIdNum of 2)
Obviously selecting content that matches a user's programs is easy (below is what I have). I'm trying to figure out an easy way to filter the content - can I do it in one go, or do I have to do a secondary pass and loop through the content via PHP?
SELECT DISTINCT (c.contentIdNum), c.*
FROM content c , program_users pu
WHERE 1=1
AND pu.userIdNum = 2 AND pu.programIdNum = c.programIdNum
SELECT c.*
FROM content c ,
program_users pu ,
content_criteria cc,
user_criteria uc
WHERE pu.userIdNum = 2
AND pu.programIdNum = c.programIdNum
and cc.contentIdNum = c.contentIdNum
and uc.criteriaIdNum = cc.criteriaIdNum
and uc.userIdNum = pu.userIdNum
should do the trick.
"distinct" is a really good way of hiding bugs - especially while you're still trying to work out what your query should look like.
Fix it thanks to UNIONs. The first part of the UNION gets all content that does NOT have a criteria to filter by. The second part of the UNION gets all content with a criteria to filter by, if the user has that criteria.
SELECT c.*
FROM content c ,
program_users pu
WHERE pu.userIdNum = 1
AND pu.programIdNum = c.programIdNum
AND NOT EXISTS (
SELECT *
FROM content_criteria cc
WHERE cc.contentIdNum = c.contentIdNum
)
UNION
SELECT c.*
FROM content_criteria cc, users_criteria uc, content c
WHERE cc.contentIdNum = c.contentIdNum
AND cc.criteriaIdNum = uc.criteriaIdNum
AND uc.userIdNum = 1