SQL Select based on certain Data - mysql

I have a few tables in my database:
user table: user_id (primary key), first_name, last_name, email_address.
inst table: inst_id (primary key), inst_name, and type.
user_insts table: user_insts_id (primary key), user_insts_status, inst_name (foreign key) and user_id(foreign
key).
I'm using this on my website and i need it to display all of the entrys in the inst_name column for the inst table, but only the entrys for a certain id in the right side or else show as null. I've tried a few things like below:
SELECT inst.inst_name,inst.inst_id,user_insts.user_id,user_insts.inst_name
FROM inst LEFT JOIN user_insts ON inst.inst_name=user_insts.inst_name;
SELECT inst.inst_name,inst.inst_id,user_insts.user_id,user_insts.inst_name
FROM inst LEFT JOIN user_insts ON inst.inst_name=user_insts.inst_name
WHERE user_insts.user_id='11';
Any help would be greatly appreciated.
EDIT::
this is what i currently get:
inst_name inst_id user_id:
ASB 1 11
BNZ 3 11
FMG 5 11
i was hoping to be able to get something more like this:
inst_name inst_id user_id:
ASB 1 11
ANZ 2 NULL
BNZ 3 11
paymark 4 NULL
FMG 5 11
STATE 6 NULL

What your original query will do is to get all rows from the inst table and then see whether there is a row that matches on inst_name in your user_insts table. If there is it will return the data from that table. Otherwise it will return NULLs. If you change the JOIN to be an INNER JOIN then it will only return rows where the right-hand side matches. Like this:
SELECT inst.inst_name,inst.inst_id,user_insts.user_id,user_insts.inst_name
FROM inst INNER JOIN user_insts ON inst.inst_name=user_insts.inst_name
WHERE user_insts.user_id='11';
But you should look at changing you schema. You have an integer primary key on inst so you should use that rather than inst_name as the foreign key on inst_name.

Do your provided queries show the following results?
Query 1 : Shows all inst + user_insts entries but unfiltered by user_id
Query 2 : Shows just the inst + user_insts entries filtered by user_id
What's happening in Query 2 is that the where clause filters the joined tables AFTER they are joined. I guess what you want to happen is to first filter the right side of the result (user_insts) by a specific user_id like so:
SELECT ui.inst_name, ui.user_id FROM user_insts ui WHERE ui.user_id = :PARAM
Then, you want to LEFT JOIN this with all the entries in the inst table AFTER the filter. You could use an inner view in order to filter by user_id first before the actual joining to the inst table. The resulting query should be something like this:
SELECT i.inst_name, filtered_ui.user_id
FROM inst i
LEFT JOIN (SELECT ui.inst_name, ui.user_id
FROM user_insts ui
WHERE ui.user_id = :PARAM) filtered_ui
ON i.inst_name = filtered_ui.inst_name
Thinking about it more, I'm not too familiar with MySQL so I'm not sure if this alternative query is valid syntax:
SELECT i.inst_name, ui.user_id
FROM inst i
LEFT JOIN user_insts ui ON i.inst_name = ui.inst_name AND ui.user_id = :PARAM
... which may be simpler than an inner view.
The main point is you have to do the filtering first before joining, so that all the inst_names will be displayed.

You question isn't 100% clear so I'm making the assumption that you want to show the inst_name for each user; showing the inst_name as null when an inst entry doesn't exist.
Something like this should work:
select u.user_id, i.inst_name
from user u
left join user_insts ui on ui.user_id = u.user_id
left join inst i on i.inst_name = ui.inst_name
You can constrain the results by user_id by adding
where u.user_id = '11'

Related

How to Join three tables properly

The main table has 4 columns:
User Activity Table
userActivityId userId therapistId activityId
1 1 1 1
Each of these columns is a table and these values are all foreign keys.
Basically im trying to run a query that will join to the users table and pull their first and last name based off the user Id.Same thing with therapist - join to the therapist table, pull first + last name.And finally Join to the Activity table and pull the activity name and path from the activity Id
The other tables look like this:
User Table
userId fName lName
Therapist Table
therapistId therapistFirstName therapistLastName
Activity Table
activityId activityTitle activityPath
So far my query looks like
SELECT
User_Activities.userId,
User_Activities.therapistId,
User_Activities.activityId,
Activities.activityTitle,
Activities.activityPath,
Users.fName,
users.lName,
Therapists.therapistFirstName,
Therapists.therapistLastName
FROM
User_Activities
INNER JOIN Users
ON User_Activities.userId = Users.userId
INNER JOIN Therapists ON
User_Activities.therapistId = Therapists.therapistId
INNER JOIN Activities ON
Activities.activityId = User_Activities.userActivityId
WHERE
User_Activities.userId = 1;
When I run this query It only returns 1 row as a result. However there are two activities in the User_Activites table assigned to userId 1.
If I change : INNER JOIN Activities ON
Activities.activityId = User_Activities.userActivityId
from an INNER JOIN to the LEFT JOIN it will display the second row, however the activityTitle and activityPath will be displayed as NULL in the second row.
userActivityId userId therapistId activityId activityId activityTitle activityPath fName lName therapistFirstName therapistLastName
1 1 1 1 1 Brain GZZ0zpUQ S C M D
11 1 1 1 NULL NULL NULL S C M D
You have pretty much answered your question. The second activity does not have a valid ActivityId.
If you want all activities for a user, then you should phrase the query as:
SELECT . . .
FROM Users u LEFT JOIN
User_Activities ua
ON ua.userId = u.userId LEFT JOIN
Therapists t
ON ua.therapistId = t.therapistId LEFT JOIN
Activities a
ON a.activityId = ua.userActivityId
WHERE u.userId = 1;
You want to start with the table where you want to keep all the rows. Then use LEFT JOIN to bring in other tables.
Two other changes of note:
Table aliases are used to simplify reading and writing the query. The SELECT needs to change to use the aliases.
The WHERE clause refers to the Users table rather than UserActivities.

