Operand should contain 1 column(s) in my sql query - mysql

Can someone help me with this query?
SELECT ((SELECT t6.`idreserva`, t5.`sala`, t6.`data`,t3.`inicio`, t4.`fim`, t6.`atividade`
FROM `req_reserva_detail` AS t1
INNER JOIN `req_material_tempo` AS t3 ON (t1.`idtempoInicio` = t3.`idtempo`)
INNER JOIN `req_material_tempo` AS t4 ON (t1.`idtempoFim` = t4.`idtempo`)
INNER JOIN `req_material_sala` AS t5 ON (t1.`idsala` = t5.`idsala`)
INNER JOIN `req_reservas` AS t6 ON (t1.`idreserva` = t6.`idreserva`)
INNER JOIN `utilizador` AS t7 ON (t6.`idutilizador` = t7.`idutilizador`) WHERE t6.`idutilizador` = 670 AND t6.`data` >= CURDATE() ORDER BY DATA ASC),
(SELECT nome FROM `req_reserva_detail` AS t1, `req_material_equipamento` AS t2 WHERE t1.`idequipamento` = t2.`idequipamento` GROUP BY nome))
It gives that error and i don't get how to fix that...
Regards
UPDATE
Schema

(SELECT t6. idreserva,
t5. sala,
t6. data,
t3. inicio,
t4. fim,
t6. atividade
FROM req_reserva_detail AS t1
INNER JOIN req_material_tempo AS t3
ON (t1. idtempoInicio = t3. idtempo)
INNER JOIN req_material_tempo AS t4
ON (t1. idtempoFim = t4. idtempo)
INNER JOIN req_material_sala AS t5
ON (t1. idsala = t5. idsala)
INNER JOIN req_reservas AS t6
ON (t1. idreserva = t6. idreserva)
INNER JOIN utilizador AS t7
ON (t6. idutilizador = t7. idutilizador)
WHERE t6. idutilizador = 670
AND t6. data >= CURDATE()
ORDER BY DATA ASC)
This subquery of yours returns 5 columns, but this is used as a subquery and mySQL expects it to return only one column

Related

Multiple JOIN and OR in WHERE clause MySQL query optimization

I'm trying to optimize a query similar to this one:
SELECT * FROM table1 t1 INNER JOIN table2 t2 ON t1.t2_id = t2.id
LEFT OUTER JOIN table3 t3 ON t1.t3_id = t3.id
LEFT OUTER JOIN table4 t4 ON t3.t4_id = t4.id
LEFT OUTER JOIN table5 t5 ON t3.t5_id = t5.id
LEFT OUTER JOIN table6 t6 ON t1.t6_id = t6.id
WHERE (t1.attribute1 = ? OR t2.attribute2 = ?)
AND t1.active = 1
AND t1.status <> 10
what I saw in the logs is that what takes most is the OR in the WHERE clause (with the OR the query takes ~1s for its execution, while without it it takes around ~400 ms with the data that I've sampled from the DB).
I'm looking for alternatives to get the same results without taking much time (also, performance decreases if many queries are executed concurrently).
I've tried replacing the OR with an union subquery with a join between t1 and t2 (I'm working with MySQL 5.7):
SELECT * FROM (SELECT * FROM table1 t1 INNER JOIN table2 t2 ON t1.t2_id = t2.id
WHERE t1.attribute1 = ?
UNION
SELECT * FROM table1 t1 INNER JOIN table2 t2 ON t1.t2_id = t2.id
WHERE t2.attribute2 = ?
) AS joined
LEFT OUTER JOIN table3 t3 ON joined.t3_id = t3.id
LEFT OUTER JOIN table4 t4 ON t3.t4_id = t4.id
LEFT OUTER JOIN table5 t5 ON t3.t5_id = t5.id
LEFT OUTER JOIN table6 t6 ON joined.t6_id = t6.id
WHERE joined.active = 1
AND joined.status <> 10
But I'd like to know if there is a better approach for optimizing the query.
EDIT: active, status, attribute1 and attribute2 are indexed as well as the ids.
The following index can increase the performance of the first query, as long as your are not selecting too many rows (ideally less than 1000 rows):
create index ix1 on table1 (attribute1, active, status, t2_id);
Add this index. If it's still slow, add the execution plan to your question.

Adding fifth join in the table

