Avoiding subqueries - mysql

I have a query like this:
SELECT a.number, a.name, b.name1 FROM a,b
WHERE a.number NOT IN (SELECT number FROM c)
AND a.name = b.name1
This query takes a very long time to run. I think it is because of the subquery.
Is it possible to avoid using subquery in this case?

You can use this code as an alternative to get your results.
SELECT a.number, a.name, b.name1
FROM a
JOIN b ON a.name = b.name1
LEFT JOIN c ON a.number = c.number
WHERE c.number is NULL;
You must however check to make sure you have properly defined indexes on your table unless the query will do full table scans on each execution. This will not be noticeable when the data in your table is small, it will start to get slower as your table grows.
You can do an explain on the query to check its execution plan, and optimise accordingly.
EXPLAIN SELECT a.number, a.name, b.name1
FROM a
JOIN b ON a.name = b.name1
LEFT JOIN c ON a.number = c.number
WHERE c.number is NULL;

Try using join:
SELECT a.number, a.name, b.name1
FROM a join b on a.name = b.name1
left join c on a.number = c.number
WHERE c.number is null

Related

Group by Use Query if SQL LEFT JOIN is performed multiple times

I think it's impossible, but I'm asking if there's a good way.
There are A table / B table / C table.
The table was joined LEFT JOIN based on table A with FK called id of each table.
At this time, I would like to output the count(*) as B table rows and C table rows based on b.id(B_CNT) c.id(C_CNT)
SELECT
*
FROM
A
LEFT JOIN B ON A.ID = B.ID
LEFT JOIN C ON A.ID = C.ID (base query)
how could I count group by b.id and c.id?
You could try:
SELECT
COUNT(DISTINCT B.ID), COUNT(DISTINCT C.ID)
FROM A
LEFT JOIN B
ON A.ID = B.ID
LEFT JOIN C
ON A.ID = C.ID
(I couldn't quite understand from your question, but I'm making an assumption that you want the distinct count of "ID" from each table)
You can use a couple of scalar subqueries. For example:
select id,
(select count(*) from b where b.id = a.id) as b,
(select count(*) from c where c.id = a.id) as c
from a

Does COALESCE work properly with VIEWs?

I have my view definition:
CREATE VIEW `view` AS
SELECT a.id,
COALESCE(COALESCE(b.name, c.name), a.name) AS name
FROM a_table a
LEFT JOIN b_table b on a.b_id = b.id
LEFT JOIN c_table c on a.c_id = c.id
And after I'm updating a_table row with new name it doesn't get updated in my view. But if I change name to COALESCE(a.name, COALESCE(b.name, c.name)) AS name it works.
As I understand the reason is in COALESCE. It takes the first not null value and in my case it's b.name and gets updated only when b.name is updated.
Is there any option to updated the view when any of COALESCE values are changed?
COALESCE() works fine in views. It also takes multiple arguments, so I would suggest writing this as:
CREATE VIEW `view` AS
SELECT a.id, COALESCE(b.name, c.name, a.name) AS name
FROM a_table a LEFT JOIN
b_table b
ON a.b_id = b.id LEFT JOIN
c_table c
ON a.c_id = c.id;
Views are not "updated". They are SQL code that is plugged into queries when the view is reference. The data comes from the underlying tables.

MySql JOIN query with OR clause very slow

I have the following query:
SELECT a.id, b.from, b.to FROM a INNER JOIN b ON a.id = b.from OR a.id = b.to;
which is extremely slow.
If I remove the OR clause and run each query separately then the both queries execute under 1 second.
SELECT a.id, b.from, b.to FROM a INNER JOIN b ON a.id = b.from;
SELECT a.id, b.from, b.to FROM a INNER JOIN b ON a.id = b.to;
How can I speed up the original query (set up indexes) or redesign the query itself?
What about using union?
SELECT a.id, b.from, b.to FROM a INNER JOIN b ON a.id=b.from
UNION
SELECT a.id, b.from, b.to FROM a INNER JOIN b ON a.id=b.to
How about the following instead. Just join to b twice:
SELECT a.id, b.from, b2.to
FROM a
INNER JOIN b ON a.id = b.from
INNER JOIN b b2 ON a.id = b2.to;
You may have to use LEFT JOIN instead if you don't always have a record for both cases.

Fix inefficient and difficult query

I have a query in my application that is performing poorly. I think it can be optimzed but my SQL skills are failing me. Here's the query in a sort of meta-sql:
SELECT A.Value, count(*)
FROM B
JOIN A ON B.A_ID = A.ID
JOIN C ON C.ID = B.C_ID
WHERE B.C_ID IN (
SELECT B.C_ID
FROM C
JOIN B ON B.C_ID = C.ID
JOIN A ON B.A_ID = A.ID
WHERE A.VALUE IN 'string literal'
)
GROUP BY A.VALUE
C is a table of vacancies, B is a table of properties of the vacancies and A is a table of property values. The tables have 1 to N relationships. We need to find a list of all other property values (and the number of times they occur) of vacancies that have a certain fixed property value related to it.
Please help in optimizing the query for efficiency.
Thanks in advance!
You don't need to join in C in either query, unless that is being used for filtering (that is, non matches are being filtered out). Try this:
SELECT A.Value, count(*)
FROM B JOIN
A
ON B.A_ID = A.ID
WHERE EXISTS (SELECT 1
FROM B b2 JOIN
A a2
ON b2.A_ID = a2.ID
WHERE a2.VALUE = 'string literal' AND b2.C_ID = b.C_ID
)
GROUP BY A.VALUE;

MYSQL getting the difference of two results

ok so my problem is that I have a set of results:
ID CODE
1 A
1 B
3 C
I also have another table of:
CODE
A
B
C
What I want to get using SQL is a query of CODES that each result from table 1 is missing. So basically:
ID CODE
1 C
3 A
3 B
Any help would be great.
You can use:
SELECT a.id, b.code
FROM (SELECT DISTINCT id FROM idcodes) a
CROSS JOIN codes b
LEFT JOIN idcodes c ON a.id = c.id AND b.code = c.code
WHERE c.id IS NULL
ORDER BY a.id, b.code
If you have another table that stores unique entries for id, it would be better to just use that table instead rather than a DISTINCT subselect:
SELECT a.id, b.code
FROM ids a
CROSS JOIN codes b
LEFT JOIN idcodes c ON a.id = c.id AND b.code = c.code
WHERE c.id IS NULL
ORDER BY a.id, b.code
SQLFiddle Demo
You can use exists. Construct the full list of possible variations with a Cartesian join and then ensure what you have isn't in this list.
select id, code
from idcode_table x
where not exists ( select 1
from idcode_table a
cross join code_table b
where b.code = x.code
and a.id = x.id )
This can also be re-written with a not in.
select id, code
from idcode_table
where (id, code) not in ( select distinct a.id, b.code
from idcode_table a
cross join code_table b )
The distinct is optional. It will make it slower to construct the list of possibles but quicker to determine if you have one of them already. I'd test it to see which is quicker.