Insert one db's different tables data to other db's single table

i'm running into a complex problem, the data in a db has three tables.
First_DB
-- default_users
id username email password
1 Timbog Timbog#mail.com vads7y3kkjdfa
2 Marta Marta#mail.com vads7y3kkjdfa
-- default_album
album_id album_name default_user_id
1 Name_Tim 1
3 Katarina 2
-- default_album_img
img_id image_file album_id
3 1320229733.jpg 1
4 3320229733.jpg 3
Second_DB
--users
user_id user_name user_email user_pass user_image
1 Timbog Timbog#mail.com vads7y3kkjdfa 1320229733.jpg
2 Marta Marta#mail.com vads7y3kkjdfa 3320229733.jpg
The approach i used to solve this problem is to first fetch all data by inner join, should i use full outer join and insert the required field to my table, the following query is actual by which i'm trying to make it wor:
INSERT INTO bbpin.users ( user_name, user_pin, user_email, user_password, user_img)
SELECT default_users.username, default_users.bb_pin, default_users.email, default_users.password
FROM bbmpins_pins.default_users
INNER JOIN bbmpins_pins.default_album_images
ON default_album_images.album_id = default_users.id;
i miss the thing how do i compare two table's id in this join maybe? or this query is all wrong by approach?
By two tables which are sepearte in First_DB there could be multiple record how do we trunk them to last entry only ?
Thanks
It looks like you are attempting to retrieve all rows from the default_users table. And along with each row, also return the corresponding row(s) from default_album table. And along with that, the corresponding row(s) from default_album_img table.
Given the example data, a query using inner joins would return the specified result:
SELECT u.id AS user_id
, u.username AS user_name
, u.email AS user_email
, u.password AS user_pass
, i.image_file AS user_image
FROM default_users u
JOIN default_album a
ON a.default_user_id = u.id
JOIN default_album_img i
ON i.album_id = a.album_id
That query will work for the example data.
But, if there is a row in default_user which doesn't have a matching row in default_album, then an inner join won't return that row:
-- default_users
id username email password
3 branstark bran#winterfell warg2
Or, if there are two or more rows in default_album that match a given user, then the query will return two copies of the row from default_user...
-- default_album
album_id album_name default_user_id
1 Tim2 1
Without a specification of what is to be returned in those cases, we can't recommend a query.
I don't see anything wrong with your current approach using a JOIN but could modify it a bit to be more readable and also you will have to join the relation table
INSERT INTO bbpin.users (user_id, user_name, user_pin, user_email, user_password, user_img)
SELECT du.id,
du.username,
du.bb_pin,
du.email,
du.password,
dai.image_file
FROM bbmpins_pins.default_users du
JOIN bbmpins_pins.default_album da ON du.id = da.default_user_id
INNER JOIN bbmpins_pins.default_album_images dai
ON dai.album_id = da.album_id;

MySQL Joins on n to n relational table keping NULL values

