MySQL select distinct across multiple tables - mysql

I have a query that selects all columns from multiple tables, but it's returning multiples of the same values (I only want distinct values).
How can I incorporate something like this? When I try this, it still
Select Distinct A.*, B.*, C.*....
Does distinct only work when selecting the column names and not all (*) ? In this reference it says distinct in reference to column names, not across all of the tables. Is there any way that I can do this?
edit - I added more info below
Sorry guys, I just got back onto my computer. Also, I just realized that my query itself is the issue, and Distinct has nothing to do with it.
So, the overall goal of my Query is to do the following
Generate a list of friends that a user has
Go through the friends and check their activities (posting, adding friends, etc..)
Display a list of friends and their activities sorted by date (I guess like a facebook wall kind of deal).
Here are my tables
update_id | update | userid | timestamp //updates table
post_id | post | userid | timestamp //posts table
user_1 | user_2 | status | timestamp //friends table
Here is my query
SELECT U.* , P.* ,F.* FROM posts AS P
JOIN updates AS U ON P.userid = U.userid
JOIN friends AS F ON P.userid = F.user_2 or F.user_1
WHERE P.userid IN (
select user_1 from friends where user_2 = '1'
union
select user_2 from friends where user_1 = '1'
union
select userid from org_members where org_id = '1'
union
select org_id from org_members where userid = '1'
)
ORDER BY P.timestamp, U.timestamp, F.timestamp limit 30
The issue I'm having with this (that I thought was related to distinct), is that if values are found to meet the requirements in, say table Friends, a value for the Posts table will appear too. This means when I'm displaying the output of the SQL statement, it appears as if the Posts value is shown multiple times, when the actual values I'm looking for are also displayed
The output will appear something like this (notice difference between post value in the rows)
update_id | update | userid | timestamp | post_id | post | userid | timestamp | user_1 | user_2 | status | timestamp
1 | update1 | 1 | 02/01/2013 | 1 | post1| 1 | 2/02/2013| 1 | 2 | 1 | 01/30/2013
1 | update1 | 1 | 02/01/2013 | 2 | post2| 1 | 2/03/2013| 1 | 2 | 1 | 01/30/2013
So, as you can see, I thought I was having a distinct issue (because update1 appeared both times), but the query actually just selects all the values regardless. I get the results I'm looking for in the Post table, but all the other values are returned. So, when I display the table in PHP/HTML, the Post value will display, but I also get duplicates of the updates (just for this example)

When you select distinct *, you select every row, including the one that makes the record unique. If you want something better than what you are getting, you have to type the individual column names in your select clause.

It would be easy if you explain a little more what is the connection between the tables you'r querying, because you can use joins, unions (as mentioned above) or even group by's ...

Your updated post shows one of the JOIN conditions as:
JOIN friends AS F ON P.userid = F.user_2 OR F.user_1
This is equivalent to:
JOIN friends AS F ON (P.userid = F.user_2 OR F.user_1 != 0)
and will include many rows that you did not intend to include.
You probably intended:
JOIN friends AS F ON (P.userid = F.user_2 OR P.userid = F.user_1)

I think you want this:
select *
from tableA
union
select *
from tableB
union
select *
from tableC
This assumes that HHS tables all have the same number of columns and they are of the same data type. This not, you'll have to select specific columns to make it so.

Related

Unable to write a proper query to join two tables and fetch what I need

