Selecting across multiple tables with UNION - mysql

I reworked my database from one user table to multiple user tables (divided per role): tblStudents, tblTeachers, tblAdmin
When logging in, I didn't want to run three queries to check if the user exists somewhere in my DB. So what I did was put together the following query with union
select s.id as id, s.email as email, s.password as password, s.role as role from tblStudents s
union
select a.id as id, a.email as email, a.password as password, a.role as role from tblAdmin a
union
select t.id as id, t.email as email, t.password as password, t.role as role from tblTeachers t
This selects the fields that are the same across all tables and outputs the results nicely for me.
So, I decided to try this and for some reason, my login form wouldn't work. For my login form, I added a where clause which checks for the email address. I ran the query in my database app and surprisingly, when I do for example where email = "admin#admin.be" (this email exists in my database tblAdmin), it also selects a record from my students table.
With the where clause:
select s.id as id, s.email as email, s.password as password, s.role as role from tblStudents s
union
select a.id as id, a.email as email, a.password as password, a.role as role from tblAdmin a
union
select t.id as id, t.email as email, t.password as password, t.role as role from tblTeachers t
where email = "admin#admin.be"
The records both have id = 1 but I don't understand why it would select the student record when I'm filtering on the admin email address. Why is this? Can someone explain and provide me with a better solution to this problem? I basically have one login form and need to select across multiple tables to check if the user exists in my db.

Thanks for updating the query; now we can see that the WHERE condition is only applied to the last UNIONed query. You need to either add that WHERE clause to each query, or wrap it as a subselect and apply the WHERE clause to that.
select s.id as id, s.email as email, s.password as password, s.role as role from tblStudents s
where email = "admin#admin.be"
union
select a.id as id, a.email as email, a.password as password, a.role as role from tblAdmin a
where email = "admin#admin.be"
union
select t.id as id, t.email as email, t.password as password, t.role as role from tblTeachers t
where email = "admin#admin.be"
or
SELECT * FROM (
select s.id as id, s.email as email, s.password as password, s.role as role from tblStudents s
union
select a.id as id, a.email as email, a.password as password, a.role as role from tblAdmin a
union
select t.id as id, t.email as email, t.password as password, t.role as role from tblTeachers t
) foo where email = "admin#admin.be"

SELECT
R.co_C,
company3.Statuss
FROM
(
SELECT
company1.co_C
FROM
company1
UNION ALL
SELECT
company2.co_C
FROM
company2
) AS R
LEFT JOIN company3 ON R.co_C = company3.co_A;

Related

Eliminate the duplicate rows from the table in SQL

I want to eliminate the duplicate rows based on email from the table and retrieve all the rows without duplicates.
I have tried using distinct but I'm not getting desired results.
SELECT
DISTINCT Email
FROM
Users
Example Table:
Id
Email
Username
1
sam#gmail.com
sam1122
2
john#gmail.com
john1122
3
sam#gmail.com
sam2233
4
lily#gmail.com
lily#as
What I want to retrieve:
Id
Email
Username
1
john#gmail.com
john1122
2
lily#gmail.com
lily#as
We can try using exists logic here:
SELECT Id, Email, Username
FROM Users u1
WHERE NOT EXISTS (
SELECT 1
FROM Users u2
WHERE u2.Email = u1.Email AND
u2.Id <> u1.Id
);
You can do it using left join :
select u.*
from Users u
left join (
select email, max(id) as Id
from Users
group by email
having count(1) > 1
) as s on s.email = u.email
where s.email is null;
Demo here
Yet another option, if you are using MySQL 8 -
SELECT Id, Email, Username
FROM (
SELECT *, COUNT(*) OVER (PARTITION BY Email) AS cnt
FROM Users
) t
WHERE t.cnt = 1;
SELECT Id, Email, Username
FROM Users
WHERE Email IN (
SELECT Email
FROM Users
GROUP BY Email
HAVING COUNT(*) = 1
)
SELECT id,
Email,
Username,
count(*) AS duplicate_email_count
FROM Users
GROUP BY Email
HAVING duplicate_email_count=1

How can i determine if a user is in first table or in second table

