An efficient way to write MySql query that has duplicate column names - mysql

I have a reasonably straightforward MySQL query as follows:
SELECT *
FROM post INNER JOIN comment ON post.post_id = comment.post_id
WHERE post.host = 99999
ORDER BY post.post_id
My problem is that some of my column names are common to both the post and comment table. In the result, the column name appears only once, and its values are taken from the last table in the query (ie. the comment table).
I realise that I could explicitly list each column name in the SELECT part of the query, and use aliases to differentiate between duplicate column names, but there are a lot of columns in each table and it would be messy.
Is there a more efficient way to go about it?

You should just use aliases for those columns that are alike and then * for the rest:
SELECT post.post_id, comment.post_id as comment_post_id, *
FROM ...
I don't think there is a better approach.
Good luck.

Listing column names is always a better approach as long as it is feasible, it may give some hint to the MySQL optimizer.
Additionally, I would use Using syntax when the Join is done on similar column name.
SELECT x.x1, x.x2 ... , y.x1, y.x2 ...
FROM post as x
INNER JOIN comment as y
USING post_id
WHERE ...

You can select all the column from both the table.Just give an alias to the both table name and the use alias.* after select statement.
Then it will select all the column from the table.
Example:
SELECT pst.*,cmt.* from post pst INNER JOIN comment cmt
FROM ...

Related

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.

Using an INNER JOIN without returning any columns from the joined table