I'm trying to fetch data from table1 which doesn't have a column with a specific value I include
Consider a social media site:
I have a "posts" table where I save all the posts by the user with their User id,
and I have the "follow" table where I save all the data like who's following who.
Now I'm trying to get all the data from the posts table where the user isn't following them
Example:
posts table
| u_id | Post |
|:---- |:----:|
| 1 |post1 |
| 2 |post2 |
| 1 |post3 |
| 3 |post4 |
follow table:
| u_id | following |
|:---- |:---------:|
| 2 | 1 |
| 1 | 3 |
Now the scenario: Let's say I'm the logged-in user with user id: 2, as per the requirement I should only see the posts of users that I'm not following, i.e., user #2 (which is me) and user #3 only.
So far the query I tried is:
$query = "SELECT posts.id, posts.u_id, posts.title, posts.date
FROM posts
LEFT JOIN follows
ON posts.u_id=follows.u_id
WHERE (follows.u_id != '$u_id')";
The $u_id is the logged-in user's id which is in the above scenario #2.
Now I m trying to get all the data from the posts table where the user isn't following them
SELECT p.id, p.u_id, p.title, p.date
FROM posts p LEFT JOIN
follows f
ON p.u_id = f.following AND
f.u_id = ?
WHERE u.u_id IS NULL;
LEFT JOIN is a fine approach. However, this is looking at what posts match following not u_id. Then you want to return the rows where there are no matches.
You ask to find posts of users which you are not following. Use NOT IN, NOT EXISTS, or LEFT JOIN:
SELECT *
FROM posts
WHERE posts.u_id NOT IN (SELECT following FROM follows WHERE u_id = 'me')
AND posts.u_id <> 'me' -- Remove this line if you want to see your posts.
;
I assume you wouldn't follow yourself. Just remove the noted line in the WHERE clause to see your posts.
This is similar to the LEFT JOIN approach.

MySQL Multiple Join with delimiting via FINDINSET

I am attempting to JOIN onto two different columns in the first table below from columns in the second and third tables.
I wish to JOIN users.id to job_listings.id to return users.username, and to also JOIN and delimit job_listings.categories to job_categories.id to return job_categories.description via FIND_IN_SET
job_listings
id | employer_id | categories
1 | 1 | 1,2
2 | 1 | 2
users
id | username | type
1 | foo | employer
2 | wat | employer
job_categories
id | description
1 | fun
2 | hak
I desire output that is of the following format:
output
username | type | category | description
foo | employer | 1 | fun
foo | employer | 2 | hak
foo | employer | 2 | hak
I have tried using various permutations of the following code:
SELECT users.username, users.type, job_listings.categories FROM users
JOIN job_listings ON users.id
JOIN job_listings AS category ON FIND_IN_SET(category.categories, job_categories.id)
ORDER BY users.username, category.categories
I know from other answers that I need to use an alias in order to use multiple JOIN operations with the same table, but despite adapting other answers I keep receiving errors related to declaring an alias, or returning output that has a column with the alias but no data returned in that column.
First, you should normalize your design. You should not store integer values in strings. You should not have foreign key references that you cannot declare as such. You should not store lists in strings. Is that enough reasons? You want a junction table for JobCategories with one row per job and one row per category.
Sometimes, we are stuck with other peoples lousy decisions and cannot readily change them. In that case, you want a query like:
SELECT u.username, u.type, jc.id, jc.category
FROM users u JOIN
job_listings jl
ON u.id = jl.employer_id and u.type = 'employer' join
job_categories jc
ON FIND_IN_SET(jc.id, j.categories) > 0
ORDER BY u.username, jc.category;
This query cannot take advantage of indexes for the category joins. That means that it will be slow. The proper data structure -- a junction table -- would fix this performance problem.

Selecting 2 rows from same table for different criterias