Hy!
I have 2 tables in my database. The one is Teachers and other is Students. if a user tries to log in then, How can i determine weather this user is in Teachers table or in Students table
i tried this but it is't working.!
SELECT *
FROM `Teachers` , `Students`
WHERE Students.username='user's name'
AND Teachers.username='user's name'
What about this?
SELECT type FROM
(SELECT *
FROM (SELECT username, 'student' as type FROM Students) t1
UNION (SELECT username, 'teacher' as type FROM Teachers)
) as subquery WHERE username = 'Student name'

SQL Query with COUNT, Having Count >1, display full details of duplicates

I have a table like :
name employment_Status email
---- ---- -----
David E David#email.com
John U John#email.com
Michael E Michael#email.com
Steve E Michael#email.com
James U David#email.com
Mary U Mary#email.com
Beth E Beth#email.com
I started by selecting email and count(email):
SELECT email, COUNT(email) AS emailCount
FROM Table
GROUP BY email
HAVING ( COUNT(email) > 1 );
The problem occurred when I tried to include name as well:
SELECT name, email, COUNT(email) AS emailCount
FROM Table
GROUP BY name, email
HAVING ( COUNT(email) > 1 );
I would like to find all people with a duplicate email addresses, (only where both people are employed (E)). However it is returning zero results.
I'd like to be able to display all information for people with duplicate emails, and having employment_Status E. If two people have the same email, but one or both is Unemployed (U), then just ignore.
Could anyone advise?
I think you want exists:
select t.*
from t
where t.employeed = 'E' and
exists (select 1
from t t2
where t2.email = t.email and t2.employeed = 'E' and
t2.name <> t.name
);
Note that this assumes that name (or at least name/email) is unique.
In MySQL 8+, you can use window functions:
select t.*
from (select t.*, count(*) over (partition by t.email) as cnt
from t
where t.employeed = 'E'
) t
where cnt >= 2;
One way would be to use your query as a subquery in FROM clause, and JOIN the result with the main table.
SELECT t.*, d.emailCount
FROM (
SELECT email, employment_Status, COUNT(*) AS emailCount
FROM my_table
GROUP BY email
WHERE employment_Status = 'E'
HAVING emailCount > 1
) d
JOIN my_table t USING(email, employment_Status)
You could also use GROUP_CONCAT(name), if you are fine getiing the names in a (comma) separated string:
SELECT email, COUNT(*) AS emailCount, GROUP_CONCAT(name) as names
FROM my_table
GROUP BY email
WHERE employment_Status = 'E'
HAVING emailCount > 1
The result for your sample data would be:
email emailCount names
-----------------------------------------------
Michael#email.com 2 Michael,Steve

Find duplicates using MySQL considering multiple columns

I need to find duplicate uses based on either same email OR first_name, last_name combination OR same birth_date. What I could comfortably try was:
SELECT id, first_name, last_name
FROM users
where id IN (SELECT id
from users
GROUP BY email
HAVING count(*) > 1)
GROUP BY email, id;
The above gives only duplicate email details, but I'm bit confused about handling other conditions based on first_name, last_name combination OR same birth_date as well.
Is it possible to achieve it in a single query?
Try doing a UNION of three separate queries which checks for the three duplicate criteria:
SELECT id
FROM users
GROUP BY id
HAVING COUNT(DISTINCT email) > 1
UNION
(
SELECT id
FROM users t1
INNER JOIN
(
SELECT firstname, lastname
FROM users
GROUP BY firstname, lastname
HAVING COUNT(*) > 1
) t2
ON t1.firstname = t2.firstname AND
t1.lastname = t2.lastname
)
UNION
SELECT id
FROM users
GROUP BY id
HAVING COUNT(DISTINCT birthdate) > 1

Selecting newest distinct email address from table

Very quick one:
I've done this before, but having a bit of a mind blank right now.
SELECT max(id) as id, username, email
FROM user_info
WHERE username!=''
GROUP by id,email
Unfortunately this is not working. It will select the max id but not then the corresponding data from that row.
If you have multiple ids per email address, then you can use max(id) and group by the email only.
SELECT max(id) as id, username, email
FROM user_info
WHERE username <> ''
GROUP by email, username
You can use a subquery which will return the max id in the subquery and then you use that to self join on the table to return the most recent id, username and email:
SELECT u.id, u.username, u.email
FROM user_info u
INNER JOIN
(
select max(id) maxid, email
from user_info
where username <> ''
group by email
) u2
on u.id = u2.maxid
See SQL Fiddle with Demo
Select DISTINCT(email), MAX(id)
FROM user_info
GROUP by email
ORDER BY id DESC