I have so far written the following mysql query which is joining 4 tables as follows:
SELECT
T3.fault, t4.name
FROM table2 T2
INNER JOIN (
SELECT a.*
FROM table1 a
LEFT JOIN table1 b ON a.item_id = b.item_id AND a.submit_id < b.submit_id
WHERE b.submit_id IS NULL
) T1 ON T1.item_id = T2.item_id
INNER JOIN table3 T3 ON T1.id = T3.run_id
LEFT JOIN table4 T4
ON 3.runname_id = T4.id
order by count(*) desc;
Below is sample Data for table 2 which has item_id as PK
Example query: select * from table2 where item_id = '15907';
item_id host
15907 abc.com
7303 cde.com
7304 abcd.com
7305 cdedf.com
I have now recently added a table table5 which looks as below and has item_id as PK. I want to join table5 with table2 on item_id and want to retrieve value for restoreid also in my final query.
item_id restoreId
15907 12342
7303 12342
7304 14342
7305 14342
How to implement join between table5 and table2 on item_id? My select query should also retrieve T5.restoreId along with T3.fault, t4.name
select your_table.fault,your_table.name,t5.restoreid
from (
SELECT
T3.fault, t4.name,t2.item_id
FROM table2 T2
INNER JOIN (
SELECT a.*
FROM table1 a
LEFT JOIN table1 b ON a.item_id = b.item_id AND a.submit_id < b.submit_id
WHERE b.submit_id IS NULL
) T1 ON T1.item_id = T2.item_id
INNER JOIN table3 T3 ON T1.id = T3.run_id
LEFT JOIN table4 T4
ON 3.runname_id = T4.id
) as your_table left join table5 t5 on your_table.item_id = t5.item_id
SELECT
T3.fault, t4.name, T5.restoreid
FROM table2 T2
INNER JOIN (
SELECT a.*
FROM table1 a
LEFT JOIN table1 b ON a.item_id = b.item_id AND a.submit_id < b.submit_id
WHERE b.submit_id IS NULL
) T1 ON T1.item_id = T2.item_id
INNER JOIN table3 T3 ON T1.id = T3.run_id
LEFT JOIN table4 T4
ON T3.runname_id = T4.id
LEFT JOIN table5 ON T2.item_id = T5.item_id;

UNION in WHERE clause of update subquery

Are there any reasons why UNIONs shouldn't be used in the WHERE clause of update subqueries? Or for that matter, even normal select subqueries?
Is there a better way such a query to eliminate the UNION?
Note that for my case, the UNION will result in a fairly small number of records.
UPDATE mytable
set mytable.bla='xxx'
WHERE id IN (
SELECT id
FROM t1
INNER JOIN t2 ON t2.t1_id=t1.id
LEFT OUTER JOIN t3 ON t3.t1_id=t2.id
WHERE t2.id IN (1,2,3) AND t3.id IS NULL
UNION
SELECT id FROM t4
INNER JOIN t5 ON t5.id=t4.t5_id
LEFT OUTER JOIN t6 ON t6.t5_id=t5.id
WHERE t5.parent_id IN (1,2,3) AND t6.id IS NULL
);
Switching it to a join:-
UPDATE mytable
INNER JOIN
(
SELECT id
FROM t1
INNER JOIN t2 ON t2.t1_id=t1.id
LEFT OUTER JOIN t3 ON t3.t1_id=t2.id
WHERE t2.id IN (1,2,3)
AND t3.id IS NULL
UNION
SELECT id
FROM t4
INNER JOIN t5 ON t5.id=t4.t5_id
LEFT OUTER JOIN t6 ON t6.t5_id=t5.id
WHERE t5.parent_id IN (1,2,3)
AND t6.id IS NULL
) sub0
ON mytable.id = sub0.id
SET mytable.bla='xxx'

Union on simple MySQL recursion