I've tried many examples for inner joins, outer joins and even tried conjuring my own with guesses (which more than often works) but no luck here.
TABLE 1:
follower_user_id, followed_user_id
(note it's followeR_ and followeD_)
TABLE 2:
user_id, username
So I need two rows from TABLE 2 where one user_id matches follower_user_id and another row where user_id matches followed_user_id
Query within query works but I know this isn't the way to go...
SELECT f.*, u.*
FROM tbl_follows f, tbl_users u
WHERE follower_user_id = u.user_id
That's the basic query
while($row = $r->fetch_assoc()){
//here i make another query to get the username of the followed_user_id
}
Surely this can be done in a single query?
Thanks in advance
--- UPDATE 1: Sample Data ---
tbl_users
user_id | username
--------------------------------------
1 | abc123
2 | xyz789
3 | nosey123
tbl_follows
follower_user_id | followed_user_id
-------------------------------------------
3 | 2 //nosey123 is following xyz789
3 | 1 //nosey123 is following abc123
1 | 2 //abc123 is following xyz789
While Results :
echo "$row[username] is following $row['???????']<br />"
I'm looking for:
nosey123 is following xyz789
nosey123 is following abc123
abc123 is following xyz789
Have you tried something like this?
SELECT f.*, u.*
FROM tbl_follow f
JOIN tbl_users u ON u.user_id = f.follower_user_id OR u.user_id = f.followed_user_id;
This should return two rows for each userID, since there will be one match for follower user and one match for followed user.
SELECT DISTINCT(A.user_id), A.username, B.*
FROM tbl_follow A
JOIN tbl_users B
ON B.user_id = A.follower_user_id
OR B.user_id = A.followed_user_id;

MySQL select row with two matching joined rows from another table

Hey I try to select a row from a table with two matching entries on another one.
The structure is as following:
----------------- ---------------------
| messagegroups | | user_messagegroup |
| | | |
| - id | | - id |
| - status | | - user_id |
| | | - messagegroup_id |
----------------- | |
---------------------
There exist two rows in user_messagegroup with the ids of two users and both times the same messagegroup_id.
I would like to select the messagegroup where this two users are inside.
I dont get it.. so I would appreciate some help ;)
The specification you provide isn't very clear.
You say "with the ids of two users"... if we take that to mean you have two user_id values you want to supply in the query, then one way to to find the messagegroups that contain these two specific users:
SELECT g.id
, g.status
FROM messagegroups g
JOIN ( SELECT u.messagegroup_id
FROM user_messagegroup u
WHERE u.user_id IN (42, 11)
GROUP BY u.messagegroup_id
HAVING COUNT(DISTINCT u.user_id) = 2
) c
ON c.messagegroup_id = g.id
The returned messagegroups could also contain other users, besides the two that were specified.
If you want to return messagegroups that contain ONLY these two users, and no other users...
SELECT g.id
, g.status
FROM messagegroups g
JOIN ( SELECT u.messagegroup_id
FROM user_messagegroup u
WHERE u.user_id IS NOT NULL
GROUP BY u.messagegroup_id
HAVING COUNT(DISTINCT IF(u.user_id IN (42,11),u.user_id,NULL)) = 2
AND COUNT(DISTINCT u.user_id) = 2
) c
ON c.messagegroup_id = g.id
For improved performance, you'll want suitable indexes on the tables, and it may be possible to rewrite these to eliminate the inline view.
Also, if you only need the messagegroup_id value, you could get that from just the inline view query, without the need for the outer query and the join operation to the messagegroups table.

Mysql select between two table without limiting if record appear on the joined table

I have been trying to figure out how to select data related to one id between to tables without limit it to the joined table. I tried using UNION, Inner join, JOIN, but it limit me to show records that are only in both tables. By example:
Table 1 (users)
id | name | register
1 | John | 2014-03-01
2 | Kate | 2014-03-02
etc..
Table 2 (birthdays by example)
id | user | birthday
1 | 1 | 1989-09-09
Note that kate dont have a record on the birthdays table, if i do:
SELECT U.id, name, register, B.birthday FROM users as U INNER JOIN birthday as B ON B.user = U.id
it will only shows JOHN data, i would like to select all my users and if the record do not exist on the joined table, still be able to select all my users, sort of:
id | name | register | birthday
1 | John | 2014-03-01 | 1989-09-09
2 | kate | 2014-03-02 | null or ''
3
4
etc.
Sorry if its a stupid question but i dont find the light on this one. I would appreciate the help.
Regards
You need a LEFT OUTER JOIN instead of the plain JOIN (also known as INNER JOIN), like this:
SELECT U.id, name, register, B.birthday
FROM users as U
LEFT JOIN birthday as B
ON B.user = U.id
A LEFT JOIN between users and birthday tables will contain all records of the "left" table (users), even if the join-condition does not find any matching record in the "right" table (birthday).
This excellent article on The Code Project will help you a lot: Visual Representation of SQL Joins.
Summary of all JOIN types:
Note: Mysql does not support FULL OUTER JOIN but it can be emulated. Useful articles:
https://stackoverflow.com/a/4796911
http://www.sql-tutorial.ru/en/book_full_join_and_mysql.html
http://www.xaprb.com/blog/2006/05/26/how-to-write-full-outer-join-in-mysql/
Use left outer join instead of inner join..
SELECT U.id, name, register, B.birthday
FROM users as U left join birthday as B ON B.user = U.id