Relating the values one table to another table - mysql

I have two tables. One is named usertbl with columns user_id, user_name, and acct_status. possible values for acct_status values are 0, 1, 2, 3. Another table named accountstatustbl has the following columns - acct_status, and acct_status_desc, with values when acct_status = 0, acct_status_desc = enrolled, 1 = active, 2 = inactive, and 3 = deactivated. Now, how should I query my db to provide me the following output:
user_id user_name status
0000000 user1 enrolled
1234567 user2 active
9999999 user3 deactived
instead of giving me values 0, 1, and 3?

You can try this.
SELECT user.user_id, user.user_name, status.description
FROM usertbl user left outer join accountstatustbl status
on user.acct_status=status.acct_status

SELECT u.user_id, u.username, s.acct_status_desc status
FROM usertbl u, accountstatustbl s
WHERE u.acct_status = s.acct_status
Hope I helped.

you can use INNER JOIN assuming that acct_status in usertbl has no NULL values:
SELECT a.user_id,
a.user_name,
b.status_desc AS status
FROM usertbl a
INNER JOIN accountstatustbl b
ON b.acct_status = a.acct_status
you can also read about MySQL JOIN Syntax to understand more about joins

Related

How to select distinct rows when using joint table

I have two tables named chatMaster and chatMessages , i was trying to left join the two tables to get all data from master and latest message for each chat. I am using this query to join the two tables
SELECT c.id, c.p1, c.p2, m.toP, m.message, m.createdOn FROM chatMaster c
left join chatMessages m on c.id = m.id group by m.id ;
This query is for selecting only one row for each entry in chatMaster, but it is selecting the first message for every entry like,
1, 2018-11-24 00:40:08, HI!, 99e22056-ee7f-11e8-bc28-8acac6f59ef9, 1001
2, 2018-11-24 00:40:21, HI! There, 99e22056-ee7f-11e8-bc28-8acac6f59ef9, 1
3, 2018-11-24 01:33:12, HI!, e3345a17-ee7f-11e8-bc28-8acac6f59ef9, 2
this is the result of select * from chatMessages, There are two entries for chat id 99e22056-ee7f-11e8-bc28-8acac6f59ef9 and i want the send one which is send on 2018-11-24 00:40:21 but the result of my join query is
99e22056-ee7f-11e8-bc28-8acac6f59ef9, 1001, 1, 1001, HI!, 2018-11-24 00:40:08
e3345a17-ee7f-11e8-bc28-8acac6f59ef9, 2, 10001, 2, HI!, 2018-11-24 01:33:12
It is selecting the first message. How to select the latest message? What changes should i make to get the latest message from chatMessages instead of first message. please ask if you need more details
In a Derived Table, you can get the maximum values of createdOn (latest createdOn) for every chat-master id. You can then join this result-set to the main table, to get only the row corresponding to latest createdOn.
SELECT c.id, c.p1, c.p2, m.toP, m.message, m.createdOn
FROM chatMaster c
LEFT JOIN
( SELECT id, MAX(createdOn) AS latest_createdOn
FROM chatMessages
GROUP BY id
) AS dt
ON dt.id = c.id
LEFT JOIN chatMessages m
ON m.id = c.id AND
m.createdOn = dt.latest_createdOn

WHERE (set) IN (set)

