select if join one table else join other table - mysql

There are 3 tables. Lets call them a, b and c. Selected data from table a must be intersected with b or c depending of value of one cell in table a. Lets call this cell d. Is there way in MySQL to make query like:
SELECT
a.cell,
a.other_cell,
a.d,
alias.cell,
alias.other_cell if(
a.d = 3,
left join b as alias on b.id = a.id,
left join c as alias on c.id = a.id
)
FROM
a where a.id = 123

You can try for example Conditional join as here but instead coalesce, use CASE WHEN
In short:
Instead, you simply LEFT OUTER JOIN to both tables, and in your SELECT clause, return data from the one that matches
select
E.EmployeeName,
CASE
WHEN d = 3 THEN s.store
WHEN d <>3 THEN o.office
END as Location
from
Employees E
left outer join
Stores S on …
left outer join
Offices O on …
NOTE I think the two columns must have the same type, at least in PG, not sure about MYSQL

Assuming you want select from the different tables (b and c) based on a 'cell' value in
table a then something like this work may work for you.
SELECT
a.cell,
a.other_cell,
a.d,
if(a.d = 3, b.cell, c.cell) cell
FROM a
INNER JOIN b on b.id = a.id
INNER JOIN c on c.id = a.id
WHERE a.id = 123
This should join the all 3 tables provided the id in b and c also match the id in table a. The if function will select the cell column from table b or c based on the value of column d in table a.
Also helpful: https://www.w3resource.com/mysql/control-flow-functions/if-function.php

Related

Join three tables A, B, C and return common in A in mysql

I want to join below three tables A, B, C and return only common(shaded) part of table A
A
-------
ID, Name
B
-------
ID, ORG
C
--------
ID, DEP
Please anyone provide simple join query
I understand that you want rows from a whose id can be foud in either b or c.
This sounds like two exists subquery:
select a.*
from a
where
exists (select 1 from b where b.id = a.id)
or exists (select 1 from c where c.id = a.id)
If you also want columns from tables b or c, you can use two left joins instead, with a where condition that ensures that at least one of the joins did succeed:
select a.*, b.org, c.dept
from a
left join b on b.id = a.id
left join c on c.id = a.id
where b.id is not null or c.id is not null
You want a left join starting with A and then some filtering:
select . . .
from a left join
b
on . . . left join
c
on . . .
where b.? is not null or c.? is not null;
The ? are either columns used in the joins or primary keys on the respective tables.

Query for rows that share a set of associations

I have three tables: A, B, C. B has a many-to-many relationship with A and C.
A >-< B >-< C
Assume every table has a primary key column called id, and the join tables have two columns [a_id, b_id] and [b_id, c_id].
The same row in B can be linked to both rows in A and C. It's fairly straightforward to find rows in C that share a specific row in B (a series of inner joins).
Given a row id of A, I would like to query for all rows in C that share ALL rows of B associated with that row in A:
select id,
(select count(*) from c
inner join b_c on c.id = b_c.c_id
) as c_group,
(select count(*) from c
inner join b_c on c.id = b_c.c_id
inner join b on b.id = b_c.b_id
inner join a_b on b.id = a_b.b_id
where a_id = ?
) as a_c_group
from c
where c_group <= a_c_group;
Can this be done via SQL? I'm working in MySQL, so a MySQL-specific solution would be fine.
This would yield all the id's for B that are associated with the selected A:
SELECT b_id FROM ab WHERE a_id = ?
So you need to find any C's that are related to only these B id's and not others. This can be done by excluding all C's that match other B id's:
SELECT c.id
FROM c
LEFT JOIN bc ON c.id = bc.c_id
AND bc.b_id NOT IN (SELECT b_id FROM ab WHERE a_id = ?)
WHERE bc.c_id IS NULL
If I understand your question correctly, you want all rows in C that have a matching row in B that, in turn, match the specified row id in A.
This should do it:
select
c.*
from
c
join bc on c.id = bc.c_id
where
exists (select 1
from ab
where ab.a_id = 123
and ab.b_id = bc.b_id)
This assumes that your join (bridge) tables are named ab and bc, and that you're looking for an a.id of 123
SQLFiddle here
Solution was to compare the count of an inner join of B and C with a inner join of all three tables.
SELECT ID
FROM C
WHERE (
SELECT COUNT(*)
FROM B_C
WHERE C_ID = C.ID
) <= (
SELECT COUNT(*)
FROM B_C INNER JOIN A_B ON B_C.B_ID = A_B.B_ID
WHERE C_ID = C.ID AND A_ID = ?
);
This covers:
If C has no associated B's, it should appear in the result set.
If C has associated B's not associated with A, it does not appear in the result set.
If A has associated B's not associated with C, but all B's C is associated with, C appears in the result set.

Join MySQL tables based on condition?