This is a vote system, where candidate can be voted from different(limited) places. and I want the number of vote per place of each candidate.
I have 3 tables
TABLE candidate
------------------
id
name
TABLE place
------------------
id
label
TABLE vote
------------------
id
id_candidate
id_vote
no_votes // represents the amount of votes in this place for that particular candidate
Suppose I have 10 candidates and 15 different places, I'm trying to make a query that will return 10*15 = 150 rows even if there is no votes, keeping NULL value for ids that are not present in the relational table(which i can replace by 0).
But i'm not making the correct query
Here is the query i made so far (i've tried many modification, inner, outer joins... but nothing worked)
SELECT *
FROM votes
RIGHT JOIN candidate ON candidate.id = candidate_id
LEFT JOIN palce ON place.id = place_id
First, if you want the number of votes per candidate, then you should be thinking "aggregation".
Second, don't mix left and right joins in a query. It is just confusing. Start with the table where you want to keep all the rows, and then just use left join.
So, something like this:
SELECT c.*,
SUM(p.place_name = 'place1') as place1,
SUM(p.place_name = 'place2') as place2,
SUM(p.place_name = 'place3') as place3
FROM candidate c LEFT JOIN
votes v
ON c.id = v.candidate_id LEFT JOIN
place p
ON p.id = v.place_id
GROUP BY c.id;
Considering:
TABLE vote
------------------
id PK
id_candidate FK to candidate
id_vote FK to place
no_votes
-
SELECT CA.name,
PL.label,
SUM(VO.no_votes) as votes
FROM candidate CA
LEFT JOIN vote VO ON CA.id = VO.id_candidate
LEFT JOIN place PL ON PL.id = VO.id_vote
GROUP BY CA.id, PL.id

SQL Join and show results if join false

I have a table - comments. Users can post if not a member of the site but want to show their details if they are.
So if a user comments who is NOT a member I show their posts but don't link to their profile, because they don't have one.
So, in the following query I want to return the rows even if there is no join:
select wc.comment, wc.comment_by_name, wc.user_id, u.url from comments wc
join users u on wc.wag_uid = u.user_id
where id = '1237' group by wc.comment order by wc.dateadded desc
I want to return:
comment comment_by_name user_id url
------- --------------- ------- ----
hello dan 12 /dan
hey jane /jane
world jack 10 /jack
But the above does not return the data for jane as she does not have a user_id
Is there a way to return all data even if the join is null?
use LEFT JOIN instead
SELECT wc.comment, wc.comment_by_name, wc.user_id, u.url
FROM comments wc
LEFT JOIN users u
on wc.wag_uid = u.user_id
WHERE id = '1237'
GROUP BY wc.comment
ORDER BY wc.dateadded DESC
basically INNER JOIN only select records which a record from one table has atleast one match on the other table while LEFT JOIN select all rows from the left hand side table (in your case, it's comments) whether it has no match on the other table.

Mysql query in drupal database - groupwise maximum with duplicate data

I'm working on a mysql query in a Drupal database that pulls together users and two different cck content types. I know people ask for help with groupwise maximum queries all the time... I've done my best but I need help.
This is what I have so far:
# the artists
SELECT
users.uid,
users.name AS username,
n1.title AS artist_name
FROM users
LEFT JOIN users_roles ur
ON users.uid=ur.uid
INNER JOIN role r
ON ur.rid=r.rid
AND r.name='artist'
LEFT JOIN node n1
ON n1.uid = users.uid
AND n1.type = 'submission'
WHERE users.status = 1
ORDER BY users.name;
This gives me data that looks like:
uid username artist_name
1 foo Joe the Plumber
2 bar Jane Doe
3 baz The Tooth Fairy
Also, I've got this query:
# artwork
SELECT
n.nid,
n.uid,
a.field_order_value
FROM node n
LEFT JOIN content_type_artwork a
ON n.nid = a.nid
WHERE n.type = 'artwork'
ORDER BY n.uid, a.field_order_value;
Which gives me data like this:
nid uid field_order_value
1 1 1
2 1 3
3 1 2
4 2 NULL
5 3 1
6 3 1
Additional relevant info:
nid is the primary key for an Artwork
every Artist has one or more Artworks
valid data for field_order_value is NULL, 1, 2, 3, or 4
field_order_value is not necessarily unique per Artist - an Artist could have 4 Artworks all with field_order_value = 1.
What I want is the row with the minimum field_order_value from my second query joined with the artist information from the first query. In cases where the field_order_value is not valuable information (either because the Artist has used duplicate values among their Artworks or left that field NULL), I would like the row with the minimum nid from the second query.
The Solution
Using divide and conquer as a strategy and mysql views as a technique, and referencing this article about groupwise maximum queries, I solved my problem.
Create the View
# artists and artworks all in one table
CREATE VIEW artists_artwork AS
SELECT
users.uid,
users.name AS artist,
COALESCE(n1.title, 'Not Yet Entered') AS artist_name,
n2.nid,
a.field_image_fid,
COALESCE(a.field_order_value, 1) AS field_order_value
FROM users
LEFT JOIN users_roles ur
ON users.uid=ur.uid
INNER JOIN role r
ON ur.rid=r.rid
AND r.name='artist'
LEFT JOIN node n1
ON n1.uid = users.uid
AND n1.type = 'submission'
LEFT JOIN node n2
ON n2.uid = users.uid
AND n2.type = 'artwork'
LEFT JOIN content_type_artwork a ON n2.nid = a.nid
WHERE users.status = 1;
Query the View
SELECT
a2.uid,
a2.artist,
a2.artist_name,
a2.nid,
a2.field_image_fid,
a2.field_order_value
FROM (
SELECT
uid,
MIN(field_order_value) AS field_order_value
FROM artists_artwork
GROUP BY uid
) a1
JOIN artists_artwork a2
ON a2.nid = (
SELECT
nid
FROM artists_artwork a
WHERE a.uid = a1.uid
AND a.field_order_value = a1.field_order_value
ORDER BY
uid ASC, field_order_value ASC, nid ASC
LIMIT 1
)
ORDER BY artist;
A simple solution to this can be to create views in your database that can then be joined together. This is especially useful if you often want to see the intermediate data in the same way in some other place. While it is possible to mash together the one huge query, I just take the divide and conquer approach sometimes.