Optimize MySQL Query on Multiple NOT INs - mysql

Is there any way to optimize this sql statement?
Maybe joins or something?
SELECT id, name
FROM item
WHERE id NOT IN (
SELECT id
FROM itemlock
) AND id NOT IN (
SELECT id
FROM itemlog
)
Thanks

use LEFT JOIN
SELECT a.*
FROM item a
LEFT JOIN itemLock b
ON a.ID = b.ID
LEFT JOIN itemLog c
ON a.ID = c.ID
WHERE b.ID IS NULL AND
c.ID IS NULL

You can also use UNION, like below:
SELECT id, name FROM item
WHERE id NOT IN (
SELECT id FROM itemlock UNION SELECT id FROM itemlog
)

Try this:
SELECT id, NAME FROM item i
LEFT JOIN (SELECT id FROM itemlock
UNION
SELECT id FROM itemlog) AS A ON i.id = A.id
WHERE A.id IS NULL;

Related

How to use GROUP_CONCAT on multiple JOIN

I am currently retrieving data from multiple tables using a cus_id as the initial query. From here I have multiple tables that can have various rows of data that I would like to retrieve and use GROUP_CONCAT to return this data in a single row. At the moment, my query is returning duplicate data based on the max number of rows returned by one of the group concats.
SELECT a.id,c.x,c.y,c.z
GROUP_CONCAT(a.column_a) AS aca,
GROUP_CONCAT(a.column_b) AS acb,
GROUP_CONCAT(b.column_a) AS bca,
GROUP_CONCAT(b.column_b) AS bcb,
FROM `table_a` a
INNER JOIN `table_b` b ON a.id = b.id
INNER JOIN `table_c` c ON a.id = c.id
WHERE a.id = ?
Also, in this scenario, what is the correct join method to use. I am expecting all the fields I am requesting to have some sort of data.
Problem was resolved by using sub queries to isolate the GROUP_CONCAT requests. This allowed me to get only the data I wanted without duplicate results manipulated by other JOIN requests.
SELECT a.id,c.x,c.y,c.z
(SELECT GROUP_CONCAT(column_a) FROM table_a) AS aca,
(SELECT GROUP_CONCAT(column_b) FROM table_a) AS acb,
(SELECT GROUP_CONCAT(column_a) FROM table_b) AS bca,
(SELECT GROUP_CONCAT(column_b) FROM table_b) AS bcb,
FROM table_a a
INNER JOIN `table_c` c ON a.id = c.id
WHERE a.id = ?
Aggregate before joining. Somthing along the lines of:
select
a.*,
b.grp_a,
b.grp_b,
c.grp_x,
b.grp_y
from table_a a
join
(
select
a_id,
group_concat(a order by b_id) as grp_a,
group_concat(b order by b_id) as grp_b
from table_b
group by a_id
) b on b.a_id = a.id
join
(
select
a_id,
group_concat(x order by c_id) as grp_x,
group_concat(y order by c_id) as grp_y
from table_c
group by a_id
) c on c.a_id = a.a_id
order by a.a_id;

Left join is returning multiple rows from Table B corresponding to ID present in Table A

I have 2 tables in my SQL database. Let's call them Table A and Table B.
I have joined both the tables using left join on ID = AID. Table A has a field by name ID and Table B has field AID and Price.
The problem is Table B can have multiple prices for the ID present in Table A.
The requirement is - If only one price is present in Table B corresponding to ID in table A then it should return that price.
If more than one price is present in table B for an ID in table A then I should get the price as Zero/null.
Query -
SELECT DISTINCT A.ID,B.Price
from A
left join B
on A.ID = B.AID
where "some condition"
Use Count() with Over() window function to find the count of records for each ID then based on count return the price
Try this way
SELECT DISTINCT A.ID,
case when count(1) over(partition by A.ID) > 1 then NULL else B.Price end
from A
left join B
on A.ID = B.AID
For Mysql
SELECT DISTINCT a.id,
CASE
WHEN c.aid IS NULL THEN NULL
ELSE b.price
END
FROM a
LEFT JOIN b
ON a.id = b.aid
LEFT JOIN (SELECT aid
FROM b
GROUP BY aid
HAVING Count(1) = 1) c
ON a.id = c.aid
For SQL Server (should work for MySQL too). One sub-query (you can put in CTE) that shows only AIDs that have only one price:
SELECT A.ID,
B.Price
FROM A
LEFT JOIN (
SELECT AID
FROM B
GROUP BY AID
HAVING COUNT(Price) = 1
) as C
ON C.AID = A.ID
LEFT JOIN B
ON C.AID = B.AID
Use below query. It should work.
SELECT A.ID, o.Price
FROM A
OUTER APPLY
(
SELECT IIF(COUNT(B.Price)>1,NULL,MAX(B.Price)) AS Price
FROM B
WHERE B.AID = A.ID
) AS o;

