Join with column outside subquery - mysql

SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount
FROM database2.table
WHERE ids IN (t1.values)
) as t2
WHERE t1.id = 20;
I get an error, that t1.values inside the subquery is unknown column.

You need to rewrite your query and take inne where to join condition:
SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount
FROM database2.table
) as t2 ON t2.ids = t1.values
WHERE t1.id = 20;
Also, you don't use amount column, so what is the point of join?
Another issue, you don't have any join condition defined.
I think you need to read about joins in SQL first :)

It seems you are trying to join database2.table to your t1 based on t1.values list.
I added group by IDs in t2 since your using aggregation function. Then, not sure what's the purpose of your sum(amount)
SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount, ids
FROM database2.table
GROUP BY ids
) as t2 on t2.ids IN (t1.values)
WHERE t1.id = 20;

Related

SQL query very slow. How to improve without indexes?

I need to get data from multiple tables with a single query which gives approximately 10600 results (rows). The problem is that the query takes a very long time to execute. Like.. very long time.. 90 sec.
Is there any way I could improve the query without adding indexes? The tables are updated constantly (rows inserted, updated, deleted).
Here is the query:
SELECT
t1.ID
, t1.ref
, t1.type
, GROUP_CONCAT(DISTINCT t3.name) AS parish
, GROUP_CONCAT(DISTINCT t2.village) AS village
, GROUP_CONCAT(DISTINCT t2.code) AS code
, GROUP_CONCAT(DISTINCT t4.year) AS year
FROM table1 t1
LEFT OUTER JOIN table2 AS t2 ON t2.teade_ID = t1.ID
LEFT OUTER JOIN table3 AS t3 ON t2.parish_ID = t3.ID
LEFT OUTER JOIN table4 AS t4 ON t4.teade_ID = t1.ID
GROUP BY t1.ID, t1.ref, t1.type
ORDER BY t1.ID DESC
Any help is very much appriciated!
Plan A - Make the GROUP BY and ORDER BY match:
Normally an index is primarily used for the WHERE clause. But there is no filtering, so the index can move on to GROUP BY. What index(es) do you have? If you have PRIMARY KEY(id), then changing to simply this is likely to work:
GROUP BY t1.ID
ORDER BY t1.ID DESC
If there is trouble with ONLY_FULL_GROUP_BY, you might need
GROUP BY t1.ID, t1.ref, t1.type
ORDER BY t1.ID DESC, t1.ref DESC, t1.type DESC
In either case note how the GROUP BY and ORDER BY "match" each other. With this (unlike what you have), both clauses can be done in a single step. Hence no need to gather all the rows, do the grouping, then sort. Getting rid of the sort is where you would gain speed.
Plan B - Delay the access to the troublesome ref and type:
SELECT ID, t1x.ref, t1x.type
FROM (
SELECT
t1.ID
, GROUP_CONCAT(DISTINCT t3.name) AS parish
, GROUP_CONCAT(DISTINCT t2.village) AS village
, GROUP_CONCAT(DISTINCT t2.code) AS code
, GROUP_CONCAT(DISTINCT t4.year) AS year
FROM table1 t1
LEFT OUTER JOIN table2 AS t2 ON t2.teade_ID = t1.ID
LEFT OUTER JOIN table3 AS t3 ON t2.parish_ID = t3.ID
LEFT OUTER JOIN table4 AS t4 ON t4.teade_ID = t1.ID
GROUP BY t1.ID
) x
JOIN t1 AS t1x USING(ID)
ORDER BY t1.ID DESC
ORDER BY is ignored in the derived table; GROUP BY is not necessary in the outer table.
Plan C - Get rid of the GROUP BY on the assumption that ID is the PK:
SELECT ID, ref, type
( SELECT GROUP_CONCAT(DISTINCT t3.name)
FROM t3 WHERE t3.ID = t1.ID ) AS parish,
( ... ) AS ...,
( ... ) AS ...,
( ... ) AS ...
FROM t1
ORDER BY ID DESC
The subqueries have the same semantics as your original LEFT JOIN.
Your original query suffers from "explode-implode". First the JOINs gather all the parishes, etc, leading to a big intermediate table. Then the grouping shrinks it back to only what you needed. Plan C avoids that explode-implode, and hence the GROUP BY.
Furthermore, there won't be a sort because it can simply scan the table in reverse order.
Aggregate before joining:
SELECT t1.ID, t1.ref, t1.type,
t2.villages, t2.codes,
t3.villages, t4.years
FROM table1 t1 LEFT JOIN
(SELECT t2.teade_ID, GROUP_CONCAT(t2.code) AS codes,
GROUP_CONCAT(t2.village) as villages
FROM table2 t2
GROUP BY t2.teade_ID
) t2
ON t2.teade_ID = t1.ID LEFT JOIN
(SELECT t2.teade_ID, GROUP_CONCAT(t3.village) as villages
FROM table2 t2 JOIN
table3 t3
ON t2.parish_ID = t3.ID
GROUP BY t2.teade_ID
) t3
ON t3.teade_id = t.id LEFT JOIN
(SELECT GROUP_CONCAT(t4.year) AS year
FROM table4 t4
GROUP BY t2.teade_ID
) t4
ON t4.teade_ID = t1.ID
ORDER BY t1.ID DESC;
You might still need DISTINCT in the GROUP_CONCAT(). It is not clear from your question if this is still needed.
Why is this faster? Your version is generating a cross product of all the tables for each ID -- potentially greatly multiplying the size of the data. More data makes the GROUP BY slower.
Also note that there is no aggregation in the outer query.

