astralmaster
astralmaster

Reputation: 2465

Group data by date from two SQL tables

Consider the following tables:

tbl1
------------

id   name   creationdate

0    AA     2015.05.11
1    BB     2015.04.27
2    cC     2015.04.18


tbl2
------------

id   name   creationdate

0    DD     2015.04.17
1    FF     2015.04.27
2    NN     2015.05.01
3    BV     2015.05.01

What would be the correct syntax for a query to group the count of rows from both table by dates? So that the result is:

DATE         TBL1_COUNT   TBL2_COUNT

2015.04.17            0            1
2015.04.18            1            0
2015.04.27            1            1
2015.05.01            0            2
2015.05.11            1            0

So far I have managed to get the dates from both tables using:

select  DISTINCT date(creationdate) from tbl1
union
select  DISTINCT date(creationdate) from tbl2

The next part would be getting count(*) from both tables and grouping them by the above query's result

Upvotes: 1

Views: 76

Answers (4)

xQbert
xQbert

Reputation: 35323

  1. You need to use UNION ALL or the distinct aspect of union will eliminate the duplicates and negatively impact your counts.
  2. You need a way to denote which value is from what table so we add a column to distinguish, so I added 1 for tbl1 and 2 for tbl2 and called the column src.
  3. We then add a case statement in the outer select and a sum to get the desired counts and a group by to aggregate the dates..
  4. Polish it off with an order by and you get what you're after.

.

SELECT creationDate as Date, 
  sum(case when src=1 then 1 else 0 end) as tbl1_count, 
  sum(case when src=2 then 1 else 0 end) as tbl2_count
FROM (
  SELECT creationdate, 1 as src
  FROM tbl1

  UNION ALL

  SELECT creationdate, 2 as src
  FROM tbl2) Sub
GROUP BY CreationDate
ORDER BY CreationDate

Upvotes: 3

fthiella
fthiella

Reputation: 49049

I think the most efficient way is to have two queries: one that counts all grouped dates from table1 and set the count of table2 to 0, one other that counts all grouped dates from table2 and sets the count of table1 to 0, and then combine them using a UNION ALL query, group again and sum the resulting counts:

SELECT creationDate, sum(count_t1), sum(count_t2)
FROM (
  SELECT creationDate, COUNT(*) AS count_t1, 0 AS count_t2
  FROM t1
  GROUP BY creationDate

  UNION ALL

  SELECT creationDate, 0 AS count_t1, COUNT(*) AS count_t2
  FROM t2
  GROUP BY creationDate
) s
GROUP BY creationDate

Upvotes: 1

pala_
pala_

Reputation: 9010

You can simluate a full outer join, basically. union distinct is fine, and actually desired, we just have to make sure we include sufficient columns to allow the distinct selection to be accurate to our needs.

select d3, count(d1), count(d2)
from (
select t1.id id1, t2.id id2, t1.date as d1, t2.date as d2, coalesce(t1.date, t2.date) d3
  from tbl1 t1
    left join tbl2 t2
      on t1.date = t2.date
union 
select t1.id id1, t2.id id2, t1.date as d1, t2.date as d2, coalesce(t1.date, t2.date) d3
  from tbl1 t1
    right join tbl2 t2
      on t1.date = t2.date
) q
group by d3;

Demo here: http://sqlfiddle.com/#!9/eaa3b/21

Upvotes: 1

AdamMc331
AdamMc331

Reputation: 16691

You have a good start. If I were approaching this, I would start by getting a date and count from each table, like this:

SELECT creationDate, COUNT(*) AS numRows
FROM t1
GROUP BY creationDate;

Then, you can do a FULL OUTER join to get all pairings. MySQL doesn't have full join built in, but you can emulate it using a union of a right join and a left join, try this:

SELECT t1.creationDate, t1.numRows AS t1Rows, COALESCE(t2.numRows, 0) AS t2Rows
FROM(
  SELECT creationDate, COUNT(*) AS numRows
  FROM t1
  GROUP BY creationDate) t1
LEFT JOIN(
  SELECT creationDate, COUNT(*) AS numRows
  FROM t2
  GROUP BY creationDate) t2 ON t1.creationDate = t2.creationDate
UNION
SELECT t2.creationDate, COALESCE(t1.numRows, 0) AS t1Rows, t2.numRows AS t2Rows
FROM(
  SELECT creationDate, COUNT(*) AS numRows
  FROM t1
  GROUP BY creationDate) t1
RIGHT JOIN(
  SELECT creationDate, COUNT(*) AS numRows
  FROM t2
  GROUP BY creationDate) t2 ON t1.creationDate = t2.creationDate;

Here is an SQL Fiddle example.

Upvotes: 2

Related Questions