SQL Display results only if the row exists in another table - sql

Is there a way to display results only if that particular value exists, if there are multiple entries of it in another table?
For example, I am trying to display teacher name only if the type is Math. If there are no entries of Math, the column Teacher should display none.
UserName U
Email
Me
row#1.com
Wiz
bow#1.com
Classes C
Username
First
Me
Second
Me
Third
Me
Third
Wiz
Classes
Teacher T
Type
First
A
Math
Second
B
Math
Third
C
NULL
Final result as Math Classes exist for Me
UserName
Email
Teacher
Me
row#1.com
A
Me
row#1.com
B
Final result as Math Classes exist for Wiz with no math classes
UserName
Email
Teacher
Wiz
bow#1.com
None
The issue I'm running into is that my query is displaying either no entries even though user has no math but has other classes, or it's displaying Math and None at the same time.
My current query is as follows:
from User u
join classes c on c.username=u.username
join teachers t on t.classes=c.classes and type ='Math' <---- If I left join, I get 2 entries, if I join, I get 0 entries for non-math folks
where username ='Me'
So the 3 scenarios I want the query to cover:
If user does not exist in the user table (no entry)
If user exists but doesn't have any math (show user None entry)
If user exists and has math (regardless of any other type) display classes - final situation up there
Do I do some kind of select count in the case statement? This query is part of a bigger execution query.
This was SQL Server Management Studio

Would something like this solve your question?
select u.Username,
Email,
CASE WHEN types = 'MATH'
THEN teacher
ELSE 'None'
end as teacher
from users u
join class c on c.username=u.username
join teacher t on t.classes=c.classes
WHERE u.Username = 'Wiz'
db fiddle

Related

Filtering out records in SQL with a join