how to return all the fields of table2 based upon the occurrence of the id in the table1

I have 2 tables, one is table1
and another is table 2
I want the result by a query, like
I have tried select id from table2 order by (select id from table1); but it is giving error.
You can join and sort. But you need a column that defines the ordering of the rows in table1. Let me assume that you have such column, and that is is called ordering_id.
select t2.*
from table2 t2
inner join table1 t1 on t1.id = t2.id
order by t1.ordering_id
You can even use a subquery in the order by clause:
select *
from table2 t2
order by (select t1.ordering_id from table1 t1 where t1.id = t2.id)
Join the two tables and then order the result.But for that you need to have some column for ordering and this does not seems to be the case. Syntax you are using for ordering will not work.
SELECT A.ID, B.NAME FROM TABLE1 A INNER JOIN TABLE2 B
ON(A.ID = B.ID) ORDER BY A.ID DESC
finally got the answer
select t2.*
from table2 t2
inner join table1 t1 on t1.id = t2.id;

Get id of the record having Min() value

I have a complex mysql query where one of the Select fields is Min(value). Since all the 'values' are unique, is there also a way to get found min value's row id along?
In other words if we simplify the query to this question, it is like this:
SELECT t1.name, MIN(t2.value) AS minval
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
GROUP BY id_user
How can i now know which t2.id was chosen for lowest t2.value for particular user? Thank you!
Use ROW_NUMBER() to find the first value of each id_user
You can replace * with the fields you need
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY t2.id_user ORDER BY t2.value) as rnk
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
) as X
WHERE X.rnk = 1
Maybe this simple, dont know how complex your statement is:
SELECT name,value,id
FROM(
SELECT t1.name,t2.value,t2.id
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
GROUP BY t2.id,id_user
ORDER BY t1.name,t2.id asc) as test
GROUP BY name;

MySQL UPDATE with subqueries and join