EDIT: I seemed to have asked this question incorrectly.
I'm trying to find a way to query if a set is available in another set. For example:
SELECT * FROM something
WHERE (1, 3) IN (1, 2, 3, 4, 5)
In this case, 1 & 3 are in the set (1, 2, 3, 4, 5). Another example:
SELECT * FROM something
WHERE (1, 3) IN (1, 5, 7, 9);
In this case, 1 & 3 ARE NOT in the set (1, 5, 7, 9) so nothing should be pulled from the table.
NOTE: This answers the original question, which seems to have nothing to do with the question after OP modifications.
You can get the users who completed all three levels by using:
SELECT cl.user_id
FROM completed_levels cl
WHERE cl.id IN (3, 5, 7)
GROUP BY cl.user_id
HAVING COUNT(DISTINCT cl.id) = 3;
(Note: DISTINCT is not necessary if the ids for a given user are unique.)
THEN, you can get what you want using a JOIN or similar construct:
SELECT u.*
FROM users u JOIN
(SELECT cl.user_id
FROM completed_levels cl
WHERE cl.id IN (3, 5, 7)
GROUP BY cl.user_id
HAVING COUNT(DISTINCT cl.id) = 3
) cu
ON cl.user_id = u.id;
NEW REQUEST (according to sqlfiddle.com/#!9/f36d92/2):
# The goal is to write a query that will select all exercises
# that the user has the correct equipment for, where the pre-defined
# set is the id's of the equipment the user has.
# For example, let's assume the user has equipment (1, 4)
# The exercise "Curls" should be pulled from the table, as the user has all
# of the required equipment based on the exercise_requirements table.
# while "Wrecking Ball" is not returned as the user only has a portion of the
# required equipment.
# If the user's equipment was (1, 3, 4) then both "Curls" and "Wrecking ball"
# would be returned from the exercises table, as the user has the required equipment
# for both exercises.
#----
#Below is my take on your query.
SELECT ex.* FROM exercises ex
WHERE ex.id IN (
SELECT exercise_id FROM exercise_requirements
WHERE ex.id IN (1, 4)
GROUP BY exercise_id
HAVING COUNT(distinct exercise_id) = 3
);
SOLUTION:
You are confusing some IDs here. This would be closer:
SELECT ex.* FROM exercises ex
WHERE ex.id IN (
SELECT exercise_id FROM exercise_requirements
WHERE equipment_id IN (1, 4)
GROUP BY exercise_id
HAVING COUNT(distinct equipment_id) = 2
);
But still this query is vice versa. We don't want to know whether all the user's equipment are found in a set of equipment needed for an exercise, but whether the whole set of equipment needed for an exercise is found in the user's equipment.
Probably the easiest way to write this is: aggregate exercise_requirements per exercise_id and check that no equipment_id is needed that the user doesn't have.
select *
from exercises
where id in
(
select exercise_id
from exercise_requirements
group by exercise_id
having sum(equipment_id not in (1, 4)) = 0
);
Your updated fiddle: http://sqlfiddle.com/#!9/f36d92/5
You are using the IN clause with a correlated subquery (i.e. the subquery references u.id). This is not how we use it. The IN clause is great for non-correlated subqueries; if you need a correlated subquery, use EXISTS instead. For your problem a non-correlated subquery suffices, so use IN accordingly:
select *
from users
where u.id in (select user_id from completed_levels where id in (1, 5, 7);
If a user must have all levels:
select *
from users
where u.id in (select user_id from completed_levels where id = 1
and u.id in (select user_id from completed_levels where id = 5
and u.id in (select user_id from completed_levels where id = 7;
Such problems are usually better solved with an aggregation so as not to have to query the same table again and again:
select *
from users
where u.id in
(
select user_id
from completed_levels where id in (1, 5, 7)
group by user_id
having count(distinct id) = 3
);
You could use this
SELECT u.*
FROM users u
INNER JOIN completed_levels cl
ON cl.user_id = u.id
WHERE cl.id IN (1, 5, 7);
Or using EXISTS as link from #DanFromGermany
You can use Case to make a Sum which will increase with 1 for each level within 1, 5 & 7.
SELECT A.* FROM users AS
INNER JOIN
(
SELECT U.id,
SUM(CASE WHEN
(
A.completed_levels = 1
OR A.completed_levels = 5
OR A.completed_levels = 7
) THEN 1 ELSE 0 END
) AS RN
FROM completed_levels A
INNER JOIN users U ON A.user_id = U.id
GROUP BY U.id
) B ON A.id = B.id
WHERE B.RN = 3 -- Those users have completed level 1, 5 & 7 will have RN = 3 only

mysql SELECT EXISTS on multiple tables

Have tables: person,person_ip
Both tables have pid column as a primary key, in table person there is column state_id, in table person_ip there is column ip.
Want to discover if specified IP address is assigned to person with state_id is not equal to 2. But always got result 1, even if state_id is 0, 1 or 2. Always got 0 only if ip address is not listed at all. What am I doing wrong?
SELECT EXISTS (
SELECT person_ip.PID
FROM person_ip,person
WHERE person.PID=person_ip.PID
AND person.state_id NOT IN (2)
AND person_ip.ip='10.11.12.13'
)
this seems like a simple join.. unless i'm missing something
select person.*
from person
inner join person_ip
on person.pid = person_ip.pid
where person.state_id <> 2
and person_ip.ip_address = '10.0.0.1'
If you want to exclude the ip_address if it has been assigned to any user with state = 2, even if it has also been assigned to a user without state = 2, then try:
select max(i)
from (
select *
from (
select 1 as i
from dual
where not exists (
select 1
from person p
inner join person_ip pi
on p.pid = pi.pid
where p.state_id = 2
and pi.ip_address = '10.0.0.1'
)
) q
union
select 0
) qq
(dual is a system table that can be used as a sort of stub table)
here's a fiddle showing both versions
update after some actual sleep
Okay, so the above query is a little.. out there. Back in the real world, this one is probably more appropriate:
select count(case when p1.state_id = 2 then 1 end)
from person p1
inner join person_ip pi1
on p1.pid = pi1.pid
where pi1.ip_address = '10.0.0.1'
group by pi1.ip_address;
This will return 1 or more if your ip_address has been used by someone with a state_id of 2, and 0 if it has never been used by someone with a state_id of 2.
It will return nothing if the ip has never been used.
this fiddle has all three of the above queries.
SELECT IF(COUNT(*)>0,1,0)
FROM person
INNER JOIN person_ip
ON person.pid = person_ip.pid
AND person_ip.ip_address = '10.0.0.1'
WHERE person.state_id <> 2

My SQL query showing error : : #1242 - Subquery returns more than 1 row

I have a problem regarding mysql.
I have few tables like tbl_follow, tbl_user, tbl_post_like,
Now what I want is that my query should return the result like:
i want userid, username, user image, user state from one table->tbl_user,
then i want those users who are following other friend(other user) only if the column "estatus" in table "tbl_follow" contain value as "Active" otherwise if there is an "inactive" value then it should return 0 as i have coded in query.
tbl_follow : 1.iFollowID, 2.iUserID, 3. iFriendID, 4. eStatus
tbl_post_like: 1. iPostLikeID, 2. iUserID, 3. iPostID
tbl_user: 1.iUserID, 2. vUsername, 3. vImage, 4. vState
Now the simple query I am using is:
SELECT u.iUserID,
u.vUsername,
u.vState,
u.vImage,
(SELECT IF(
(SELECT iFollowID
FROM tbl_follow
WHERE iUserID =249
AND iFriendID = 250
AND eStatus = 'Active')!='', 1,0)
FROM tbl_follow) AS is_follow
FROM tbl_user u
INNER JOIN tbl_post_like l ON u.iUserID=l.iUserID
WHERE l.iPostID=21
Not sure about performance on this in comparison to using an additional join, but hopefully it'll work:
Try:
SELECT u.iUserID,
u.vUsername,
u.vState,
u.vImage,
IF(EXISTS
(SELECT iFollowID
FROM tbl_follow
WHERE iUserID =249
AND iFriendID = 250
AND eStatus = 'Active'), 1,0) AS is_follow
FROM tbl_user u
INNER JOIN tbl_post_like l ON u.iUserID=l.iUserID
WHERE l.iPostID=21

Many to many relation filter

I have the following tables:
user (id, firstname, lastname)
follow (id, follower_id, following_id)
Now imagine we have users with id 1, 2, 3, 4, 5
And user_id = 1 already following user 2 and 3.
Now I want to write a query that gives me the user_id's that I (user_id = 1) am not following which are (4 and 5).
Can someone please help.
This should do it:
SELECT id FROM user
WHERE
id NOT IN
(
SELECT following_id
WHERE follower_id = 1 --(or you can use any user i, i used 1 to show an example)
)
SELECT * FROM user_table
LEFT JOIN follow_table ON user_table.id = follow_table.following_id
WHERE follow_table.following_id IS NULL
Try this:
SELECT * FROM user_table ut
LEFT JOIN follow_table ft ON ut.id = ft.following_id AND ft.follower_id = 1
WHERE ft.following_id IS NULL