How do I inner join multiple tables? - mysql

I have tables A, B and C and I want to get matching values for from all tables (tables have different columns).
Table A (primary key = id)
+------+-------+
| id | name |
+------+-------+
| 1 | Ruby |
| 2 | Java |
| 3 | JRuby |
+------+-------+
Table B (pid is reference to A(id) - No primary key)
+------+------------+
| pid | name |
+------+------------+
| 1 | Table B |
+------+------------+
Table C (primary key = id, pid is reference to A(id))
+------+------+------------+
| id | pid | name |
+------+------+------------+
| 1 | 2 | Table C |
+------+------+------------+
So my below query returned nothing. Whats wrong here? Is it treated as AND when multiple inner joins present?
Select A.* from A
inner join B ON a.id = b.pid
inner join C ON a.id = c.pid;

As you first join
1 | Ruby | Table B
and then try to join Table C, there is no match for pid 2 in the aforementioned result, the result is therefore empty.

An inner join excludes everything that doesn't match. So after you joined against B, you were left with only one record (id=1). Your inner join against C doesn't have any matches from what's left, so you get nothing.
I suppose a union would do the trick:
select A.* from A join B on a.id = b.pid
union
select A.* from A join C on a.id = c.pid
Or there are other ways, like where a.id in (select pid from b) or a.id in (select pid from c)

When you inner-join like this, a single row from A needs to exist such that a.id = b.pid AND a.id = c.pid are true at the same time. If you examine the rows in your examples, you would find that there is a row in A for each individual condition, but no rows satisfy both conditions at once. That is why you get nothing back: the row that satisfies a.id = b.pid does not satisfy a.id = c.pid, and vice versa.
You could use an outer join to produce two results:
select *
from A
left outer join B ON a.id = b.pid
left outer join C ON a.id = c.pid;
a.id a.name b.pid b.name c.id c.pid c.name
1 | Ruby | 1 | Table B | NULL | NULL | NULL
2 | Java | NULL | NULL | 1 | 2 | Table C

Of course you return nothing!
Table A and B inner join returns 1st record of Table A (table A ID = 1)
then you join table C, there is no matching rows to join table C, and vice versa.

Related

Verify value of column in table is not equal to the sum of values of two columns in other tables

I have three tables, with the following schema;
Table A
id
b_id
amount
Table B
id
amount
Table C
id
a_id
fee_amount
Tables A and B are related directly, however, table C has a_id that may be NULL.
I am trying to put together an SQL query to return the rows whose value of A.amount != B.amount + C.amount.
So far I have this;
SELECT a.*
FROM a
LEFT OUTER JOIN b ON b.id = a.b_id
LEFT OUTER JOIN c ON c.a_id = a.id
WHERE a.amount > 5000 AND a.amount != (b.amount + c.fee_amount)
With a simple dataset like this;
Table A
| id | b_id | amount |
|----|------|--------|
| 1 | 1 | 50000 |
Table B
| id | amount |
|----|--------|
| 1 | 5000 |
Table C
| id | a_id | fee_amount |
|----|------|------------|
| 1 | 1 | 7000 |
And the query returns zero results. I'm pretty I've missed something, just not sure what it is.
I think you need to handle the NULLs by treating them as 0 - eg:
SELECT a.*
FROM a
LEFT OUTER JOIN b ON b.id = a.b_id
LEFT OUTER JOIN c ON c.a_id = a.id
WHERE a.amount > 5000 AND a.amount != (IFNULL(b.amount, 0) + IFNULL(c.fee_amount,0))
First, if only C can have the NULL value, then you are better off using the LEFT JOIN only for that table:
SELECT a.*
FROM a JOIN
b
ON b.id = a.b_id LEFT JOIN
c
ON c.a_id = a.id
WHERE a.amount > 5000 AND
a.amount <> (b.amount + COALESCE(c.fee_amount, 0)) ;
However, normally you have secondary tables like this because the tables can have multiple rows per a_id. If that is the case, you need some sort of aggregation.

How to select data across multiple MySQL tables with same ID

