views:

44

answers:

2

Hello.

I have two tables, foo and bar:

+----+-----+    +----+-----+
| id | val |    | id | val |
+----+-----+    +----+-----+
|  1 | qwe |    |  1 | asd |
|  2 | rty |    |  3 | fgh |
+----+-----+    +----+-----+

id is not unique here. Not all IDs in foo have their equivalents in bar and vice versa. I need to count all rows with specific ID in both tables and present them in a new table, e.g.:

+----+-----------+-----------+
| id | count_foo | count_bar |
+----+-----------+-----------+
|  1 |         1 |         1 |
|  2 |         1 |         0 |
|  3 |         0 |         1 |
+----+-----------+-----------+

I've tried UNION SELECT:

SELECT id, COUNT(id) AS count_foo, 0 AS count_bar FROM foo GROUP BY id
UNION SELECT id, 0, COUNT(id) FROM bar GROUP BY id;

But this outputs row with id=1 twice, like

+----+-----------+-----------+
| id | count_foo | count_bar |
+----+-----------+-----------+
|  1 |         1 |         0 |  <- not good
|  2 |         1 |         0 |
|  1 |         0 |         1 |  <- not good
|  3 |         0 |         1 |
+----+-----------+-----------+

I've also tried LEFT JOIN:

SELECT id, COUNT(foo.id) AS count_foo, COUNT(bar.id) AS count_bar
FROM foo LEFT JOIN bar USING(id) GROUP BY id;

But this query ignores rows from table bar with ID that is missing in table foo:

+----+-----------+-----------+
| id | count_foo | count_bar |
+----+-----------+-----------+
|  1 |         1 |         1 |
|  2 |         1 |         0 |
+----+-----------+-----------+  <- can I haz `id=3`?

What am I missing? What would be the right query or the right manual to read?

Thanks.

A: 

are you looking for OUTER JOIN?

second
Yes, something joining by `OR` and opposite to `INNER JOIN` that joins by `AND`. But AFAIR `OUTER JOIN` in MySQL is used only in `LEFT [OUTER] JOIN` and `RIGHT [OUTER] JOIN` constructs for some compatibility reasons. Anyway, none worked for me, results are the same as with simple `LEFT JOIN` and `RIGHT JOIN`.
hudolejev
+4  A: 

You may want to try the following:

SELECT d.id,
       (SELECT COUNT(*) FROM foo WHERE id = d.id) count_foo,
       (SELECT COUNT(*) FROM bar WHERE id = d.id) count_bar
FROM   ((SELECT id FROM foo) UNION (SELECT id FROM bar)) d;

Test case:

CREATE TABLE foo (id int, val varchar(5));
CREATE TABLE bar (id int, val varchar(5));

INSERT INTO foo VALUES (1, 'qwe');
INSERT INTO foo VALUES (2, 'rty');
INSERT INTO bar VALUES (1, 'asf');
INSERT INTO bar VALUES (3, 'ghj');

Result:

+------+-----------+-----------+
| id   | count_foo | count_bar |
+------+-----------+-----------+
|    1 |         1 |         1 |
|    2 |         1 |         0 |
|    3 |         0 |         1 |
+------+-----------+-----------+
3 rows in set (0.00 sec)
Daniel Vassallo
@hudolejev: Note that I removed my [other example](http://stackoverflow.com/posts/3351762/revisions) using `LEFT JOINs` because it doesn't work well when there is more than 1 count of the same `id` for either `foo` or `bar`. On the other hand, this example using correlated subqueries works fine in these cases.
Daniel Vassallo
Thanks a lot, this works for me.
hudolejev