Join table and Case sql - mysql

I have a problem in my SQL Select , for example we have two users X and Y , user X want to see user Y Following so , when see his following ,
user Y want to know who users in user X (following) follow them
in this picture : https://i.imgsafe.org/d2b2d83886.png user with id :68 want to see users.id = 50 Following
SELECT users.id,users.username,
CASE WHEN follows.user_id = 68 THEN 1 END AS is_Follow
FROM users
LEFT JOIN follows
ON follows.follower_id = users.id
WHERE follows.app = 1 AND follows.user_id = 50
but this return me NULL :( what should i do ?!

Conditions on the right table of a LEFT JOIN should be on the ON clause and not on the WHERE clause :
SELECT users.id,users.username,
CASE WHEN follows.user_id = 68 THEN 1 ELSE -1 END AS is_Follow --Minus one value means NO.
FROM users
LEFT JOIN follows
ON follows.follower_id = users.id AND
follows.app = 1 AND
Another thing, what exactly are you checking? How many people follow user_id=68 ? Because by the name of the column it doesn't sounds like it.
EDIT: Try this:
SELECT users.id,users.username,
MAX(CASE WHEN follows.user_id = 68 THEN 1 ELSE -1 END) AS is_Follow --Minus one value means NO.
FROM users
LEFT JOIN follows
ON follows.follower_id = users.id AND
follows.app = 1 AND
GROUP BY users.id,users.username

Related

How to use IF statement before FROM Clause

I have three tables:
Users and companies can add feeds. The flag columns means
0 = user
1 = company
How can I perform this SQL query correctly? Thanks in advance for your help!
SELECT
feeds.feeds_id,
feeds.title
IF feeds.flag = 0
FROM user
INNER JOIN
feeds.user_or_company = user.user_id
ELSEif feeds.flag = 1
INNER JOIN
feeds.user_or_company = company.company_id
One way to solve this is to LEFT JOIN to both user and company tables and then select the appropriate name value based on feeds.flag:
SELECT f.feeds_id, f.title,
CASE f.flag WHEN 0 THEN u.name ELSE c.name END AS name
FROM feeds f
LEFT JOIN user u ON u.user_id = f.user_or_company
LEFT JOIN company c ON c.company_id = f.user_or_company
Output (for your sample data)
feeds_id title name
2 This title added twice by user User-1
3 This title added by company Company-2
1 This title added by user User-3
Demo on dbfiddle

compare colums of two table if table1.row > table2.row

TABLE1
mybb_users
(id gcoins)
1 150
2 10
TABLE2
servercoins
(id prezzo)
1 150
2 70
I should compare this table for control if users have enough "gcoins" for buy "prezzo". If "gcoins" > "prezzo" it's ok but "gcoins" < "prezzo" print an alert with "You don't have enough gocins for this"
Try this...
SELECT
CASE WHEN ((SELECT gcoins
FROM TABLA1
WHERE TABLA1.id = <ID_USER>
AND gcoins >0) < ( SELECT prezzo
FROM TABLA2
WHERE TABLA2.id = <ID_PREZZO>))
THEN 'You dont have enough gocins for this'
ELSE 'something else...'
END
<ID_USER> and <ID_PREZZO> replace with your variables.
HERE you can test!
Hope this help!
This is a general query that will print out the status:
SELECT u.id, u.gcoins, s.prezzo,
CASE WHEN u.gcoins >= s.prezzo THEN 'OK' else 'Not Enough gcoins' END AS Status
FROM mybb_users u
INNER JOIN servercoins s ON u.id = s.id
If you want a query that just returns the rows that need the alert, then remove the second line, and add a WHERE clause instead:
SELECT u.id, u.gcoins, s.prezzo
FROM mybb_users u
INNER JOIN servercoins s ON u.id = s.id
WHERE u.gcoins < s.prezzo
This gives you a list of those who need to be warned that they don't have enough gcoins.

Substitute 2 IDs by Name in SQL

I have 2 tables that looks like the below:
Table 1
Table 2
What Im trying to do, is I want to substitute the change_builder ID from table 1 by the first and last name from table 2. In addition, I want to do the same for the change_manager_ID in table 2 (Substitute it by the first and last name from table 2)
My query looks like the below:
SELECT a.change_number, a.title, change_manager_id,change_builder_id, concat(users.first_name,' ', users.last_name) as Manager_Name, concat(users.first_name,' ', users.last_name) as Builder_Name,
(CASE
WHEN a.change_state_id = '128' THEN 'In Progress'
WHEN a.change_state_id = '127' THEN 'Approved'
WHEN a.change_state_id = '125' THEN 'Pending'
WHEN a.change_state_id = '124' THEN 'Requested'
END) AS Change_State
FROM change_item as a
LEFT JOIN users
ON a.change_manager_id = users.id
WHERE a.change_state_id = 128
OR a.change_state_id = 124
OR a.change_state_id = 125
OR a.change_state_id = 127
The output of this is changing the first and last name of the manager w.r.t the ID but I want to do the same for the builder as well.
I'm stuck, any help or hint would be really appreciated.
Seems you have forgotten that you can join a table twice to the same other table - each join depicting a different relationship.
Good practice requires you to give each join clause a good correlation name to describe the role of the relationship.
And, please, use the right literals for the right types.
Not once change_state_id = '128' (string) and then change_state_id = 124 (number). Implicit conversions are slow and can impact the data quality.
And I used an IN () clause instead of a bunch of OR-s:
SELECT
a.change_number
,a.title
,change_manager_id
,change_builder_id
,CONCAT (mgr.first_name,' ',mgr.last_name) AS Manager_Name
,CONCAT (bld.first_name,' ',bld.last_name) AS Builder_Name
,CASE
WHEN a.change_state_id = 128 THEN 'In Progress'
WHEN a.change_state_id = 127 THEN 'Approved'
WHEN a.change_state_id = 125 THEN 'Pending'
WHEN a.change_state_id = 124 THEN 'Requested'
END AS Change_State
FROM change_item AS a
LEFT JOIN users AS mgr -- join as manager
ON a.change_manager_id = mgr.id
LEFT JOIN users AS bld -- join as builder
ON a.change_builder_id = bld.id
WHERE a.change_state_id IN(128,124,125,127)
;

Mysql Return true if idx exists in another table

I'm trying to write a query that returns true if the same idx exists in another table.
Here is what I want to do.
Two Tables:
User (user_idx, name)
Group (group_idx, user_idx)
Pseudo Query:
SELECT user_idx, name, (True(1)/False(0) value) as has_joined_group
FROM User
WHERE (Check if user_idx exists in Group table where group_idx is 3)
Can this be done using Mysql? If yes, how?
SELECT u.user_idx, u.name, g.user_idx IS NOT NULL AS has_joined_group
FROM User AS u
LEFT JOIN Group AS g
ON g.user_idx = u.user_idx AND g.group_idx = 3
SELECT
u.user_idx,
u.name,
CASE WHEN g.user_idx IS NOT NULL AND g.group_idx = 3 THEN 1 ELSE 0 END AS has_joined_group
FROM
user u JOIN LEFT group g ON u.user_idx = g.user_idx
SELECT u.user_idx, u.name, if(g.user_idx IS NOT NULL,'true','false') as has_joined_group
FROM User AS u
LEFT JOIN Group AS g
ON g.user_idx = u.user_idx AND g.group_idx = 3

Join multiple tables, keeping NULLs

I have 4 tables user, posts, follows, notifications. The posts table has a field called privacy in which a value of 1 means "anyone can see" and 2 means "only friends can see".
My notifications table looks like this:
id user_id tonotify_id notification post_id
1 2 3 --- 1
2 3 2 --- 2
3 2 4 --- 3
And my follows table looks like this:
id user_id tofollow_id status fstatus
1 1 2 1 1
2 1 3 1 1
The field fstatus value of 1 means that they are also friends.
Now I am trying to get all notifications sent out by people who a certain user is following (lets say a user with id 1). Assuming 1 is following user 2 and 3, I need to get all notifications from the above table. However, before this I need to make sure that the post (posted by the users in the tonotify_id column) is available. That is, I need to check the privacy setting. I have the following code:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)
ORDER BY n.id DESC
It seems to be working except for one glitch. Since user 1 is not following user 4 all notifications aimed at 4, even if the posts are public don't show up. This my guess has to do with JOIN follows fr ON (n.tonotify_id = fr.tofollow_id) because, since the user 1 hasn't followed 4, there are no rows matching this join. Any suggestions to solving this?
I did try [the outer join], but the output is the same.
When you use an outer join, and then use one of the "outer" columns in an equality check in the WHERE clause, you convert your outer join to an inner join. This is because your condition that checks post's privacy requires the post to be there:
AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)
When an outer join is about to produce a row that corresponds to a notification without a post, it would check the above condition. Since the post is not there, p.privacy would evaluate to NULL, "contaminating" both sides of the OR, and eventually making the whole condition evaluate to false.
Moving this condition into the ON condition of the join will fix the problem:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
AND (p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1))
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
ORDER BY n.id DESC
Another way to fix this would be adding an IS NULL condition to your OR, like this:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
AND (p.privacy IS NULL OR p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1))
ORDER BY n.id DESC
You need to use an outer join such as LEFT JOIN instead of an inner join using just JOIN. An outer join will always return rows from one "side" (which is why it is called LEFT [OUTER] JOIN and RIGHT [OUTER] JOIN) even if the other "side" does not match anything.