Running an INNER JOIN type of query, i get duplicate column names, which can pose a problem. This has been covered here extensively and i was able to find the solution to this problem, asides from it being fairly logical, by SELECTing only the columns i need.
However, i would like to know how i could run such a query without actually returning any of the columns from the joined table.
This is my MySQL query
SELECT * FROM product z
INNER JOIN crosslink__productXmanufacturer a
ON z.id = a.productId
WHERE
(z.title LIKE "%search_term%" OR z.search_keywords LIKE "%search_term%")
AND
z.availability = 1
AND
a.manufacturerId IN (22,23,24)
Question
How would i modify this MySQL query in order to return only columns from product and none of the columns from crosslink__productXmanufacturer?
Add the table name to the *. Replace
SELECT * FROM product z
with
SELECT z.* FROM product z
Often when you are doing this, the intention may be clearer using in or exists rather than a join. The join is being used for filtering, so putting the condition in the where clause makes sense:
SELECT p.*
FROM product p
WHERE (p.title LIKE '%search_term%' OR p.search_keywords LIKE '%search_term%') AND
p.availability = 1 AND
exists (SELECT 1
FROM pXm
WHERE pXm.productId = p.id AND pxm.manufacturerId IN (22, 23, 24)
);
With the proper indexes, this should run at least as fast as the join version (the index is crosslink__productXmanufacturer(productId, manufacturerId). In addition, you don't have to worry about returning duplicate records, if there are multiple matches in crosslink__productXmanufacturer.
You may notice two other small changes I made to the query. First, the table aliases are abbreviates for the table names, making the logic easier to follow. Second, the string constants use single quotes (the ANSI standard) rather than double quotes. Using single quotes only for string and date constants helps prevent inadvertent syntax errors.

read a list of values from another table using subquery and check where in condition

A small question may be it is silly but I am not getting idea how to solve this problem
select * from customers where id in(select assigned from users where username='test');
in the above query
select assigned from users where username='test'
this returns 1,2
but the condition where in doesnot work which should be like below
select * from customers where id in(1,2);
this is not the exact output i am just guessing that it might be this way. which is not so the problem is occuring.
i am getting only one row that is corresponding to 1
so help me figuring this out.
please check the sqlfiddle below:
http://sqlfiddle.com/#!2/95c28/2
thanks
SELECT DISTINCT c.*
FROM customers c
JOIN users u ON FIND_IN_SET(c.id, u.assigned) IS NOT NULL
Putting comma-separated values is a bad idea in relational databases, it makes everything more complicated. You should use a relation table instead, so you can write a normal equality join. The above query cannot be indexed, so it will be very innefficient if the tables are large.
SQLFIDDLE
if select assigned from users where username='test' returns 1,2. This means your customer table contains only Id=1.

mysql: join on with or condition displaying result twice

why this query displaying same result twice.
"SELECT * from sony.bsha
inner join sony.frndreq
on sony.frndreq.from='"+email+"' or sony.frndreq.to='"+email+"'";
And please tell to me how to stop displaying data twice.
You should join your tables on some common field, and then use WHERE clause:
SELECT *
FROM sony.bsha
INNER JOIN sony.frndreq
ON sony.bsha.someField = sony.frndreq.someField
WHERE sony.frndreq.from='"+email+"' OR sony.frndreq.to='"+email+"' "
If you're still getting double results use DISTINCT or GROUP BY. It's hard to say anything more not being given your database schema etc.
Use GROUP BY
"SELECT *
from sony.bsha
inner join sony.frndreq
on sony.frndreq.from='"+email+"' or sony.frndreq.to='"+email+"'
GROUP BY sony.frndreq.from
";
You should have to specify a condition on a common field between two tables. Then only you will get unique records.
"SELECT * FROM sony.bsha
INNER JOIN sony.frndreq ON sony.bsha.id = sony.frndreq.bid
WHERE sony.frndreq.from='"+email+"' OR sony.frndreq.to='"+email+"'";
In above SQL I assumed fields for
sony.bsha.id = sony.frndreq.bid
condition where sony.bsha.id is Primary Key in Left Table and sony.frndreq.bid is Foriegn Key in Right Table.
Be aware that even though you are using an inner join that it will still return more than one of the "same" record if redundant data exists. Perhaps if you check "email" you may find more than one occurrence of a value in which you are getting duplicates for. Run a query using a value from the duplicate records you are getting and see what you get.
In the case there are duplicate values for email (and that is not in error), do as the other user has said and use DISTINCT or GROUP BY. Remember though for those to work that all the fields you specify in the select must be the same, not just email.

Select from one table where not in another

I'm trying to find the rows that are in one table but not another, both tables are in different databases and also have different column names on the column that I'm using to match.
I've got a query, code below, and I think it probably works but it's way too slow:
SELECT `pm`.`id`
FROM `R2R`.`partmaster` `pm`
WHERE NOT EXISTS (
SELECT *
FROM `wpsapi4`.`product_details` `pd`
WHERE `pm`.`id` = `pd`.`part_num`
)
So the query is trying to do as follows:
Select all the ids from the R2R.partmaster database that are not in the wpsapi4.product_details database. The columns I'm matching are partmaster.id & product_details.part_num
Expanding on Sjoerd's anti-join, you can also use the easy to understand SELECT WHERE X NOT IN (SELECT) pattern.
SELECT pm.id FROM r2r.partmaster pm
WHERE pm.id NOT IN (SELECT pd.part_num FROM wpsapi4.product_details pd)
Note that you only need to use ` backticks on reserved words, names with spaces and such, not with normal column names.
On MySQL 5+ this kind of query runs pretty fast.
On MySQL 3/4 it's slow.
Make sure you have indexes on the fields in question
You need to have an index on pm.id, pd.part_num.
You can LEFT JOIN the two tables. If there is no corresponding row in the second table, the values will be NULL.
SELECT id FROM partmaster LEFT JOIN product_details ON (...) WHERE product_details.part_num IS NULL
To expand on Johan's answer, if the part_num column in the sub-select can contain null values then the query will break.
To correct this, add a null check...
SELECT pm.id FROM r2r.partmaster pm
WHERE pm.id NOT IN
(SELECT pd.part_num FROM wpsapi4.product_details pd
where pd.part_num is not null)
Sorry but I couldn't add a comment as I don't have the rep!
So there's loads of posts on the web that show how to do this, I've found 3 ways, same as pointed out by Johan & Sjoerd. I couldn't get any of these queries to work, well obviously they work fine it's my database that's not working correctly and those queries all ran slow.
So I worked out another way that someone else may find useful:
The basic jist of it is to create a temporary table and fill it with all the information, then remove all the rows that ARE in the other table.
So I did these 3 queries, and it ran quickly (in a couple moments).
CREATE TEMPORARY TABLE
`database1`.`newRows`
SELECT
`t1`.`id` AS `columnID`
FROM
`database2`.`table` AS `t1`
.
CREATE INDEX `columnID` ON `database1`.`newRows`(`columnID`)
.
DELETE FROM `database1`.`newRows`
WHERE
EXISTS(
SELECT `columnID` FROM `database1`.`product_details` WHERE `columnID`=`database1`.`newRows`.`columnID`
)