Reputation: 1526
I have two tables, tbl_foo
and tbl_bar
, and I want to join these tables with tbl_foo.foo_id = tbl_bar.foo_id
in the on-clause. However, for each tbl_bar.baz_id
there should be one row for each tbl_foo.foo_id
(even if no such entry in tbl_bar
exists). How do I write such query?
There's more info on the schema and my desired result below.
foo_id
and baz_id
.tbl_baz
below.+--------+--------+--------+------------+
| bar_id | baz_id | foo_id | some_field |
+--------+--------+--------+------------+
| 1 | 101 | 1 | foo |
| 2 | 101 | 2 | bar |
| 3 | 101 | 3 | baz |
| NULL | 101 | 4 | bin |
| 4 | 102 | 1 | foo |
| NULL | 102 | 2 | bar |
| 5 | 102 | 3 | baz |
| NULL | 102 | 4 | bin |
+--------+--------+--------+------------+
+--------+------------+
| foo_id | some_field |
+--------+------------+
| 1 | foo |
| 2 | bar |
| 3 | baz |
| 4 | bin |
+--------+------------+
+--------+--------+--------+
| bar_id | baz_id | foo_id |
+--------+--------+--------+
| 1 | 101 | 1 |
| 2 | 101 | 2 |
| 3 | 101 | 3 |
| 4 | 102 | 1 |
| 5 | 102 | 3 |
+--------+--------+--------+
+--------+
| baz_id |
+--------+
| 101 |
| 102 |
+--------+
CREATE TABLE tbl_foo (
foo_id INT,
some_field VARCHAR(255),
PRIMARY KEY (foo_id)
);
INSERT INTO tbl_foo VALUES
(1, 'foo'),
(2, 'bar'),
(3, 'baz'),
(4, 'bin');
CREATE TABLE tbl_bar (
bar_id INT,
baz_id INT,
foo_id INT,
PRIMARY KEY (bar_id, baz_id),
FOREIGN KEY (baz_id) REFERENCES tbl_baz (baz_id),
FOREIGN KEY (foo_id) REFERENCES tbl_foo (foo_id)
);
INSERT INTO tbl_bar VALUES
(1, 101, 1),
(2, 101, 2),
(3, 101, 3),
(4, 102, 1),
(5, 102, 3);
CREATE TABLE tbl_baz (
baz_id INT,
PRIMARY KEY (baz_id)
);
INSERT INTO tbl_baz VALUES
(101),
(102);
Upvotes: 2
Views: 235
Reputation: 15251
You may be looking for a query like this:
UPDATE
Based upon new tbl_baz:
select y.bar_id, x.baz_id, x.foo_id, x.some_field
from (
select a.foo_id, a.some_field, b.baz_id
-- Cross foo_id with all baz_id
from tbl_foo as a, tbl_baz as b
) as x
-- Get the bar_id where it exists for each foo_id/baz_id combo
left join tbl_bar as y on x.foo_id = y.foo_id
and x.baz_id = y.baz_id
order by x.baz_id, x.foo_id
This is based on the assumption that you want to see each foo_id for each baz_id regardless of what is in your many-to-many table.
EXAMPLE of why you may not want this, or may want to update your many-to-many table instead:
If we replace "foo" and "baz" with "person" and "car", this query is essentially saying that every person owns every car. This may be the case, but it is certainly not represented in the "ownership" many-to-many table (bar).
Upvotes: 1
Reputation: 4245
Like mwigdalh said, there's no way to achieve that output with the given tables. If there was another baz table, there would be a way. The problem is that the highlighted records below are essentially pulled from thin air, and meaningless. You could just as easily put "meh" in each one, and the output would make as much sense.
+--------+--------+--------+------------+
| bar_id | baz_id | foo_id | some_field |
+--------+--------+--------+------------+
| 1 | 101 | 1 | foo |
| 2 | 101 | 2 | bar |
| 3 | 101 | 3 | baz |
| NULL | *101*| 4 | bin |
| 4 | 102 | 1 | foo |
| NULL | *102*| 2 | bar |
| 5 | 102 | 3 | baz |
| NULL | *102*| 4 | bin |
+--------+--------+--------+------------+
If you provide some context in a closer-to-real-world example, it might be found that there's a different output altogether that achieves your desired result.
Upvotes: 3
Reputation: 16578
Vague, you can't get there from here. You're asking for a result that specifies a baz_id
for rows where there is no corresponding row from tbl_bar
. There is simply no way to construct the missing data in this case.
Either your schema is not correct or you need some custom default logic for cases where you can't find a row in tbl_bar
.
Upvotes: 0