Hi i am new to subqueries and so not sure if i am doing right
I am happy with this
SELECT t2.cons, t1.date, t1.account_no FROM
(
SELECT date, account_no FROM tbl_consignment_x3
) t1
INNER JOIN
(
SELECT cons, date, account_no FROM
tbl_volume_analysis
) t2
ON t2.account_no=t1.account_no AND t2.date=t1.date
It gives me the results i want to use
So i was hoping something like this below would do what i want but i can't get the syntax right plus i'm not sure if my technique is completely wrong
UPDATE tbl_margin_all t3
(
SELECT t2.cons, t1.date, t1.account_no FROM
(
SELECT date, account_no FROM tbl_consignment_x3
) t1
INNER JOIN
(
SELECT cons, date, account_no FROM
tbl_volume_analysis
) t2
ON t2.account_no=t1.account_no AND t2.date=t1.date
)
SET t3.cons=t2.cons
WHERE t1.date=t3.date AND t1.account_no=t3.account_no
thanks
ADDITION:
First i do a total count of consignments for a particular date taken from consignment table that is then written in volume table with the date and account.. then from consignments table i want to write to each consignment that count that i did.
You need to join with the first subquery -- put JOIN after t3.
Actually, you don't need any of the subqueries at all, you can just join directly with the tables.
UPDATE tbl_margin_all AS t3
JOIN tbl_consignment_x3 AS t1 ON t1.date = t3.date AND t1.account_no=t3.account_no
JOIN tbl_volume_analysis AS t2 ON t2.account_no=t1.account_no AND t2.date=t1.date
SET t3.cons = t2.cons
It's the same in the SELECT query, it should be:
SELECT t2.cons, t1.date, t1.account_no
FROM tbl_consignment_x3 AS t1
JOIN tbl_volume_analysis AS t2
ON t2.account_no=t1.account_no AND t2.date=t1.date
Notice the comma after t3 for syntax
UPDATE tbl_margin_all_4000 t3,
(
SELECT cons, t1.date, t1.account_no FROM
(
SELECT date, account_no, consignment_no FROM tbl_consignment_x3_4000
) t1
INNER JOIN
(
SELECT cons, date, account_no FROM
tbl_volume_analysis_4000
) t2
ON t2.account_no=t1.account_no AND t2.date=t1.date
) as src
SET t3.cons=src.cons
WHERE t3.date=src.date AND t3.account_no=src.account_no
this query took 4 mins. i had tried the double joins as suggested kindly but that took 45 mins.

In MySQL, how to use a subquery to a left join statement?

I tried to count how many new tuples are in a subset of t2 as compared to t1 by
SELECT
COUNT(t2.id)
FROM (
(SELECT id, col1 FROM t2 WHERE col2=0 AND col3=0) AS t
LEFT OUTER JOIN
t1
ON
t.id=t1.id
)
WHERE
t1.id IS NULL;
The subset is defined by
(SELECT id, col1 FROM t2 WHERE col2=0 AND col3=0) AS t
But the above program doesn't seem to work, issuing errors.
There is no need to enclose the FROM clause in (). You are referencing t2.id in your aggregate COUNT(), but your SELECT list will only produce t.id from the subquery that encapsulates t2. This version addresses the source of your errors:
SELECT
COUNT(t.id) AS idcount
FROM
(SELECT id, col1 FROM t2 WHERE col2=0 AND col3=0) AS t
LEFT OUTER JOIN t1 ON t.id = t1.id
WHERE t1.id IS NULL
However:
Since your subquery is actually pretty simple, I believe it isn't necessary at all. The whole thing can be done with a LEFT JOIN:
SELECT
/* The equivalent of COUNT(*) in this context */
COUNT(t2.id) AS idcount
FROM
t2
LEFT OUTER JOIN t1 ON t2.id = t1.id
WHERE
t1.id IS NULL
AND (t2.col2 = 0 AND t2.col3 = 0)
are you sure you don't want to do COUNT(t.id)? t2 is in a subquery and is not available to the main query only t and t1 are available.
The problem is the alias. You have:
select count(t2.id)
But, t2 is defined in the subquery, so it is out of scope.
You want:
select count(t.id)