I had create two table (Table A and Table B) and try using INNER JOIN both table but the result will be in different row even the ID is same.
$sql = "SELECT * FROM Table A INNER JOIN Table B ON Table A.ID = Table B.ID";
Is there any mysql select to extract all the value with same ID in one row as shown in 'Result' table?
Code:
$sql =
"SELECT GROUP_CONCAT(ITEM1), GROUP_CONCAT(ITEM2)
FROM Table A INNER JOIN Table B
ON Table A.ID = Table B.ID
WHERE Table A.ID = Table B.ID ";
Image
You must group by id, type and use group_concat() only for the item columns.
From your sample data it seems like one of item1 or item2 in each row is null.
If this is the case then:
select
a.id, a.type,
group_concat(coalesce(b.item1, b.item2) order by b.sub_id) item
from tablea a inner join tableb b
on b.id = a.id
group by a.id, a.type
See the demo.
If they can be both null or both not null:
select
a.id, a.type,
group_concat(concat_ws(',', item1, item2) order by b.sub_id) item
from tablea a inner join tableb b
on b.id = a.id
group by a.id, a.type
See the demo.
Results:
| id | type | item |
| --- | --------- | --------------------------- |
| 1 | FRUIT | BANANA,PINEAPPLE,WATERMELON |
| 2 | VEGETABLE | SPINACH,CARROT |
| 3 | MEAT | CHICKEN |

select common element from various tables where all values are not null

I have 3 tables, A,B, and C. Each table has a common column, ID, plus other data.
I want to have all IDs that are in every table and where all data are not null.
What is the most efficent way to do it?
In my real case I have more than 5 tables.
Ex:
Table A
| ID | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 |
Table B
| ID | B_1 | B_2 | B_3 | B_4 |
Table C
| ID | C_1 | C_2 | C_3 | C_4 | C_5 | C_6 | C_7 | C_8 |
This query will take all the ID in common among the three tables.
SELECT distinct ID FROM A
where
exists(select 1 from B where A.ID = B.ID )
AND exists(select 1 from C where A.ID = C.ID );
This query will select ID in which all columns are non null :
SELECT ID
FROM A
WHERE A_1 IS NOT NULL AND A_2 IS NOT NULL AND A_3 IS NOT NULL AND A_4 IS NOT NULL AND A_5 IS NOT NULL;
(I hope there is a better query for this.)
Than I should have the same query for all tables.
And then join all together.
Is there a better solution?
This should work:
SELECT DISTINCT A.ID
FROM A
INNER JOIN B ON A.ID = B.ID AND B.value IS NOT NULL
INNER JOIN C ON A.ID = C.ID AND C.value IS NOT NULL
INNER JOIN D ON A.ID = D.ID AND D.value IS NOT NULL
INNER JOIN E ON A.ID = E.ID AND E.value IS NOT NULL
WHERE A.value IS NOT NULL
;
The downside of it is that if there are one or more one-to-many relationships the intermediate results could proverbially explode. A better solution MIGHT be more similar to your first example; but instead of using correlated EXISTS subqueries....
SELECT DISTINCT ID
FROM A
WHERE A.Value IS NOT NULL
AND A.ID IN (SELECT DISTINCT ID FROM B WHERE Value IS NOT NULL)
AND A.ID IN (SELECT DISTINCT ID FROM C WHERE Value IS NOT NULL)
AND A.ID IN (SELECT DISTINCT ID FROM D WHERE Value IS NOT NULL)
AND A.ID IN (SELECT DISTINCT ID FROM E WHERE Value IS NOT NULL)
...etc
The downside of this is you won't get any benefit from indexes on ID. If the "explosion" issue I mentioned isn't a concern, and ID is indexed on all or most of the tables, my first suggestion would likely be faster and more efficient.
Edit: Oh, I overlooked you meant multiple values in each table NOT NULL, but the same concept should apply, you'll just have to replace all the Value IS NOT NULL conditions with ANDed IS NOT NULL conditions on the appropriate columns.

Select * as well as count/sum from another table

