I have one table to store users and one table to store member fee payments:
Users
Id (int)
Name (string)
MemberFeePayments
Id (int)
User (int)
Year (int)
The "User" column in MemberFeePayment is a reference (foreign key) to the user that have payed the fee. The "Year" column tells which year the user have payed the fee for. If a user has been a member for several years, there will be multiple rows for the user in the MemberFeePayments table.
Now I would like to write an sql query that fetches ALL users. The resulting table should have a column that tells if the users are members in a specific year (which will be provided to the query):
Result
Id (int)
Name (string)
IsMember (bool)
What is a good way to accomplish this?
I'm using MySql (5.6).
This should work if there is only one Fee Payment record per year:
SELECT
U.Id, U.Name,
CASE WHEN M.ID IS NULL THEN 0 ELSE 1 END AS `IsMember`
FROM Users U
LEFT JOIN MemberFeePayments M ON (U.Id = M.User AND M.Year = 2013)
This will work if you have multiple payments in year:
SELECT
U.Id, U.Name,
CASE WHEN COUNT(M.ID) > 0 THEN 1 ELSE 0 END AS `IsMember`
FROM Users U
LEFT JOIN MemberFeePayments M ON (U.Id = M.User AND M.Year = 2013)
GROUP BY U.Id, U.Name;
Here's a link to a demo
Try this:
SELECT a.Id,a.Name,if(b.id>0,TRUE,FALSE) as ismember FROM USERS a LEFT JOIN MemberFeepayments b ON a.id=b.id
check column fields and table name
Here is a way you can do it. So it will lit all the users no matter they are in the MemberFeePayments table or not and will show Yes if they are member for a particular year else No.
select
x.Id,
x.Name,
case when x.member is not null then 'Yes' else 'No' end as IsMember
from
(
select
u.Id,
u.Name,
m.User as member
from Users u
left join MemberFeePayments m on m.User = u.Id AND m.year = 2014
)x
OR simply as below without doing the outer select from derived table.
select
u.Id,
u.Name,
case when m.User IS NOT NULL THEN 'Yes' else 'No' end as IsMember
from Users u
left join MemberFeePayments m on m.User = u.Id AND m.year = 2014
DEMO
Use left join
SELECT t1.id,t1.Name,t2.id
FROM Users t1
LEFT JOIN MemberFeePayments t2 ON t1.id = t2.user and t2.year = 2014
t2.id will be null if there are no data in MemberFeePayments for that user and year
Related
I have multiple tables of roles (e.g. student, guest, teacher) and a table of users with their id's.
I want to make a SQL view which has the userId and Role ("student", "teacher" ...) as a string.
The roles tables each have a foreign userId but don't have the role as text string. So there should be some kind of comparator, if the user has an id in student then its role is "student".
How would you start writing this ?
Assuming that each of the role tables has 0 or 1 records per user, you could use a series of left joins:
SELECT
u.id,
CASE
WHEN s.id IS NOT NULL THEN 'student'
WHEN g.id IS NOT NULL THEN 'guest'
WHEN t.id IS NOT NULL THEN 'teacher'
ELSE 'unknown'
END role
FROM users u
LEFT JOIN students s ON s.id = u.id
LEFT JOIN guests g ON g.id = u.id
LEFT JOIN teacher t ON t.id = u.id
If a user may have more than one role, you could split the information over several boolean columns:
SELECT
u.id,
CASE
s.id IS NOT NULL is_teacher,
g.id IS NOT NULL is_guest,
t.id IS NOT NULL then is_teaacher
FROM users u
LEFT JOIN students s ON s.id = u.id
LEFT JOIN guests g ON g.id = s.id
LEFT JOIN teacher t ON t.id = t.id
Is this what you want?
SELECT u.*,
(CASE WHEN EXISTS (SELECT 1 FROM students s WHERE s.user_id = u.user_id)
THEN 'student'
WHEN EXISTS (SELECT 1 FROM guests g WHERE g.user_id = u.user_id)
THEN 'guest'
WHEN EXISTS (SELECT 1 FROM teachers t WHERE t.user_id = u.user_id)
THEN 'teacher'
ELSE '???'
END) AS role
FROM users u;
This assumes that each user has only one role. This can be modified (using concat()) to handle multiple roles.
I wanna count all the orders a user has and all the complete orders a user has. I came with this but it´s not working
select
count(a.id) as total,
count(b.id) as complete
from
user
join
orders a on user.id = a.user_id
join
orders b on user.id = b.user_id
where
a.id = 1
and
(b.id = 1 and b.complete = 'yes');
Any idea?
you could sum the order with yes and count the distinct id group by user
select user.id, sum(if(a.complete ='yes',1,0)), count(distinct a.id)
from user
INNER join orders a on user.id = a.user_id
group by user.id
I believe you are searching for grouping (MySQL GROUP BY) by the differents users, and then count all the orders related to each user plus the completed ones. For this approach, you will need to:
(1) Join users with they orders.
(2) Use GROUP BY clause on user.id column.
(3) Count all orders related to each user with COUNT()
(4) Sum all orders related to each user having some specific condition with SUM(CASE WHEN <specific_condition> THEN 1 ELSE 0 END).
In summary, a query like next one should work:
SELECT
u.id,
COUNT(o.id) AS total_orders,
SUM(CASE WHEN o.complete = "yes" THEN 1 ELSE 0 END) AS complete_orders
FROM
user AS u
INNER JOIN
orders AS o ON o.user_id = u.id
GROUP BY
u.id
I am trying to do a search functionalities that involves three tables.
Searching for users and returning wheather the user id 1 is a friend of the returned users. Also The returned users is being filtered from a third table where it checks tag of that users.
So I can say, "Return users who has tag 'Programming', 'Php'
in userinterests table and also if the returned user is a friend of usr id 1 or not "
I am trying to use the bellow query but getting Column 'id' in IN/ALL/ANY subquery is ambiguous
If I remove the left join then it works.
SELECT n.id, n.firstName, n.lastName, t.id, t.tag, t.user_id, if(id in (
SELECT u.id as id from friends f, users u
WHERE CASE
WHEN f.following_id=1
THEN f.follower_id = u.id
WHEN f.follower_id=1
THEN f.following_id = u.id
END
AND
f.status= 2
), "Yes", "No") as isFriend
FROM users n
LEFT JOIN userinterests t on n.id = t.id
WHERE t.tag in ('Programming', 'Php')
Thank you for your time :)
Qualify all your column names. You seem to know this, because all other column names are qualified.
I'm not sure if your logic is correct, but you can fix the error by qualifying the column name:
SELECT . . .
(CASE WHEN n.id IN (SELECT u.id as id
FROM friends f CROSS JOIN
users u
WHERE CASE WHEN f.following_id=1
THEN f.follower_id = u.id
WHEN f.follower_id=1
THEN f.following_id = u.id
END
) AND
f.status= 2
THEN 'Yes' ELSE 'No'
END) as isFriend
. . .
This is the way I will go for your approach:
1) I used INNER JOIN instead of LEFT JOIN for skip users that are not related to tags: Programming and Php.
2) I replaced the logic to find the set of friends related to user with id equal to 1.
SELECT
n.id,
n.firstName,
n.lastName,
t.id,
t.tag,
t.user_id,
IF(
n.id IN (SELECT follower_id FROM friends WHERE status = 2 AND following_id = 1
UNION
SELECT following_id FROM friends WHERE status = 2 AND follower_id = 1),
"Yes",
"No"
) AS isFriend
FROM
users n
INNER JOIN
userinterests t ON n.id = t.id AND t.tag IN ('Programming', 'Php')
Just curious, whats is the meaning of status = 2 ?
I have created database with following tables.
booking (id, user_id, user_table, date);
user (id, fname, lname);
tmp_user (id, fname, lname);
The user_id of booking table refer both user table id and tmp_user table id. I use user_table column for keep user table type.
I want to write a query to get booking details with user details. So i should check user_table column value before join user table.
Is it possible? How can i do that?
You can do a query of this type by joining both in and then using precedence:
select b.*,
(case when u.id is not null then u.fname else tu.fname end) as fname,
(case when u.id is not null then u.lname else tu.lname end) as lname
from booking b left outer join
user u
on b.user_id = u.id left outer join
tmp_user tu
on b.user_id = tu.id
You can also add in the condition and u.uid is null to the second join. I don't know if that would help or hinder performance.
Oh, if you want the user table value, then that is just a small modification to the logic:
select b.*,
(case when b.user_table = 'user' then u.fname else tu.fname end) as fname,
(case when b.user_table = 'tmp_user' then u.lname else tu.lname end) as lname
from booking b left outer join
user u
on b.user_id = u.id left outer join
tmp_user tu
on b.user_id = tu.id;
Hi, I have these two tables: users and friends (friend_status = 1 means the request is sent, friend_status = 2 means they are friends). Now I want to select all users are not friend of a specific user. How to do?
Assuming the current user is 1. I tried this SQL. It works but it's too long and slow. The first selects all users sent request to user1 but not accepted. The second selects all users receive request from user1. The third and the fourth selects all users is not in "friends" table.
SELECT user_id, name, email
FROM
(
SELECT user_id, name, email
FROM users u INNER JOIN friends f ON u.user_id = f.sender
WHERE f.receiver = 1 AND friend_status <> 2
UNION
SELECT user_id, name, email
FROM users u INNER JOIN friends f ON u.user_id = f.receiver
WHERE f.sender = 1 AND friend_status <> 2
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.sender
WHERE f.receiver IS NULL
GROUP BY user_id
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.receiver
WHERE f.sender IS NULL
GROUP BY user_id
) T
GROUP BY user_id
Update: Add a pic.
SELECT
a.user_id,
a.name,
a.email,
b.status IS NOT NULL AS friend_status
FROM
users a
LEFT JOIN
friends b ON
a.user_id IN (b.sender, b.receiver) AND
1 IN (b.sender, b.receiver)
WHERE
(b.friend_id IS NULL OR b.status <> 2) AND
a.user_id <> 1
You had asked a question previously here - "Select users who aren't friends with anyone", and I provided an answer which utilized a LEFT JOIN.
Building off of that, to select users who aren't friends with a specific user, we just simply need to add that specific user's ID to the LEFT JOIN condition (1 IN (b.sender, b.receiver).
Minor Edit: Unless the user can friend him/herself, it wouldn't make sense to also select the user who we're selecting against!! So I added WHERE a.user_id <> 1.
Assuming you want to perform the query on user_id 1:
SELECT user_id, name, email
FROM users AS u
WHERE NOT EXISTS (SELECT * FROM friends AS f
WHERE (f.sender = u.user_id AND f.receiver = 1 AND f.friend_status = 2)
OR (f.sender = 1 AND f.receiver = u.user_id AND f.friend_status = 2)
)
AND u.user_id <> 1
The subquery fetches all the established friendship relationship in which user 1 is either the sender or the receiver. The outer query selects all users for which no such relationship exists. The user with ID 1 is excluded from the query using the last line, as, even if he cannot be friend with himself, I suppose that he should not appear in the final query result.
You may be able to simplify this by using something like this:
SELECT user_id, name, email
FROM
(
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.sender
WHERE IFNULL(friend_status,0) <> 2
GROUP BY user_id
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.receiver
WHERE IFNULL(friend_status,0) <> 2
GROUP BY user_id
) T
GROUP BY user_id
The IFNULL function returns the value of the first parameter, replacing NULLs with the value of the value second parameter. In this case it means that friend_status will be treated as 0 if there is no matching friend in the friends table, which allows you to reduce the number of selects in the UNION by half.
Try this query
select
u.user_id,
u.name,
u.email,
ifnull(f.friend_status,0) as Relation
from users as u
left join friends as f
on f.sender = u.user_id
where u.user_id not in(select
sender
from friends
where sender = 1)
Here sender = 1 means the user id = 1. You can pass user id to restrict this condition. Also status 0 means he is not friend. and 1 , 2 , 3 are according to your rules