I have this query:
select distinct somecolumn from sometable
where something = somethingelse and
someid not in (select anotherid from another tabele where ...);
I think the query runs really slow because of the subselect. Is there a way to rewrite that so the not in and the subselect can be removed?
use LEFT JOIN
SELECT someClumn
FROM sometable a
LEFT JOIN anotherTable b
ON a.someID = b.anotherID
-- AND condition for anotherTable
WHERE a.something = somethingelse AND
b.anotherID IS NULL
for better performance, define an index on columns: someID and anotherID.
Try
select
distinct somecolumn
from
sometable t1
left join anothertable t2 on (t1.someid=t2.otherid and t2.othercondition='else')
where
t1.something='something else'
and t2.pk is null
;
And t2.otherid should be indexed.
NOTE: The WHERE clause from the subquery is in the JOIN condition.
In theory, NOT EXISTS should optimize slightly better than NOT IN, and should also be more reliable if anotherid is NULLable (details on this from a SQL Server standpoint). Though I will confess I don't know enough about MySQL to know if this query will be better:
SELECT somecolumn
FROM dbo.sometable AS s
WHERE something = somethingelse
AND NOT EXISTS
(
SELECT 1 FROM dbo.[another table]
WHERE anotherid = s.someid
);
But I suspect the real performance problem here is lack of indexes, not the presence of a subquery. Is sometable.something indexed? How about sometable.somied? And [another table].anotherid? Also the DISTINCT may require an additional sort, but is it truly necessary? If you have duplicates, that might suggest a design problem...
select somecolumn
from sometable
LEFT JOIN another tabele
ON someid = anotherid
AND (where clause from subquery)
WHERE anotherid IS NULL
AND something = somethingelse
I assume DISTINCT redundant if you have One-to-many relationship.
try this
select somecolumn from sometable
where something = somethingelse and
someid not in (select anotherid from another tabele where ...)
GROUP BY somecolumn;
Related
Hy mates,
I have a database table which looks like this:
uniqueId,asin,rank
1,abc,1
2,xyz,2
3,abc,1
4,xyz,2
5,opq,3
As you can see that the asin's (abc and xyz) were repeated. So I would like my query to avoid them completey and return me only (opq).
Best Regards
Usama
I think you need
select *
from yourtable a
where 1 = (
select count(*)
from yourtable
where a.asin = asin
)
Demo
not exists should have the best performance:
select t.*
from t
where not exists (select 1
from t t2
where t2.asin = t.asin and t2.id <> t.id
);
For performance, you want an index on (asin, id).
I am running a query like this:
SELECT DISTINCT `tableA`.`field1`,
`tableA`.`filed2` AS field2Alias,
`tableA`.`field3`,
`tableB`.`field4` AS field4Alias,
`tableA`.`field6` AS field6Alias
FROM (`tableC`)
RIGHT JOIN `tableA` ON `tableC`.`idfield` = `tableA`.`idfield`
JOIN `tableB` ON `tableB`.`idfield` = `tableA`.`idfield`
AND tableA.field2 IN
(SELECT field2
FROM tableA
GROUP BY tableA. HAVING count(*)>1)
ORDER BY tableA.field2
This is to find all the duplicate entries, but now it's taking lot of time for the execution. Any suggestions for optimization?
It looks like you are trying to find all duplicates on field2 in TableA. The first step would be to move the in subquery to the from clause:
SELECT DISTINCT a.`field1`, a.`filed2` AS field2Alias,
a.`field3`, b.`field4` AS field4Alias, a.`field6` AS field6Alias
FROM tableA a left join
tableC c
on c.`idfield` = a`.`idfield` join
`tableB` b
ON b.`idfield` = a.`idfield` join
(SELECT field2
FROM tableA
group by field2
having count(*) > 1
) asum
on asum.field2 = a.field2
ORDER BY tableA.field2
There may be additional optimizations, but it is very hard to tell. Your question "find duplicates" and your query "join a bunch of tables together and filter them" don't quite match. It would also be helpful to know what tables have which indexes and unique/primary keys.
select * from tablename
where id in(select id from tablename2 where condition UNION select -1)
Is it ok to use select -1 as if the inner query does not result anything it will give error. It is feasible or not?
imho, inner-select is far from ideal (slow)
based on your posted SQL, an inner join will do the trick
select *
from tablename as t1
inner join tablename2 as t2
on t1.id=t2.id
where condition; --- your condition
If you have to get it done with a subquery then the correct way to do it would probably be:
SELECT *
FROM tablename AS t1
WHERE EXISTS
(SELECT id
FROM tablename2 AS t2
WHERE conditions)
It won't give an error if the query returns nothing. It just returns an empty resultset.
Look here and here.
With the answers above, I have made this query, is it valid? If not, how can I correct it?
SELECT *,
FROM TABLE_2 t
WHERE EXISTS(SELECT IF(column1 = 'smith', column2, column1)
FROM TABLE_1 a
WHERE 'smith' IN (a.column1, a.column2)
AND a.status = 1
AND ( 'smith' IN (t.column1, t.column2)
)
To start with, the comma after select * does not belong.
Second, you alias your tables (table_2 t and table_1 a), but then you don't consistently use the aliases, so you might have issues at run time. Also from a maintenance perspective, I think most folks prefer to use aliases when declared, and no aliases otherwise.
Third, you do a comparison against cols from the t table in the outer select ('smith' in (t.column1, t.column2) ), when that appears unnecessary. You can just do it in the outer select. In other words, you can move that terminal paren to before the AND ('smith'...
As for whether it works -- I have no idea, since I don't know what you are trying to accomplish.
Combined, that would leave you with :
SELECT t.*
FROM TABLE_2 t
WHERE EXISTS (SELECT IF(a.column1 = 'smith', a.column2, a.column1)
FROM TABLE_1 a
WHERE 'smith' IN (a.column1, a.column2)
AND a.status = 1)
AND ( 'smith' IN (t.column1, t.column2)
Problem is as follows. I have a product that can be in one of three categories (defined by category_id). Each category table has category_id field related to category_id in product table. So I have 3 cases. I'm checking If my product.category_id is in table one. If yes, I take some values. If not I check in tables that are left. What can I write In the ELSE section? Can anyone correct my query ?
CASE
WHEN IF EXISTS(SELECT * FROM table1 WHERE category_id='category_id') THEN SELECT type_id FROM table1 WHERE category_id='category_id';
WHEN IF EXISTS(SELECT * FROM table2 WHERE category_id='category_id') THEN SELECT value_id FROM table2 WHERE category_id='category_id';
WHEN IF EXISTS(SELECT * FROM table3 WHERE category_id='category_id') THEN SELECT group_id FROM table3 WHERE category_id='category_id';
ELSE "dont know what here";
END;
In the else you would put whatever you want as default value, for example null.
I think that it would be much more efficient to make three left joins instead of several subqueries for each product in the result, and use coalesce to get the first existing value. Example:
select coalesce(t1.type_id, t2.value_id, t3.group_id)
from product p
left join table1 t1 on t1.category_id = p.category_id
left join table2 t2 on t2.category_id = p.category_id
left join table3 t3 on t3.category_id = p.category_id
example
SELECT CompanyName,
Fax,
CASE WHEN IF(Fax='', 'No Fax', 'Got Fax')='No Fax' THEN NULL
ELSE IF(Fax='', 'No Fax', 'Got Fax')
END AS Note
FROM Customers;
You can possibly include this...
SELECT "Unknown type" FROM table1;
You do not need to use ELSE if there is nothing left to do.
or something like this
CASE
WHEN IF EXISTS(SELECT * FROM table1 WHERE category_id='category_id') THEN SELECT type_id FROM table1 WHERE category_id='category_id';
WHEN IF EXISTS(SELECT * FROM table2 WHERE category_id='category_id') THEN SELECT value_id FROM table2 WHERE category_id='category_id';
ELSE SELECT group_id FROM table3 WHERE category_id='category_id';
In addition to Guffa's answer here is another approach - assuming #category_id is
SET #category_id = 'some_category_id_value'
then
SELECT t1.type_id
WHERE category_id = #category_id
UNION ALL
SELECT t2.value_id
WHERE category_id = #category_id
UNION ALL
SELECT t3.group_id
WHERE category_id = #category_id
should return what you ask for (and performance is not bad either).
If you have certain category_id in more then one table you will get multiple records (you can get out of that by limiting the number of results to 1; you might need to make it the whole union a subquery and order it, but not sure, consult the docs)
However, your question looks like you have a problem with a design of your tables
why do you keep three category tables and not one?
what is the relationship between type_id, value_id and group_id and why does it make sense to select them as if they were the same thing (what is the meaning/semantics of each table/column)?
how do you guarantee that you don't have entries in multiple tables that correspond to one product (and implement other business rules that you might have)?
These questions could have valid answers, but you should know them :)