Make 3 paired columns from one Mysql

I have a problem with a query that I try to make over a table in database.
So my table has a column with names like this :
I want a query that will select names and ids in the following mode:
either
or
Thanks in advance...
You can use inner join and calc the id
#my_len = 3
select a.id as id, a.name as name, b.id as id1, b.name as name1, c.id as id2, c.name as name2
from my_table as a
inner join my_table as b where a.id = b.id+#my_len
inner join my_table as c where a.id = c.id+#my_len*2

How to use JOINS instead of sub query

SELECT *
FROM table_a
LEFT JOIN table_b ON (table_b.id = table_a.id)
WHERE table_b.created BETWEEN ? AND ?
AND table_b.manager IN(
SELECT DISTINCT (b.id)
FROM table_b a
INNER JOIN table_b b ON a.manager = b.id
AND b.user_level > 0
AND b.id != 1
)
How can I remove the sub query and use JOINS instead in the above query
Thanks
MySQL 5.5 (and lower version)'s optimizer produces a DEPENDENT SUBQUERY for IN (SELECT ...) which means every matching row is found, IN(SELECT ...) is evaluated that makes select slow.
Simple optimization of your query is make inline view as follows:
SELECT *
FROM table_a LEFT JOIN table_b ON (table_b.id = table_a.id)
INNER JOIN (
SELECT DISTINCT b.id AS id
FROM table_b a
INNER JOIN table_b b ON a.manager = b.id
AND b.user_level > 0
AND b.id != 1
) x ON table_b.manager = x.id
WHERE table_b.created BETWEEN ? AND ?
AND x.id IS NOT NULL;
I think avobe query would produce as same as your own.
Last, DISTINCT is not a function. please use SELECT DISTINCT b.id rather SELECT DISTINCT (b.id)

MySQL - Use select field value in nested SQL statement of the same SQL

I have the following SQL query
SELECT
a.id AS ID, a.title,
(
SELECT Group_Concat( title )
FROM (
SELECT title
FROM `table_b` AS b
JOIN table_c ON c.id = b.id
WHERE b.id = ID
UNION
SELECT title
FROM `table_b` AS b
JOIN table_c ON c.id = b.id
WHERE b.another_id = ID
) AS other_titles
FROM table_a
However it is not working and is having a problem with the parts WHERE b.id = ID and WHERE b.another_id = ID in the nested SQL part.
How can I use the ID from the first select (SELECT a.id AS ID) in the nested select?
I think what you have here is called correlated subquery. It looks quite promising and seems to only lack a couple of final strokes (highlighted in bold italic):
SELECT
a.id AS ID,
a.title,
(
SELECT Group_Concat( title )
FROM (
SELECT title
FROM `table_b` AS b
JOIN table_c ON c.id = b.id
WHERE b.id = a.ID
UNION
SELECT title
FROM `table_b` AS b
JOIN table_c ON c.id = b.id
WHERE b.another_id = a.ID
) AS other_titles
FROM table_a AS a
Keep in mind that what you are actually referencing in the subquery is a.id, not the ID alias. (You can't reference the alias there.)
If a.id is a complex expression and you are not very happy about repeating it in the subquery, then you might need to restructure the entire query, maybe like this:
SELECT
x.ID,
x.title,
(
SELECT Group_Concat( title )
FROM (
SELECT title
FROM `table_b` AS b
JOIN table_c ON c.id = b.id
WHERE b.id = x.ID
UNION
SELECT title
FROM `table_b` AS b
JOIN table_c ON c.id = b.id
WHERE b.another_id = x.ID
) AS other_titles
FROM (
SELECT
a.id AS ID,
a.title,
FROM table_a AS a
) x
You cannot select values into the FROM clause. You may only use variables to dynamically set the table name.