I am trying to write a MySQL query to select all rows from table a, as well as information from table b, while also querying the count and sum of values in another table c, for each row of a.
I will try to break that down a bit better, here is a simplified version of my tables:
Table A
+---------+----------+-----------+
| id | name | bid |
+---------+----------+-----------+
| 1 | abc | 1 |
| 2 | def | 1 |
| 3 | ghi | 2 |
+--------------------------------+
Table B
+---------+----------+
| id | name |
+---------+----------+
| 1 | STAN |
| 2 | UCLA |
+--------------------+
Table C
+---------+----------+-----------+
| id | aid | cnumber |
+---------+----------+-----------+
| 1 | 1 | 40 |
| 2 | 1 | 20 |
| 3 | 2 | 10 |
| 4 | 3 | 40 |
| 5 | 3 | 20 |
| 6 | 3 | 10 |
+--------------------------------+
What I need is a query that will return rows containing
a.id | a.name | b.id | b.name | SUM(c.cnumber) | COUNT(c.cnumber)
I am not sure if such a thing is even possible in MySQL.
My current solution is trying to query A + B Left Join and then UNION with A + C Right Join. It's not giving me the results I'm looking for however.
Thanks.
edit:
current query re-written for this problem:
SELECT
a.id,
a.name,
b.id,
b.name
"somecolumn" as dummy_column
"somecolumn1" as dummy_column1
FROM a
LEFT OUTER JOIN b ON a.b.id = b.id
UNION
SELECT
"somecolumn" as dummy_column
"somecolumn1" as dummy_column1
"somecolumn2" as dummy_column2
"somecolumn3" as dummy_column3
COUNT(c.cnumber) AS ccount
SUM(c.cnumber) AS sum
FROM a
RIGHT OUTER JOIN c ON a.id = c.a.id;
Unfortunately MySQL doesn't have FULL OUTER JOIN, and this is my temporary work around, although I don't think it's even the proper idea.
My desired output is all the rows from table A with some info from table B, as well as their totaled inputs in table C.
edit2:
SELECT
a.id,
a.name,
b.id,
SUM(c.cnumber) as totalSum,
(SELECT count(*) FROM c as cc WHERE cc.aid = a.id) as totalCount
FROM
a
LEFT JOIN b ON a.bid = b.id
LEFT JOIN c ON c.aid = a.id;
For future similar questions, solution:
SELECT
a.id AS aid,
a.name,
b.id,
(SELECT SUM(c.rating) FROM c WHERE c.aid = aid) AS totalSum,
(SELECT COUNT(c.rating) FROM c WHERE c.aid = aid) AS totalCount
FROM
a
LEFT JOIN b ON a.bid = b.id;
Your query should be :-
SELECT
a.id,
a.name,
b.id,
(SELECT SUM(c.cnumber) FROM c as cd WHERE cd.aid = a.id) as totalSum,
(SELECT count(*) FROM c as cc WHERE cc.aid = a.id) as totalCount
FROM
a
LEFT JOIN b ON a.bid = b.id
LEFT JOIN c ON c.aid = a.id;
It may help you.
I have tried your example.
SELECT * ,
(SELECT SUM(cnumber) FROM `table_c` WHERE `table_c`.`iaid` = `table_a`.`id`),
(SELECT COUNT(cnumber) FROM `table_c` WHERE `table_c`.`a.id` = `table_a`.`id`)
FROM `table_a`,`table_b` WHERE `table_b`.`id` = `table_a`.`b.id`
i got the Following output.

Select unrelated ids on relate / lookup table

I have seen various examples for this, but I can't find a definitive example of how to return all rows from table_A that are not related to a row in table_B using relate table_A_B without a given value for either table_A.id or table_B.id. The closest matchs I can find to this are:
Get a list of A not related to one or more rows in B but without knowing which value in B is the issue.
Get a list of A not related to given B.
Get list of A with comma-separated field of unrelated B (not sure I saw that, but it seemed like one example could expand as such).
A list of As and Bs not related to each other but no indication of which is not related to the other.
I can also get a list of all potential A_B tuples with:
SELECT A.id, B.id FROM A
INNER JOIN B ON A.id <> B.id
And I could hypothetically use one of the EXCEPT workarounds (I think) against the relate table, but all attempts were unsuccessful and I imagine that once there are millions of potential combinations returned by that join it will be much less efficient anyway.
So given the table values:
A
id | name
1 | X
2 | y
3 | z
B
id | name
7 | e
8 | f
9 | g
A_B
id | a_id | b_id
1 | 1 | 7
2 | 1 | 8
3 | 1 | 9
1 | 2 | 7
2 | 2 | 8
1 | 3 | 7
Is there a query that would return:
A | B
2 | 9
3 | 8
3 | 9
Or even better:
A | B
y | g
z | f
z | g
Or is this asking for trouble?
Start with a cross join between A and B to get all possible pairs. Then do a left join to the relation table and choose where there is no match:
select driver.aID, driver.bID
from (select a.id as aID, b.id as bID
from table_A A cross join table_B B
) driver left outer join
table_A_B ab
on ab.aID = driver.aID and ab.bID = bID
where ab.aID is null
This works, assuming that the ids are never NULL.
I haven't tested the SQL so it might have syntax errors.
This version gets you the names:
select driver.aName, driver.bName
from (select a.id as aID, b.id as bID, a.name as aName, b.name as Bname
from table_A A cross join table_B B
) driver left outer join
table_A_B ab
on ab.aID = driver.aID and ab.bID = bID
where ab.aID is null