I am creating an app that makes guest lists for greek life events at universities.
The two tables I am working with are 'student' table and 'participant' table.
The fields in the student table are: student_id, student_name, university, and chapter.
Students with chapter id's are considered members, and students without chapter id's are considered guests when making guest lists(participant table).
The participant table fields are: participant_id, member(which is related to student_id), guest (which is also related to student_id), and event.
When trying to add guests to the guest list for an event, I wrote the following sql query to filter out students from different universities and that aren't in chapters and weren't already on the list:
$student = getColumn("SELECT guest FROM participant WHERE event = '$event'");
$university = getSqlValue("SELECT university FROM student WHERE student_id = '$member'");
$f->setOption('filter',
"SELECT student_name
FROM `student`
LEFT JOIN participant ON student.student_id = participant.guest
WHERE student.chapter = ''
AND student.university = '$university'
AND participant.guest != '$student'");
So, I know this isn't going to work, because I have a whole array for $student, but even if I try it with one student id, the query doesn't work. It returns empty. If I remove the last AND particpant.guest!= $student, then the query returns all the students at the university that are not members of a chapter.
My question has two parts:
Why wouldn't that query work with one value for student?
Can someone think of a better way to go about doing this?

SQL query join different tables based on value in a given column?

Well I am designing a domain model and data mapper system for my site. The system has different kind of user domain objects, with the base class for users with child classes for admins, mods and banned users. Every domain object uses data from a table called 'users', while the child classes have an additional table to store admin/mod/banned information. The user type is determined by a column in the table 'users' called 'userlevel', its value is 3 for admins, 2 for mods, 1 for registered users and -1 for banned users.
Now it comes a problem when I work on a members list feature for my site, since the members list is supposed to load all users from the database(with pagination, but lets not worry about this now). The issue is that I want to load the data from both the base user table and additional admin/mod/banned table. As you see, the registered users do not have additional table to store extra data, while for admin/mod/banned users the table is different. Moreover, the columns in these tables are also different.
So How am I supposed to handle this situation using SQL queries? I know I can simply just select from the base user table and then use multiple queries to load additional data if the user level is found to be a given value, but this is a bad idea since it will results in n+1 queries for n admins/mods/banned users, a very expensive trip to database. What else am I supposed to do? Please help.
If you want to query all usertypes with one query you will have to have the columns from all tables in your result-table, several of them filled with null-values.
To get them filled with data use a left-join like this:
SELECT *
FROM userdata u
LEFT OUTER JOIN admindata a
ON ( u.userid = a.userid
AND u.usertype = 3 )
LEFT OUTER JOIN moddata m
ON ( u.userid = m.userid
AND u.usertype = 2 )
LEFT OUTER JOIN banneddata b
ON ( u.userid = b.userid
AND u.usertype = -1 )
WHERE...
You could probably drop the usertype-condition, since there should only be data in one of the joined tables, but you never know...
Then your program-code will have the job to pick the correct columns based on the usertype.
P.S.: Not that select * is only for sake of simplicity, in real code better list all of the column-names...
While is totally fine having this hierarchy in your domain classes, I would suggest changing the approach in your database. Otherwise your queries are going to be very complex and slow.
You can have just another table called e.g. users_additional_info with the mix of the columns that you need for all your user types. Then you can do
SELECT * FROM users
LEFT JOIN users_additional_info ON users.id = users_additional_info.user_id
to get all the information in a single simple query. Believe me or not, this approach will save you a lots of headaches in the future when your tables start to grow or you decide to add another type of user.

Login DAO sql statement involving multiple joins

I am trying to create a query that will return through DAO whether the inputted username and password is correct. I'm using java for DAO implementation as well as JSF.
I have the following tables:
LOGIN: username (pk)
BUSINESS: username (fk), password
CUSTOMER: username (fk), password
What I'm trying to do is create multiple joins so that when a user goes to log in, their stored username defines what type of account they have. By pulling the username, the username is looked for in both the BUSINESS and CUSTOMER and when found, the password is then compared. I tried the following statement:
SELECT l.USERNAME
FROM ITKSTU.BUSINESS b
JOIN ITKSTU.LOGIN l
ON l.USERNAME=b.USERNAME
JOIN ITKSTU.CUSTOMER c
ON c.USERNAME=l.USERNAME
WHERE l.USERNAME='user111' AND (b.PASSWORD='aaa' OR c.PASSWORD='aaa');
Yet it returns nothing. Any possible suggestions?
I have replicated the same here and it looks like it is working. Could you check?
http://sqlfiddle.com/#!2/f253d/2
Thanks
If I understood correctly, what you need is to distinguish a user's type, whether he/she is in business table or customer table. Then, check the password correctness.
Then, again if I am not wrong, you should have an entry for all users in login table, then each one of them should take place EITHER in businees OR customer table.
Let's assume we have records such as:
INSERT INTO login VALUES ('TEST');
INSERT INTO login VALUES ('TEST2');
INSERT INTO business VALUES ('TEST','PASSWORD123');
INSERT INTO customer VALUES ('TEST2','PASSWORD1234');
I think you may solve the problem with the following query. Let's test with the user named "TEST2":
SELECT b.username AS business_user, c.username AS customer_user
FROM login l
LEFT JOIN business b ON b.username = l.username
LEFT JOIN customer c ON c.username = l.username
WHERE l.username = 'TEST2' AND (b.password = 'PASSWORD1234' OR c.password = 'PASSWORD1234');
This query will return 2 columns as you notice: first one will return null as the user is not in business table. The second one will give you the username and label it as "customer_user". Therefore, if you check each column and determine which one is null, then you will know where the user actually belongs to (either to business or customer table).
The trick here is to begin with login table ("FROM login") and use LEFT JOIN, instead of JOIN. Here is a quick tip about joins and their differences, if you need it: http://www.firebirdfaq.org/faq93/

How can a query return 'yes' if a matching record exists and 'no' if not? SQL / MS Access

I have the following tables:
Student Data
Student ID (primary key)
Prior Education
Student ID (foreign key)
Prior Education Code
At the moment I have a query that displays various data from Student Data with one record per student. I want to add an additional column to this query that shows "Y" if there is at least one matching record in Prior Education and "N" is there is no matching record. Basically I want an answer to the question "Does this student have any prior education?".
I want one record per student in the query regardless of how many records they have in Prior Education.
I'm working in MS Access and have little experience with SQL so solutions that don't require much SQL knowledge are preferable, but not necessary.
You may use LEFT JOIN and IIF.
SELECT student.studentid,iif (isnull(prior.priorid),'Yes','No')
FROM student LEFT JOIN [prior] ON student.studentid = prior.studentid;
EDIT:
SELECT student.studentid, iif(count(prior.priorid)<>0,'Yes','No')
FROM student LEFT JOIN [prior] ON student.studentid=prior.studentid
group by student.studentid

SQL Stored procedure

I have 3 tables:
tbl_Image from which a list of all images will be obtained
A user table from which User ID will be obtained
and an association table of Image and Member called tbl_MemberAssociation.
My work flow is that a user can upload image and this will be stored in to image table. Then all users can view this image and select one of three choice provided along with the image. If user selects an option it will be added to Association table. No user can watch same image more than once. So multiple entries will not be there.
Now I want to find the % of match by getting the list of members choose the same option and different option corresponding to all common images for which they have provided their option.
I.e. say if 3 users say A, B and C view an image of tajmahal. If A and B opted beautiful as choice and C as "Not Good ". For another image say Indian Flag A B and C opted same as Salute. Then for User A: B have 100 % match (since they selected same option both times). For A : C have 50% match one among 2 same.
So this is my scenario, in which I have to find all matched corresponding to currently logged in User.
Please help me.... I am totally disturbed with this procedure.
I have made some assumptions about the actual structure of your tables, but if I understand what you are looking for then I think this query will get the results you are wanting. You may have to make a few modifications to match your table structures.
SELECT
matches.UserName,
CAST(matches.SameRatings AS FLOAT) / CAST(ratings.UserRatingCount AS FLOAT) AS MatchPercent
FROM
tbl_User
CROSS APPLY
(
SELECT
COUNT(*) UserRatingCount
FROM
tbl_MemberAssociation
WHERE
UserId = tbl_User.UserId
) ratings
CROSS APPLY
(
SELECT
u1.UserId,
u1.UserName,
COUNT(*) AS SameRatings
FROM
tbl_MemberAssociation ma
INNER JOIN
tbl_MemberAssociation ma1
ON
ma.ImageId = ma1.ImageId
AND ma.Rating = ma1.Rating
AND ma.UserId <> ma1.UserId
INNER JOIN
tbl_User u1
ON
ma1.userId = u1.UserId
WHERE
ma.UserId = tbl_User.UserId
GROUP BY
u1.UserId,
u1.UserName
) matches
WHERE
tbl_User.UserId = #UserId
ORDER BY
MatchPercent DESC
#UserId could be passed as an input to the stored procedure.
The 1st CROSS APPLY "ratings" is getting a count of for the total number of ratings for the logged in user.
The 2nd CROSS APPLY "matches" is getting a count of the number of like ratings for the other users in the database.
The result set uses the counts calculated by the two CROSS APPLY queries to compute the match percentage between the logged in user and the other users who have rated the same images as the logged in user.