MySQL with ON condition from another table - mysql

Let's say that I have:
SELECT * FROM a
LEFT OUTER JOIN b ON b.a_id = a.id
LEFT OUTER JOIN c ON b.c_id = c.id
Now what I want to do is to select b's that are assigned to c that is e. g. active (c.active = 1). How can I do that with ON?
Note that I can't use WHERE after the whole query above, because I want a's to be returned even if 0 b's are found.

Just to make sure, I understood the question: You want all rows where either c.active equals 1 or where there is no entry in b or c, right?
It's a bit lengthy but this seems to work:
SELECT * FROM a
LEFT OUTER JOIN b ON a.aid = b.aid
LEFT OUTER JOIN c ON b.bid = c.bid
WHERE a.aid NOT IN (
SELECT a.aid FROM a
INNER JOIN b ON a.aid = b.aid
INNER JOIN c ON b.bid = c.bid
WHERE NOT c.active
);
I could also imagine a solution using UNION

Which rows are returned in each case... Note that one case is different:
FROM b JOIN c ON ... AND c.active=1 -- rows in both tables exist and active
FROM b JOIN c ON ... WHERE c.active=1 -- ditto
FROM b LEFT JOIN c ON ... WHERE c.active=1 -- ditto
FROM b LEFT JOIN c ON ... AND c.active=1 -- all b's, but NULLs for inactive/missing c's
(Caveat: I am not sure I got the cases correct; just keep in mind that ON and WHERE are not always interchangeable.)
When mixing JOIN and LEFT JOIN, you may need to add parentheses:
FROM a JOIN ( b LEFT JOIN c ON... ) ON ... WHERE ...
FROM ( a JOIN b ON ... ) LEFT JOIN c ON... WHERE ...

Related

SELECT JOIN with conditional (OR) cross

I need to do something like this (in MySQL), my attempts using UNION won't work until now.
In theory:
SELECT * FROM
tableA A
JOIN tableB B ON A.tableAId = B.tableAId
LEFT JOIN tableC C ON C.tableAId = A.tableAId
LEFT JOIN tableD D ON D.tableAId = A.tableAId
JOIN tableE E
ON (C.tableEId = E.tableEId OR D.tableEId = E.tableEId)
The expected result is crossing A with B, optional C with A, optional D with A and get the E result if its id is on C or D.
In order to know if the record found is from C or D, I'm using an IF checking if tableCId or tableDId are null.
I think your code will work.
SELECT *
FROM tableA A JOIN
tableB B
ON A.tableAId = B.tableAId LEFT JOIN
tableC C
ON C.tableAId = A.tableAId LEFT JOIN
tableD D
ON D.tableAId = A.tableAId JOIN
tableE E
ON E.tableEId IN (C.tableEId, D.tableEId);
This will filter out rows that have no matches in C and D, as well as those whose matches in C/D are not in E. I assume that is desirable.
Also, OR and IN can have a bad impact on JOIN performance, but you don't mention performance as a concern.

rails query - conditional joins

I have 4 tables A, B, C & D as follows:
B belongs to A
B belongs to C
&
C has many D
As 'A' may or may not have any B's but if there is a B, then that B must have a C. And according to my logic, C will have at least one D or may be more.
Now, I want to get the list of A's with count(b) as well as count(d). Here count(b) and count(d) might be zero.
So what I was doing till now is as follows:
#a = A.joins(bs: {c: :ds}).select("a.*, count(b) as count_b, count(d) as count_d").group("a.id")
But eventually this is not working, as it INNER JOIN b with a. Which means, if there is no corresponding b for a, then that a will not be in the list #a. That's the problem.
So, is there any way to do it ?
joins has a form where it accepts a string. In that string you can put 'LEFT OUTER join bs ON bs... = as...'
Try Left outer join:
#a = A.joins("LEFT JOIN B on A.id=B.a_id INNER JOIN C on C.id=B.c_id INNER JOIN CD on C.id=CD.c_id INNER JOIN D on D.id=CD.d_id")
For more details check this question
I tried
#a = A.joins("LEFT JOIN B on A.id=B.a_id LEFT JOIN C on C.id=B.c_id LEFT JOIN CD on C.id=CD.c_id LEFT JOIN D on D.id=CD.d_id") which worked for me.

Mysql inner join twice and use WHERE on both joins

In MySQL, I want to SELECT A.* FROM A where an inner join condition is satisfied whether directly (joining table B) or through another join table (C), WHERE B.field = myvalue. Can anyone point out the proper way to get results?
I have the following tables: A, B, C, which are associated as follows (A joins B, B joins C, A joins C):
B
/ \
A --- C
It looks pretty straightforward, but I get an empty set when I run the following code, even though I get results when I restrict the search to just joining B through C:
SELECT A.* FROM A
INNER JOIN C ON C.id = A.c_id
INNER JOIN B AS B_thru_C ON B_thru_C.id = C.b_id
INNER JOIN B AS B_from_A ON B_from_A.id = A.b_id
WHERE B_thru_C.field = 'myvalue' OR B_from_A.field = 'myvalue';
# yields an empty set
SELECT A.* FROM A
INNER JOIN C ON C.id = A.c_id
INNER JOIN B AS B_thru_C ON B_thru_C.id = C.b_id
WHERE B_thru_C.field = 'myvalue';
# yields results
How about this?
SELECT A.* FROM A
LEFT OUTER JOIN C ON C.id = A.c_id
INNER JOIN B ON B.id = A.b_id OR B.id = C.b_id
WHERE B.field = 'myvalue';

MYSQL JOINS with 3 tables

TABLE A, B, C
How can I make a query that joins these three tables. The condition is that Table A must have a record.
I tried like this
select * from a
left join b on a.article_id = b.article_id
left join c on b.file_id = c.submission_id
where c.user_id = 6;
My query doesn't work in the case that Table C is missing a record. In that case, the join doesn't work for the three tables.
Any criteria on the outer tables must be int he relevant ON clause, not the WHERE clause.
For example:
select * from a
left join b on a.article_id = b.article_id
left join c on b.file_id = c.submission_id and c.user_id = 6;
If you use LEFT JOIN, then records from a and b are selected even if there are no corresponding records in table c. Use INNER JOIN instead:
SELECT * FROM a
INNER JOIN b ON a.article_id = b.article_id
INNER JOIN c ON b.file_id = c.submission_id
WHERE c.user_id = 6;

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)