I want to do a full outer join in MySQL. Is this possible? Is a full outer join supported by MySQL?
You don't have full joins in MySQL, but you can sure emulate them.
For a code sample transcribed from this Stack Overflow question you have:
With two tables t1, t2:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
The query above works for special cases where a full outer join operation would not produce any duplicate rows. The query above depends on the UNION set operator to remove duplicate rows introduced by the query pattern. We can avoid introducing duplicate rows by using an anti-join pattern for the second query, and then use a UNION ALL set operator to combine the two sets. In the more general case, where a full outer join would return duplicate rows, we can do this:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.id IS NULL
The answer that Pablo Santa Cruz gave is correct; however, in case anybody stumbled on this page and wants more clarification, here is a detailed breakdown.
Example Tables
Suppose we have the following tables:
-- t1
id name
1 Tim
2 Marta
-- t2
id name
1 Tim
3 Katarina
Inner Joins
An inner join, like this:
SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
Would get us only records that appear in both tables, like this:
1 Tim 1 Tim
Inner joins don't have a direction (like left or right) because they are explicitly bidirectional - we require a match on both sides.
Outer Joins
Outer joins, on the other hand, are for finding records that may not have a match in the other table. As such, you have to specify which side of the join is allowed to have a missing record.
LEFT JOIN and RIGHT JOIN are shorthand for LEFT OUTER JOIN and RIGHT OUTER JOIN; I will use their full names below to reinforce the concept of outer joins vs inner joins.
Left Outer Join
A left outer join, like this:
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
...would get us all the records from the left table regardless of whether or not they have a match in the right table, like this:
1 Tim 1 Tim
2 Marta NULL NULL
Right Outer Join
A right outer join, like this:
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
...would get us all the records from the right table regardless of whether or not they have a match in the left table, like this:
1 Tim 1 Tim
NULL NULL 3 Katarina
Full Outer Join
A full outer join would give us all records from both tables, whether or not they have a match in the other table, with NULLs on both sides where there is no match. The result would look like this:
1 Tim 1 Tim
2 Marta NULL NULL
NULL NULL 3 Katarina
However, as Pablo Santa Cruz pointed out, MySQL doesn't support this. We can emulate it by doing a UNION of a left join and a right join, like this:
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
UNION
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
You can think of a UNION as meaning "run both of these queries, then stack the results on top of each other"; some of the rows will come from the first query and some from the second.
It should be noted that a UNION in MySQL will eliminate exact duplicates: Tim would appear in both of the queries here, but the result of the UNION only lists him once. My database guru colleague feels that this behavior should not be relied upon. So to be more explicit about it, we could add a WHERE clause to the second query:
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
UNION
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;
On the other hand, if you wanted to see duplicates for some reason, you could use UNION ALL.
Using a union query will remove duplicates, and this is different than the behavior of full outer join that never removes any duplicates:
[Table: t1] [Table: t2]
value value
----------- -------
1 1
2 2
4 2
4 5
This is the expected result of a full outer join:
value | value
------+-------
1 | 1
2 | 2
2 | 2
Null | 5
4 | Null
4 | Null
This is the result of using left and right join with union:
value | value
------+-------
Null | 5
1 | 1
2 | 2
4 | Null
SQL Fiddle
My suggested query is:
select
t1.value, t2.value
from t1
left outer join t2
on t1.value = t2.value
union all -- Using `union all` instead of `union`
select
t1.value, t2.value
from t2
left outer join t1
on t1.value = t2.value
where
t1.value IS NULL
The result of the above query that is as the same as the expected result:
value | value
------+-------
1 | 1
2 | 2
2 | 2
4 | NULL
4 | NULL
NULL | 5
SQL Fiddle
#Steve Chambers: [From comments, with many thanks!]
Note: This may be the best solution, both for efficiency and for generating the same results as a FULL OUTER JOIN. This blog post also explains it well - to quote from Method 2: "This handles duplicate rows correctly and doesn’t include anything it shouldn’t. It’s necessary to use UNION ALL instead of plain UNION, which would eliminate the duplicates I want to keep. This may be significantly more efficient on large result sets, since there’s no need to sort and remove duplicates."
I decided to add another solution that comes from full outer join visualization and math. It is not better than the above, but it is more readable:
Full outer join means (t1 ∪ t2): all in t1 or in t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: all in both t1 and t2 plus all in t1 that aren't in t2 and plus all in t2 that aren't in t1:
-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value
union all -- And plus
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)
union all -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)
SQL Fiddle
None of the previous answers are actually correct, because they do not follow the semantics when there are duplicated values.
For a query such as (from this duplicate):
SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;
The correct equivalent is:
SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION -- This is intentionally UNION to remove duplicates
SELECT name FROM t2
) n LEFT JOIN
t1
ON t1.name = n.name LEFT JOIN
t2
ON t2.name = n.name;
If you need this to work with NULL values (which may also be necessary), then use the NULL-safe comparison operator, <=> rather than =.
MySQL does not have FULL-OUTER-JOIN syntax. You have to emulate it by doing both LEFT JOIN and RIGHT JOIN as follows:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
But MySQL also does not have a RIGHT JOIN syntax. According to MySQL's outer join simplification, the right join is converted to the equivalent left join by switching the t1 and t2 in the FROM and ON clause in the query. Thus, the MySQL query optimizer translates the original query into the following -
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
Now, there is no harm in writing the original query as is, but say if you have predicates like the WHERE clause, which is a before-join predicate or an AND predicate on the ON clause, which is a during-join predicate, then you might want to take a look at the devil; which is in details.
The MySQL query optimizer routinely checks the predicates if they are null-rejected.
Now, if you have done the RIGHT JOIN, but with WHERE predicate on the column from t1, then you might be at a risk of running into a null-rejected scenario.
For example, the query
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
gets translated to the following by the query optimizer:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'
So the order of tables has changed, but the predicate is still applied to t1, but t1 is now in the 'ON' clause. If t1.col1 is defined as NOT NULL
column, then this query will be null-rejected.
Any outer-join (left, right, full) that is null-rejected is converted to an inner-join by MySQL.
Thus the results you might be expecting might be completely different from what the MySQL is returning. You might think its a bug with MySQL's RIGHT JOIN, but that’s not right. Its just how the MySQL query optimizer works. So the developer in charge has to pay attention to these nuances when he/she is constructing the query.
I modified shA.t's query for more clarity:
-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value
UNION ALL -- include duplicates
-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t1.value IS NULL
In SQLite you should do this:
SELECT *
FROM leftTable lt
LEFT JOIN rightTable rt ON lt.id = rt.lrid
UNION
SELECT lt.*, rl.* -- To match column set
FROM rightTable rt
LEFT JOIN leftTable lt ON lt.id = rt.lrid
You can do the following:
(SELECT
*
FROM
table1 t1
LEFT JOIN
table2 t2 ON t1.id = t2.id
WHERE
t2.id IS NULL)
UNION ALL
(SELECT
*
FROM
table1 t1
RIGHT JOIN
table2 t2 ON t1.id = t2.id
WHERE
t1.id IS NULL);
You can just convert a full outer join, e.g.
SELECT fields
FROM firsttable
FULL OUTER JOIN secondtable ON joincondition
into:
SELECT fields
FROM firsttable
LEFT JOIN secondtable ON joincondition
UNION ALL
SELECT fields (replacing any fields from firsttable with NULL)
FROM secondtable
WHERE NOT EXISTS (SELECT 1 FROM firsttable WHERE joincondition)
Or if you have at least one column, say foo, in firsttable that is NOT NULL, you can do:
SELECT fields
FROM firsttable
LEFT JOIN secondtable ON joincondition
UNION ALL
SELECT fields
FROM firsttable
RIGHT JOIN secondtable ON joincondition
WHERE firsttable.foo IS NULL
SELECT
a.name,
b.title
FROM
author AS a
LEFT JOIN
book AS b
ON a.id = b.author_id
UNION
SELECT
a.name,
b.title
FROM
author AS a
RIGHT JOIN
book AS b
ON a.id = b.author_id
I fix the response, and works include all rows (based on the response of Pavle Lekic):
(
SELECT a.* FROM tablea a
LEFT JOIN tableb b ON a.`key` = b.key
WHERE b.`key` is null
)
UNION ALL
(
SELECT a.* FROM tablea a
LEFT JOIN tableb b ON a.`key` = b.key
where a.`key` = b.`key`
)
UNION ALL
(
SELECT b.* FROM tablea a
right JOIN tableb b ON b.`key` = a.key
WHERE a.`key` is null
);
Use:
SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;
It can be recreated as follows:
SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
LEFT JOIN t1 ON t1.id = tmp.id
LEFT JOIN t2 ON t2.id = tmp.id;
Using a UNION or UNION ALL answer does not cover the edge case where the base tables have duplicated entries.
Explanation:
There is an edge case that a UNION or UNION ALL cannot cover. We cannot test this on MySQL as it doesn't support full outer joins, but we can illustrate this on a database that does support it:
WITH cte_t1 AS
(
SELECT 1 AS id1
UNION ALL SELECT 2
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 6
),
cte_t2 AS
(
SELECT 3 AS id2
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 6
)
SELECT * FROM cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;
This gives us this answer:
id1 id2
1 NULL
2 NULL
NULL 3
NULL 4
5 5
6 6
6 6
6 6
6 6
The UNION solution:
SELECT * FROM cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION
SELECT * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
Gives an incorrect answer:
id1 id2
NULL 3
NULL 4
1 NULL
2 NULL
5 5
6 6
The UNION ALL solution:
SELECT * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
Is also incorrect.
id1 id2
1 NULL
2 NULL
5 5
6 6
6 6
6 6
6 6
NULL 3
NULL 4
5 5
6 6
6 6
6 6
6 6
Whereas this query:
SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
LEFT JOIN t1 ON t1.id = tmp.id
LEFT JOIN t2 ON t2.id = tmp.id;
Gives the following:
id1 id2
1 NULL
2 NULL
NULL 3
NULL 4
5 5
6 6
6 6
6 6
6 6
The order is different, but otherwise matches the correct answer.
Use a cross join solution:
SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2
ON 1=1;
It is also possible, but you have to mention the same field names in select.
SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id
The SQL standard says full join on is inner join on rows union all unmatched left table rows extended by nulls union all right table rows extended by nulls. Ie inner join on rows union all rows in left join on but not inner join on union all rows in right join on but not inner join on.
Ie left join on rows union all right join on rows not in inner join on. Or if you know your inner join on result can't have null in a particular right table column then "right join on rows not in inner join on" are rows in right join on with the on condition extended by and that column is null.
Ie similarly right join on union all appropriate left join on rows.
From What is the difference between “INNER JOIN” and “OUTER JOIN”?:
(SQL Standard 2006 SQL/Foundation 7.7 Syntax Rules 1, General Rules 1 b, 3 c & d, 5 b.)
Related
I searched around and found a near example to what I'm looking for, but it doesn't work in my case.
I have a query that does an INNER JOIN on two tables and this join constrains my overall data set substantially. I then want to LEFT JOIN onto a third table but I only want one record from that third table. The reason for the left join is because not every result of the INNER JOIN has a match in the 3rd table. Something like this:
SELECT DISTINCT t1.code, t2.id, t2.code, t3.id, t3.source_title, t3.display_order
FROM table1 t1
INNER JOIN table2 t2 ON t2.code=t1.code AND t2.type=0
LEFT JOIN table3 t3 ON t3.code=t1.code
ORDER BY t1.code, t3.display_order
This query returns too many records because the third table contains multiple records with a matching code. I just want the first one that matches with the lowest display_order value and, unfortunately, I can't limit the records to have display_order=1 because the lowest display order is not always one.
IMPORTANT: The t3.id value (if any) returned by this query must correspond to the record with the lowest display_order value. I.e., it won't work if the query correctly returns the lowest display_order value but the t3.id value corresponds to some other record in table 3.
Is this even possible? Any help would be much appreciated.
EDIT: Per Nick's suggestion, I have tried this, which appears to be working. I'll do some verification and report back:
SELECT DISTINCT t1.code, t2.*, sq.id, sq.source_title, sq.display_order
FROM table1 t1
INNER JOIN table2 p ON t2.code=t1.code AND t2.type=0
LEFT JOIN (
SELECT t3.*
FROM table3 t3
WHERE t3.display_order=(
SELECT MIN(display_order)
FROM table3 t3a
WHERE t3a.code = t3.code
)
) sq ON sq.code=t1.code
ORDER BY t1.code, sq.display_order
You should be able to replace table3 in your LEFT JOIN with
(SELECT *
FROM table3 t3
WHERE display_order = (SELECT MIN(display_order)
FROM table3 t3a
WHERE t3a.code = t3.code)
) t3
In MySQL 8.0 you can try to use row_number() for each code and ordered by display_order in a subquery from table3. Then left join that result and check for the row_number() to be equal to 1.
SELECT DISTINCT
t1.code,
t2.id,
t2.code,
t3.id,
t3.source_title,
t3.display_order
FROM table1 t1
INNER JOIN table2 t2
ON t2.code = t1.code
LEFT JOIN (SELECT t3.id,
t3.source_title,
t3.display_order,
t3.code,
row_number() OVER (PARTITION BY t3.code
ORDER BY t3.display_order) rn
FROM table3 t3) t3
ON t3.code = t1.code
WHERE t2.type = 0
AND t3.rn = 1
ORDER BY t1.code,
t3.display_order;
In lower versions you can try correlated subqueries ordered by display_order and LIMIT 1 (to get only one record).
SELECT DISTINCT
t1.code,
t2.id,
t2.code,
(SELECT t3.id
FROM table3 t3
WHERE t3.code = t1.code
ORDER BY t3.display_order,
t3.id
LIMIT 1) id,
(SELECT t3.source_title
FROM table3 t3
WHERE t3.code = t1.code
ORDER BY t3.display_order,
t3.id
LIMIT 1) source_title,
(SELECT t3.display_order
FROM table3 t3
WHERE t3.code = t1.code
ORDER BY t3.display_order,
t3.id
LIMIT 1) display_order
FROM table1 t1
INNER JOIN table2 t2
ON t2.code = t1.code
WHERE t2.type = 0
ORDER BY t1.code,
(SELECT t3.display_order
FROM table3 t3
WHERE t3.code = t1.code
ORDER BY t3.display_order,
t3.id
LIMIT 1);
I assumed, that display_order in table3 isn't unique but id is. So I added id to the ORDER BY clauses in the subqueries to make sure the same record is selected in each of them. If display_order is unique, you can remove id FROM the ORDER BY clauses.
Edit:
If you don't want to repeat the subqueries in the (overall) ORDER BY clause, you can also order by the column ordinals. E.g.:
...
ORDER BY 1, 6;
I created 2 simple table. tableA and table B, both only have 1 column 'po'.
I am trying to combine the 2 table together using FULL OUTER JOIN.
The error output is Warning: mysqli_fetch_array() expects parameter 1 to be mysqli_result.
So I guess pretty much my query is wrong. Appreciate any help here!
<?php
include 'db.php';
$sqlcount="SELECT DISTINCT po FROM testonly FULL OUTER JOIN testonly2 ON testonly.po=testonly2.po";
$resultcount = mysqli_query($conn,$sqlcount);
while($row = mysqli_fetch_array($resultcount)){
echo $row['po'];
}
?>
There is no FULL OUTER JOIN built in with MySQL. But, you could simulate your query via:
SELECT * FROM testonly t1
LEFT JOIN testonly2 t2 ON t1.po = t2.po
UNION -- use UNION ALL to retain common rows
SELECT * FROM testonly t1
RIGHT JOIN testonly2 t2 ON t1.po = t2.po
PHP code:
$sqlcount = "SELECT * FROM testonly t1 LEFT JOIN testonly2 t2 ON t1.po = t2.po UNION ALL SELECT * FROM testonly t1 RIGHT JOIN testonly2 t2 ON t1.po = t2.po";
Read here for more information: Full Outer Join in MySQL
if you need an united table you need and union You can't use FULL OUTER JOIN because this is not available in mysql ..but yuo can emulate with and an union select
The union clause implies that only distint value are merged for the two table ..
$sqlcount="SELECT po
FROM testonly
UNION
testonly2 ";
the union all implies the select of all the rows (also duplicated) from both the tables
$sqlcount="SELECT po
FROM testonly
UNION ALL
testonly2 ";
otherwise if you need a real join (bothe the column on the same rows ) you can use JOIN (inner join .. or left join, or right ) depending the way you need join the table
this is for inner join
$sqlcount="SELECT DISTINCT t1.po, t2.po
FROM testonly t1 INNER JOIN testonly2 t2 ON testonly.po=testonly2.po";
The database I am working on right now is somewhat messy. I have three potential tables, that I want to join but in some cases it may only be two tables.
Let's call these table1, table2 and table3.
table1 has a field called "type". If table1.type is 2, then I only need to join table3.
For any other values I want to join table2 and then table3.
How can I achieve this in one single SQL query rather than: 1) having one query to select the type. 2) make a PHP foreach-loop to check the type of the current iteration and 3) perform a new query according to the type value.
Edit:
I'll try to be more specific.
table1 has a column named "pid" that references to a whole other table, but that's redundant to this question. I tried working my ways around with UNIONs and LEFT JOINs but couldn't manage to achieve what I was looking for.
I want to select all results from my database with the "pid" value being "100". This gives me four rows in return, where was 2 of them are of type value "2" and the others are "1".
So basically what I want to achieve is the following two SQL statements in one:
(If "type" is "2")
SELECT *
FROM table1 t1
INNER JOIN table3 t3
ON t1.id = t3.t1_id
WHERE t1.pid = 100
(If "type" is NOT "2")
SELECT *
FROM table1 t1
INNER JOIN table2 t2
ON t1.id = t2.t1_id
INNER JOIN table3 t3
ON t2.id = t3.t2_id
WHERE t1.pid = 100
I'm guessing I could manage to do this with a UNION statement, but I'm confused on how to implement the WHERE t1.pid = '100' part.
use an UNION e.g.
SELECT t1.*, t3.*
FROM table1 t1
INNER JOIN table3 t3 ON t1.id = t3.t1_id
WHERE t1.pid = 100 and t1.type = 2
UNION
SELECT t1.*, t3.*
FROM table1 t1
INNER JOIN table2 t2
ON t1.id = t2.t1_id
INNER JOIN table3 t3 ON t2.id = t3.t2_id
WHERE t1.pid = 100 and t1.type <> 2;
but it would be better to explicitly name the columns you want to get back.
I have a query on my PHP script it takes too long time!
When I run the query, server load time increase and server goes down!
Note: these fields are index: t1.submits_id,t4.submit_id,t3.userid,t1.user_id,owner_id,invited_id,agreed,t2.users_id,,t1.sent_timestamp
SELECT
t1.submits_id,t1.user_id,is_html,shared_from,type,contents,url,sent_timestamp,show_type,album_cached_info,
t2.users_id,name,t2.active,page_url,
t3.time,
t4.like_time
FROM iv6_submits as t1 LEFT JOIN iv6_likes as t4 ON (t1.submits_id = t4.submit_id AND t4.user_id=1)
,iv6_users as t2 LEFT JOIN iv6_onlineusers as t3 ON (t2.users_id=t3.userid)
WHERE
t1.submits_id<19000 AND
(t1.user_id=1 OR t1.user_id in
(select IF(owner_id=1,invited_id,owner_id) as id
from iv6_add_lists
where ((owner_id=1 or invited_id=1) AND agreed=1) OR (owner_id=1 AND agreed=2)))
AND t2.users_id=t1.user_id
ORDER BY t1.sent_timestamp DESC LIMIT 10
I'd start by writing the query as:
SELECT t1.submits_id,
t1.user_id,
is_html, /* I'd append all table aliases here */
shared_from,
type,
contents,
url,
sent_timestamp,
show_type,
album_cached_info,
t2.users_id,
name,
t2.active,page_url,
t3.time,
t4.like_time
FROM iv6_submits as t1
JOIN iv6_users as t2
ON t2.users_id=t1.user_id
LEFT JOIN iv6_likes as t4
ON t4.submit_id = t1.submits_id
AND t4.user_id=1
LEFT JOIN iv6_onlineusers as t3
ON t3.userid = t2.users_id
WHERE t1.submits_id<19000
AND (
t1.user_id=1
OR t1.user_id IN (
SELECT IF(owner_id=1,invited_id, owner_id) as id
FROM iv6_add_lists
WHERE ((owner_id=1 OR invited_id=1) AND agreed=1)
OR (owner_id=1 AND agreed=2))
)
ORDER BY t1.sent_timestamp DESC
LIMIT 10
From this and your explain i'd guess that t1.submits_id< 19000 reduces your result set the most. So I'd then try:
...
FROM iv6_submits as t1 USE INDEX (submits_id)
...
Your subquery is also v. strange, i'd rewrite it as something like:
SELECT invited_id
FROM iv6_add_lists
WHERE owner_id = 1
AND agreed BETWEEN 1 AND 2
UNION ALL
SELECT owner_id
FROM iv6_add_lists
WHERE invited_id = 1
AND agreed = 1
AND owner_id != 1
And see if that helps as well, you can hint an index for each FROM. A composite index on (owner_id, agreed, invited_id) and (invited_id, agreed, owner_id) should cover both queries respectively.
You also could write this as
SELECT 1
UNION
SELECT DISTINCT invited_id
FROM iv6_add_lists
WHERE owner_id = 1
AND agreed BETWEEN 1 AND 2
UNION
SELECT DISTINCT owner_id
FROM iv6_add_lists
WHERE owner_id != 1
AND agreed = 1
AND invited_id = 1
And JOIN it to your t1 instead of the AND (t1.user_id=1 OR ...)
UPDATE
SELECT t1.submits_id,
t1.user_id,
is_html, /* I'd append all table aliases here */
shared_from,
type,
contents,
url,
sent_timestamp,
show_type,
album_cached_info,
t2.users_id,
name,
t2.active,page_url,
t3.time,
t4.like_time
FROM iv6_submits as t1
JOIN iv6_users as t2
ON t2.users_id=t1.user_id
JOIN (
SELECT 1 user_id
UNION
SELECT DISTINCT invited_id
FROM iv6_add_lists
WHERE owner_id = 1
AND agreed BETWEEN 1 AND 2
UNION
SELECT DISTINCT owner_id
FROM iv6_add_lists
WHERE owner_id != 1
AND agreed = 1
AND invited_id = 1
) t5
ON t1.user_id = t5.user_id
LEFT JOIN iv6_likes as t4
ON t4.submit_id = t1.submits_id
AND t4.user_id=1
LEFT JOIN iv6_onlineusers as t3
ON t3.userid = t2.users_id
WHERE t1.submits_id<19000
ORDER BY t1.sent_timestamp DESC
LIMIT 10
I suggest you split the query to see where the resources are being consumed.
Execute the subquery in the WHERE section and see if it runs fast
Remove the left joins and then add one by one to see where it all goes down.
Remove all the "WHERE" conditions and add one by one.
Try to run the query without the "ORDER BY" statement.
You did not referred t4.user_id as being indexed, it may be important.
Table iv6_add_lists also should have all the fields present in WHERE statement indexed.
Also suggest you to make an INNER JOIN between t1 and t2:
FROM (iv6_submits as t1
LEFT JOIN iv6_likes as t4 ON (t1.submits_id = t4.submit_id AND t4.user_id=1))
INNER JOIN
(iv6_users as t2
LEFT JOIN iv6_onlineusers as t3 ON (t2.users_id=t3.userid))
ON t2.users_id=t1.user_id
Then ou can remove
AND t2.users_id=t1.user_id
from the WHERE statement.
Try This.
SELECT
t1.submits_id,t1.user_id,is_html,shared_from,type,contents,url,sent_timestamp,show_type,album_cached_info,
t2.users_id,name,t2.active,page_url,
t3.time,
t4.like_time
FROM
iv6_submits as t1
LEFT JOIN iv6_users as t2 ON t2.users_id = t1.user_id
LEFT JOIN iv6_likes as t4 ON t1.submits_id = t4.submit_id AND t4.user_id = 1
LEFT JOIN iv6_onlineusers as t3 ON t2.users_id = t3.userid
WHERE
t1.submits_id < 19000
AND
(t1.user_id = 1 OR t1.user_id in
(
select IF(owner_id=1,invited_id,owner_id) as id from iv6_add_lists where (invited_id=1 AND agreed=1) OR ( owner_id=1 AND agreed IN (1,2) )
)
)
ORDER BY t1.sent_timestamp DESC LIMIT 1
i have seen how to inner join 2 tables where a column is equal to the content in another column. but how do i do this with 7 tables?'
thanks everyone,
I figured it out lol after a long time. this seems to work
SELECT *
FROM
tbl_school
INNER JOIN tbl_apprequirments ON (tbl_school.schoolname = tbl_apprequirments.schoolname)
INNER JOIN tbl_citygallery ON (tbl_apprequirments.schoolname = tbl_citygallery.schoolname)
INNER JOIN tbl_schoolgallery ON (tbl_citygallery.schoolname = tbl_schoolgallery.schoolname)
INNER JOIN tbl_livingexp ON (tbl_schoolgallery.schoolname = tbl_livingexp.schoolname)
INNER JOIN tbl_tuition ON (tbl_livingexp.schoolname = tbl_tuition.schoolname)
where tbl_school.schoolname = 'glendale community college';
SELECT * FROM t1 JOIN t2 JOIN t3 JOIN t4 JOIN t5
ON (t2.c=t1.c AND t3.c=t1.c AND t4.c=t1.c AND t5.c=t1.c)
MySQL provides a shorthand for this:
SELECT * FROM t1 JOIN (t2, t3, t4, t5)
ON (t2.c=t1.c AND t3.c=t1.c AND t4.c=t1.c AND t5.c=t1.c)
This example is for 5 tables. You can repeat as necessary.
See MySQL's join syntax.
Edit: after seeing the clarification from sarmenhb, I think this query also works:
SELECT * FROM t1 JOIN (t2, t3, t4, t5, t6, t7)
USING (schoolname)
WHERE t1.schoolname = 'name'
After joining 2 of them, join the thrid to the first two, then the 4th to the first 3, etc,
Select *
From T1 Join T2 On <criteria>
Join T3, on <criteria>
Join T4 On <Criteria>
etc...
Try something like this...
Select data
from table as tbl1
join as tbl2 on tbl2.data = tbl1.data
join as tbl3 on tbl3.data = tbl1.data
is this what you are looking for?