Problem:
I'm trying to figure out how to join tables based on a condition in an SQL statement. I've spent an hour searching Google, SO, various websites and the MYSQL manual, but I just can't find the correct syntax for what I want to do.
I can't post the exact query I'm trying to get working, but I will post a simplified version for simplicity reasons.
Scenario:
Assuming I have three tables, a = person table, b = address table and c = car table.
Table b will always be joined to table a, becuase a person always lives at an address, but table c should only be joined to a if the value in the 'car_id' field is more than 0, because having a car is optional.
The query:
SELECT a.firstname, a.lastname, a.gender, a.address_id, b.address_firstline, b_address_secondline, b.postcode, c.car_manufacturer, c.car_model
FROM a
INNER JOIN b ON b.id = a.address_id
INNER JOIN c ON c.id = a.car_id AND a.car_id > 0
WHERE a.id = 1
The query above will run fine for a person with the id of 1 because he owns a car. However, if the query is run for a person with the id of 2, the query will return 0 rows because she does not own a car.
How do I make this second JOIN optional? I've tried using the IF ELSE statement, but I'm forever getting syntax errors. Could someone point me in the right direction here? Thanks in advance
You should use left outer join to join c with a.
SELECT a.firstname, a.lastname, a.gender, a.address_id, b.address_firstline, b_address_secondline, b.postcode, c.car_manufacturer, c.car_model
FROM a
INNER JOIN b ON b.id = a.address_id
LEFT OUTER JOIN c ON c.id = a.car_id AND a.car_id > 0
WHERE a.id = 1
Use LEFT JOIN instead of INNER JOIN on table c.
Unilateral joins work on this scenario.
A brief explanation.
a INNER JOIN b ON a.field1 = b.field1 returns every row for which both a.field1 and b.field1 exist and are equal
a LEFT JOIN b ON a.field1 = b.field1 returns every row from table a and returns every row in table b for which a.field1 = b.field1, and null values for non-matching values on table b.
RIGHT JOIN is analogous to LEFT JOIN

Mysql inner joins advanced, howto

Can anyone help me with this query?
I have three tables (A;B;C)
A <--1....N---> B <--1....N---> C
I want all A rows having C.dates (the greatest)
SELECT A.*, MAX(C.dates)
FROM A
JOIN B ON B.A_fk = A.id
JOIN C ON C.B_fk = B.id
GROUP BY A.id
This JOIN will exclude results which wont have LEFT join. That is, if any row from A wont have B row or any row from B wont have any C row, then the row wont show. To overcome this you can use LEFT JOIN instead of JOIN.
SELECT A.*, MAX(C.dates)
FROM A
LEFT JOIN B ON B.A_fk = A.id
LEFT JOIN C ON C.B_fk = B.id
GROUP BY A.id
EDIT: Sorry didnt noticed that you needed the greatest value of C.data. There you have it. You have to use MAX function in SELECT and GROUP BY A.id

MySQL LEFT RIGHT JOIN syntax fluency

I'm coming across this situation alot, I'll have a query that will have one table needed in a join condition that may have no entries therefore requiring me to use a LEFT JOIN. I can't wrap my head around the syntax when it's used with more than 1 join.
I'll have:
SELECT A.*, B.*, C.*
FROM A, B, C
WHERE A.id = C.id
AND C.aid = A.id
AND B.cid = C.id
Along comes D with the possibility of being empty and I have to rewrite the query and run into problems.
How can I simply join D to any one of these tables?
You're much better off explicitly specifying all of your JOINs. That should make things much clearer.
SELECT A.*, B.*, C.*, D.*
FROM A
INNER JOIN C
ON C.aid = A.id
INNER JOIN B
ON B.cid = C.id
LEFT JOIN D
ON C.did = d.id
My advice is to never specify more than one column on FROM clause.
For clarity, it's better to always:
Use JOIN clause
Use aliases
Specify columns of joined tables on left side of equal sign
Example:
SELECT a.*, b.*, c.*
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
Not sure about MySQL, but in some other SQL flavors, you can use the same on UPDATES and DELETES, like:
DELETE FROM a
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
or
UPDATE a
SET something = newValue
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
The syntax below should help you. The basic premise is whatever table is listed LEFT is the required.. the table (or alias) on the right is optional. I understand you don't quite get it, and your syntax sample shows that (not meant to criticize) as you are joining from A -> C and C back to A on a different field. If this is the case where two fields are in the "C" table that BOTH point to A, you would re-join to A as a second alias...
select
Want.*,
Maybe.*,
SecondA.*,
B.*
From
A as Want
LEFT JOIN C as Maybe
on Want.ID = Maybe.ID
JOIN A as SecondA
on Maybe.AID = SecondA.ID
JOIN B
on Maybe.ID = B.cID
So, this query is stating I want everything from Table A (alias Want -- left side/first table in the list) Regardless of there being a match in Table C (alias Maybe) where the ID keys match.
Notice the next joins going down from "C" back to the second instance of "A" and table B. I have those as just joins... So the relationship between the "Maybe" alias, and that of second instance of "A" and "B" are JOIN (required).
Hopefully this gives some better clarification on HOW it works.
Now, for your real-life query. If you can describe what you are looking for, and your sample table structures / result expections, listing that could offer more explicit solution to your needs.
Hope this will help
SELECT
A.*, B.*, C.*
FROM A
inner join C on(A.id = C.id)
inner join B on(B.cid = C.id)