Is there a way to do a UNION between the LEFT JOIN lines, so that the results are not in a separate columns (lev1, lev2, lev3 and lev4), but in a single column (i.e. "ItemNo")?
Here's the MySQL query:
SELECT t1.ItemID AS lev1, t2.ItemID as lev2, t3.ItemID as lev3, t4.ItemID as lev4
FROM TableOfRelations AS t1
LEFT JOIN TableOfRelations AS t2 ON t2.ParentItemID = t1.ItemID
LEFT JOIN TableOfRelations AS t3 ON t3.ParentItemID = t2.ItemID
LEFT JOIN TableOfRelations AS t4 ON t4.ParentItemID = t3.ItemID
WHERE t1.ParentItemID = (SELECT ID FROM TableOfItems WHERE ItemID = 3599);
EDIT:
Here is a sample of result I am looking for:
ItemID ParentItemID JoinedDescription1 JoinedDescription2
3599 NULL MyString1A MyString1B
35 3599 MyString35A MyString35B
168 3599 MyString168A MyString168B
192 168 MyString192A MyString192B
238 3599 MyString238A MyString238B
266 168 MyString266A MyString266B
This result will be used for filling up a TreeView using VB.NET. Also the "JoinedDescriptions" are yet to be joined from a different table according to ItemID, but I think I can handle that easily once I get the basic table correctly.
Important note: Those selected lines are only belonging to one item (root item "3599" in this example), meaning it's only few lines out of thousands. Some recursion examples presume that all the table lines are used in the query, which is not my case.
No, there's not really a way to do a UNION between the LEFT JOIN operations.
But you can use the resultset from your query to get the result you want, by turning your query into an inline view.
Here's one way:
SELECT u.i AS lev
, CASE u.i
WHEN 1 THEN t.lev1
WHEN 2 THEN t.lev2
WHEN 3 THEN t.lev3
WHEN 4 THEN t.lev4
END AS levItemID
FROM ( SELECT 1 AS i
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
) u
CROSS
JOIN ( SELECT t1.ItemID AS lev1
, t2.ItemID AS lev2
, t3.ItemID AS lev3
, t4.ItemID AS lev4
FROM TableOfItems t0
JOIN TableOfRelations t1
ON t1.ParentItemID = t0.id
LEFT
JOIN TableOfRelations t2
ON t2.ParentItemID = t1.ItemID
LEFT
JOIN TableOfRelations t3
ON t3.ParentItemID = t2.ItemID
LEFT
JOIN TableOfRelations t4
ON t4.ParentItemID = t3.ItemID
WHERE t0.ItemID = 3599
) t
Note: this is really more of a UNION ALL operation, it doesn't remove duplicates, it returns NULL values, and it returns the level of the parent.
You can tweak the query to get the results you want. If you don't care about the level number, remove the u.i from the SELECT list.
To remove duplicates, you can either add the DISTINCT keyword following SELECT, or add a GROUP BY clause. To eliminate NULL values, you can add a HAVING levItemID IS NOT NULL clause, etc.
I believe you are looking for concatenating strings.
See the Mysql Documentation on Concat:
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_concat
How about using a query as below.
select t1.ItemID as ItemNo
LEFT JOIN TableOfRelations AS t2 ON t2.ParentItemID = t1.ItemID
LEFT JOIN TableOfRelations AS t3 ON t3.ParentItemID = t2.ItemID
LEFT JOIN TableOfRelations AS t4 ON t4.ParentItemID = t3.ItemID
WHERE t1.ParentItemID = (SELECT ID FROM TableOfItems WHERE ItemID = 3599)
UNION
select t2.ItemID as ItemNo
LEFT JOIN TableOfRelations AS t2 ON t2.ParentItemID = t1.ItemID
LEFT JOIN TableOfRelations AS t3 ON t3.ParentItemID = t2.ItemID
LEFT JOIN TableOfRelations AS t4 ON t4.ParentItemID = t3.ItemID
WHERE t1.ParentItemID = (SELECT ID FROM TableOfItems WHERE ItemID = 3599)
UNION
select t3.ItemID as ItemNo
LEFT JOIN TableOfRelations AS t2 ON t2.ParentItemID = t1.ItemID
LEFT JOIN TableOfRelations AS t3 ON t3.ParentItemID = t2.ItemID
LEFT JOIN TableOfRelations AS t4 ON t4.ParentItemID = t3.ItemID
WHERE t1.ParentItemID = (SELECT ID FROM TableOfItems WHERE ItemID = 3599)
UNION
select t4.ItemID as ItemNo
LEFT JOIN TableOfRelations AS t2 ON t2.ParentItemID = t1.ItemID
LEFT JOIN TableOfRelations AS t3 ON t3.ParentItemID = t2.ItemID
LEFT JOIN TableOfRelations AS t4 ON t4.ParentItemID = t3.ItemID
WHERE t1.ParentItemID = (SELECT ID FROM TableOfItems WHERE ItemID = 3599)
Assuming you mean that you want the itemID on leaf nodes (I see no mention of itemNo in your query)....
SELECT
IFNULL(t4.ItemID, IFNULL(t3.ItemID, IFNULL(t2.ItemID, t1.ItemId))
(+remainder of your query)

How to optimize IN constraint query?

Following is my query.
SELECT * FROM t1 WHERE t1.record_id IN (
SELECT t2.record_id FROM t2
INNER JOIN t3 ON CONCAT(t2.case_number,t2.courtfile_type) = CONCAT(t3.case_number,t3.courtfile_type))
It contain IN constraint which is taking lot of time to extract result from database.Database is huge obviously.
How can I optimize this query?
Try this:
USING JOIN
SELECT DISTINCT t1.*
FROM t1
INNER JOIN t2 ON t1.record_id = t2.record_id
INNER JOIN t3 ON t2.case_number = t3.case_number AND t2.courtfile_type = t3.courtfile_type
USING EXISTS
SELECT *
FROM t1
WHERE EXISTS (SELECT t2.record_id
FROM t2 INNER JOIN t3 ON t2.case_number = t3.case_number AND t2.courtfile_type = t3.courtfile_type
WHERE t1.record_id = t2.record_id )
Check the execution plan of the query using EXPLAIN keyword and do proper indexing on tables.