Joining and querying two tables with conflicting column names - mysql

Imagine I have two tables: users and students
Each table has an id and email column. I want to be able to search for emails from both tables. I can join the two tables where the IDs match like this:
SELECT users.email,students.email as student_email FROM users
INNER JOIN students ON users.id = students.id
I can't search the email column because they have the same column name (email). So if I try use WHERE it complains that the column (email) is ambiguous. If I try use student_email it complains that the column doesn't exist.
If the two tables didn't use an identical column name (email) then it would be fine when I use WHERE.
The only solution I can think of is to get all rows and then loop around them and search the email strings manually. This is extremely slow compared to using MySQL like this:
SELECT users.email,students.email as student_email FROM users
INNER JOIN students ON users.id = students.id
WHERE email LIKE '%test#email.com%' OR student_email LIKE '%test#email.com%'
But of course this doesn't work because WHERE looks for the original column names before the SELECT.
How can I get around this without getting all the rows and the looping it? Maybe it is a union, rather than a JOIN? I'm not sure...

Just use the qualified column name. I also recommend table aliases:
SELECT u.email, s.email as student_email
FROM users u INNER JOIN
students s
ON u.id = s.id
WHERE u.email LIKE '%test#email.com%' OR
s.email LIKE '%test#email.com%';
Whenever you have more than one table in a query, you should always qualify all the column names. Using abbreviations for the tables as table aliases makes the query easier to write and to read.

Related

Mysql join:search with two tables

I have two tables
1)Users table (id,name);
1)Deals table (id,user_id(FK users),title,keyword);
When the user gives a keyword
I would like to get all deals from the deals table that matches title and keyword along with all deals of the users to match the keyword name.
Is it possible to achieve this within single query I am confusing with it or do I need to run two query's
ie
1)Get all deals of that matches keyword and title from deals table.
2)Get all deals of the users matches the keyword in the name from user table (probably a join query).
If I go with this approach how do I implement pagination on it??.
This joins both tables and returns the rows that matches all 3 conditions.
SELECT d.id, d.title, d.keyword, u.name,
FROM Deals d
JOIN Users u ON u.id = d.user_id
WHERE (d.title = 'some title' AND d.keyword = 'some keyword')
OR u.name = 'some name'
If you don't want/need exact matches LIKE can be used instead, for instance
WHERE d.title LIKE '%some title%'

How to properly use inner join in SQL when I have to join a table twice?

Note: The actual schema isn't male/female, but some other criteria. I'm just using male/female for this example to make it easier to understand.
I have a table "users", which contains a column user_name and user_gender. The gender can be "M" or "F".
The problem is that I have another table, "messages", that has a column for "sender" and "receiver". These columns contains user_name in each row.
How can I use INNER JOIN so that I can get messages where only males send to females?
I know easily how to specify it once, binding users.user_name to "sender" or "receiver" but not both.
To expand on my question, how do see which top 10 pairs where a male sent the most messages to a female? Note, this means unique A/B pairs, so I want to return cases where a guy sends a single female a ton of messages, not when a guy spams a lot of messages to different females.
Think of your messages table as a "cross table" connecting two rows in the users table. When you join to a table like that, give users two different aliases, and refer to them in your join conditions, like this:
select *
from messages msg
join users m on msg.sender = m.user_id AND m.user_gender='M'
join users f on msg.receiver = f.user_id AND f.user_gender='F'
With this skeleton in hand, you should be able to figure out the rest of your query:
Use GROUP BY to group by m.user_id, f.user_id, and count(*) to count
Order by COUNT(*) to get the highest sender+receiver pairs at the top
Use LIMIT to grab the top ten pairs.

Select from a table the ones that don't have a relationship with another table

The specific problem is listing the names of the teachers that never graded.
I have 'teachers' table with the columns 'Name' and 'ID'.
And 'grades' table with the column 'IDTeacher' and 'Grade'.
Don't get why this doesn't work:
Select Name from teachers where not exists(Select * from grades, teachers)
You can just join it with the grades table and use the ones where the join returns "null" for the right side:
SELECT
name
from
teachers t
LEFT JOIN
grades g
on
t.teacher = g.teacher
WHERE
ISNULL(g.teacher)
edit: Thought about a right join instead, but no, the right join might not work, if the teacher has no entry in the grades table. (Then you would miss him completely, even if he is in the teacher table)
You could also use WHERE IN for this:
SELECT
name
FROM
teachers
WHERE
name
NOT IN (SELECT name from grades)
BUT the MySQL Optimizer will rewrite this to exactly the correlated subquery #Gordon Linoff has written. Using WHERE NOT IN is just easier to read imho.
Your query does work, it just doesn't do what you think it should. The subquery creates a cartesian product between the two tables. If both tables have rows, then the cartesian product has rows and the where clause will always be true.
You can take this approach, but you need a correlated subquery:
Select Name
from teachers t
where not exists (Select 1 from grades g where g.idteacherid = t.id);
Note that this query only has one table in the subquery.
There are other ways to write this query, but this seems to be the approach you are heading in. And, not exists is a very reasonable approach.

Left join and show the non-foreign key

I have two tables that I'm joining, Users and Addresses.
The Users table has a unique (but not primary) key called userID.
The Addresses table has a primary key called userID.
I'm trying to left-join the tables so that I get all the info from the Users table regardless if it has a match in the Addresses table, so I used
select * from users u left join addresses a on a.userID = u.userID
This works, but it only shows userID's if there is a match. How do I get the userID regardless if there's a match or not?
Edit: The following image shows what my current query (left join) returns:
Now it's clear what the problem is.
There's nothing "wrong" with the query, except that it is returning multiple expressions (columns) with the same alias. And one of them is overriding the other. (Not in terms of the resultset being returned, all the columns and rows are there; the issue is with how your PHP script is processing the resultset. If you are referencing the values from the row by "association" (using the column name), only one of the column values gets referenced.
So, one way to fix that, is to qualify the columns in the query:
SELECT u.userID
, u.blah
, a.userID AS a_userID
, a.blah AS a_blah
FROM users u
LEFT
JOIN addresses a
ON ...
such that all column aliases are unique. Then all of those column names will be available by "association" in your PHP.
Using the query you provided should give a result in the u.userID column regardless of if it had a corresponding address. The a.userID column would only have data in the rows that were joined with an address.
You could change to:
select u.*, a.address from users u left join addresses a on a.userID = u.userID
Which would select only the relevant parts of the address and keep the whole u.

SQL Server 2005/2008 : find row values that exist and list that don't in my in select column condition IN()

I have a single table that contain columns:
UserID, EmployeeID, BadgeType, HiredDate, TermDate
Now I need to find userID that are with (gbro, qunro, 1utny, ybeiot, 4ybey)
The 3 users (gbro, qunro, 1utny) exist so it is listed with respective its column info.
What if ybeiot, 4ybey does not exist AT ALL but still I want them listed in a separate table still but with a message that PRINTS: User that does not exist: ybeiot;4ybey
Help, been finding way how to do this.
I tried JOIN (all the joins) but it does not result to what I wanted.
Did you look at SQL EXISTS keyword?
put all the users to be searched in a temp table or table variable #userstoSearch
select * from #userstoSearch us left join users u
on us.UserID=u.UserID where u.userID is not null
select us.UserID from #userstoSearch us left join users u
on us.UserID=u.UserID where u.userID is null
for xml path('')
You need two selects. The first will list the existing values and the second lists the not existing values. You should merge these results using the union keyword.