MySQL OUTER Join with AS - mysql

I have quite the beast of a SQL statement and I was hoping for a little help. I have found that I need to be using an OUTER join for some of these tables but MySQL doesn't have that function.
SELECT validclick.CampaignName AS CampaignName,
validclick.Website AS Website,
validclick.RevClicks AS RevClicks,
validclick.Revenue AS Revenue,
validclick.TQ AS TQ,
validclick.Source AS Source,
validclick.ScoredClicks AS ScoredClicks,
validclick.Searches AS Searches,
vci.Impressions AS Impressions,
(validclick.RevClicks / validclick.Searches * 100) AS CTR,
(IFNULL(yaho.Spend, 0) + IFNULL(facebook.Spend, 0) + IFNULL(google.Spend, 0)) AS Spend,
(IFNULL(yaho.PaidClicks, 0) + IFNULL(facebook.PaidClicks, 0) + IFNULL(google.PaidClicks, 0)) AS PaidClicks,
(validclick.Revenue -
(IFNULL(yaho.Spend, 0) + IFNULL(facebook.Spend, 0) + IFNULL(google.Spend, 0))) AS Profit,
(validclick.TQ / validclick.ScoredClicks) AS ScoredTQ,
(validclick.TQ / validclick.RevClicks) AS UnscoredTQ,
(validclick.Revenue /
(IFNULL(yaho.PaidClicks, 0) + IFNULL(facebook.PaidClicks, 0) + IFNULL(google.PaidClicks, 0))) AS RPI,
(validclick.Revenue / validclick.RevClicks) AS RPC,
((IFNULL(yaho.Spend, 0) + IFNULL(facebook.Spend, 0) + IFNULL(google.Spend, 0)) /
(IFNULL(yaho.PaidClicks, 0) + IFNULL(facebook.PaidClicks, 0) + IFNULL(google.PaidClicks, 0))) AS CPC,
((validclick.Revenue -
(IFNULL(yaho.Spend, 0) + IFNULL(facebook.Spend, 0) + IFNULL(google.Spend, 0))) /
(IFNULL(yaho.Spend, 0) + IFNULL(facebook.Spend, 0) + IFNULL(google.Spend, 0)) * 100) AS ROI,
(validclick.RevClicks /
(IFNULL(yaho.PaidClicks, 0) + IFNULL(facebook.PaidClicks, 0) + IFNULL(google.PaidClicks, 0)) * 100) AS Conversion
FROM
(SELECT camp.CampaignName AS CampaignName,
MAX(camp.Website) AS Website,
MAX(camp.Source) AS Source,
SUM(vc.Clicks) AS RevClicks,
SUM(vc.Revenue) AS Revenue,
SUM(vc.TQ) AS TQ,
SUM(vc.ScoredClicks) AS ScoredClicks,
SUM(vc.BiddedSearches) AS Searches
FROM
(SELECT AffID,
MAX(CampaignName) AS CampaignName,
Website,
MAX(Source) AS Source
FROM campaigns
GROUP BY AffID) AS camp
JOIN
(SELECT AffID,
SUM(Clicks) AS Clicks,
SUM(AffiliateRevenue) AS Revenue,
SUM(BiddedSearches) AS BiddedSearches,
SUM(CASE WHEN TQ > 0 THEN (TQ * Clicks) ELSE NULL END) AS TQ,
SUM(CASE WHEN TQ > 0 THEN Clicks ELSE NULL END) AS ScoredClicks
FROM validclickvc
WHERE Date BETWEEN '2018-05-06' AND '2018-05-07'
GROUP BY AffID) AS vc
ON vc.AffID = camp.AffID
GROUP BY camp.CampaignName) AS validclick
LEFT JOIN
(SELECT CampaignName,
SUM(Spend) AS Spend,
SUM(OutboundClicks) AS PaidClicks
FROM facebookads
WHERE Date BETWEEN '2018-05-06' AND '2018-05-07'
GROUP BY CampaignName) AS facebook
ON validclick.CampaignName = facebook.CampaignName
LEFT JOIN
(SELECT CampaignName,
SUM(Spend) AS Spend,
SUM(Clicks) AS PaidClicks
FROM yahoo
WHERE Date BETWEEN '2018-05-06' AND '2018-05-07'
GROUP BY CampaignName) AS yaho
ON validclick.CampaignName = yaho.CampaignName
LEFT JOIN
(SELECT CampaignName,
SUM(Cost) AS Spend,
SUM(Clicks) AS PaidClicks
FROM adwords
WHERE Date BETWEEN '2018-05-06' AND '2018-05-07'
GROUP BY CampaignName) AS google
ON validclick.CampaignName = google.CampaignName
LEFT JOIN
(SELECT camp.CampaignName AS CampaignName,
SUM(vc.Impressions) AS Impressions
FROM
(SELECT AffID,
MAX(CampaignName) AS CampaignName
FROM campaigns
GROUP BY AffID) AS camp
JOIN
(SELECT ty AS AffID,
COUNT(DISTINCT(id)) AS Impressions
FROM validclickimpressions
WHERE ts BETWEEN '2018-05-06 00:00' AND '2018-05-07 23:59'
GROUP BY AffID) AS vc
ON vc.AffID = camp.AffID
GROUP BY camp.CampaignName) AS vci
ON validclick.CampaignName = vci.CampaignName
ORDER BY CampaignName;
I'm aware this may not be the most efficient MySQL statement, but we will soon be changing the structure of things so i's not a big deal. For now I need some way to use OUTER join, or do a LEFT JOIN UNTION RIGHT JOIN but with an alias. The tables (aliases) I need to full join are vci, facebook, google, and yaho. Any ideas on how to tackle this?

MySQL does not support FULL [OUTER] JOIN.
We can emulate a full outer join in MySQL using two separate select, combining the results. The pattern of an outer join and an anti-join.
-- outer join (all rows from a along with matching rows from b)
SELECT ... FROM a LEFT JOIN b ON ...
UNION ALL
-- anti-join (rows from b with no matching row in a)
SELECT ... FROM b LEFT JOIN a ON ... WHERE a.notnull_col IS NULL
As a simplistic demonstration, two tables a and b:
table a table b
an bn
------- -------
1 2
2 3
3 5
4 7
Example query
-- left outer join (rows in a with matching rows from b)
SELECT a.an, b.bn
FROM a
LEFT
JOIN b
ON b.bn = a.an
UNION ALL
-- anti-join (rows from b with no match in a)
SELECT a.an, b.bn
FROM b
LEFT
JOIN a
ON a.an = b.bn
WHERE a.an IS NULL
should return something like this (without ORDER BY clause, order of rows is indeterminate)
an bn
------- -------
1 (NULL)
2 2
3 3
4 (NULL)
(NULL) 5
(NULL) 7

Related

Combining the result of two queries to one result SQL

I'm trying t create a compare, now i'm only able to make it as multiple result (two different result).
both of the result above is from two queries.
My first result query
SELECT
customercode,
CONVERT(DATE, TransDate) transdate,
SUM(TotalReceivable) AS total
FROM
SalesOrderHeader
WHERE
CustomerCode = 'K-MDMM4'
AND TransDate BETWEEN '2016-07-25' AND '2016-07-30'
GROUP BY
CONVERT(DATE, TransDate), customercode
and my second query
SELECT
b.OutletCode AS outlet,
tanggal,
(cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item,0)) total
FROM
transaksi a
LEFT JOIN
Outlet b ON a.Outlet = b.OutletCode
LEFT JOIN
area c ON b.areacode = c.areacode
WHERE
b.active = 1
AND b.OutletCode LIKE 'K-MDMM4'
AND flag = 1
AND tanggal BETWEEN '2016-07-25' AND '2016-07-30'
GROUP BY
b.OutletCode, tanggal, cash, cc, dc, flash,
piutang, reject, disc50, spesial_item, ba, mpm, tf,
ul,remarks
ORDER BY
tanggal DESC
I want this result.
customercode | transdate | total_tbl1 | total_tbl2
K-MDMM4 2016-07-25 6004050 6004050
K-MDMM4 2016-07-26 6880340 6880340
K-MDMM4 2016-07-27 5745040 5745040
K-MDMM4 2016-07-28 7424820 7424820
I can't use jsfiddle :(. I don't know why. I can't create table via queries.
From now, I have this query
SELECT
b.OutletCode AS outlet,
tanggal,
(cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item, 0)) total,
SUM(d.TotalReceivable) AS total
FROM
transaksi a
LEFT JOIN
Outlet b ON a.Outlet = b.OutletCode
LEFT JOIN
area c ON b.areacode = c.areacode
LEFT JOIN
salesorderheader d ON CONVERT(DATE, a.tanggal) = CONVERT(DATE, d.transdate)
WHERE
b.active = 1
AND b.BrandCode LIKE '%%'
AND b.OutletCode LIKE '%%'
AND flag = 1
AND YEAR(tanggal) = '2016'
AND MONTH(tanggal) = '7'
AND outlet = 'K-MDMM4'
GROUP BY
OutletCode, tanggal, cash, cc, dc, flash,
piutang, reject, disc50, spesial_item, transdate, totalreceivable
ORDER BY
tanggal DESC
and the result so far from my desired result....
Combine both queries into a single join and select
SELECT tbl1.customercode,
CAST(tbl1.transdate AS DATE) AS transdate,
tbl1.total AS total_tbl1,
tbl2.total AS total_tbl2
FROM
(
-- Query 1
SELECT customercode,convert(date,TransDate) transdate,SUM(TotalReceivable) as total
FROM SalesOrderHeader
where CustomerCode = 'K-MDMM4'
and TransDate between '2016-07-25' and '2016-07-30'
group by convert(date,TransDate),customercode
) AS tbl1
INNER JOIN (
-- Query 2
select b.OutletCode as outlet,tanggal, (cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item,0)) total From transaksi a
left join Outlet b on a.Outlet = b.OutletCode
left join area c on b.areacode = c.areacode
where b.active = 1 and b.OutletCode like 'K-MDMM4' and flag = 1 and tanggal
between '2016-07-25' and '2016-07-30'
group by b.OutletCode,tanggal,cash,cc,dc,flash,piutang,reject,disc50,spesial_item,ba,mpm,tf,ul,remarks
) AS tbl2 ON tbl2.outlet = tbl1.customercode AND CAST(tbl2.trnggal AS DATE) = CAST(tbl1.transdate AS DATE)
order by CAST(tbl1.transdate AS DATE) DESC;
I don't have a database installed on this PC but what you're looking for is:
SELECT val1, val2 FROM
(SELECT1_of_your_code AS table1) INNER JOIN
(SELECT2_of_your_code AS table2) ON
table1.x == table2.y

MySQL query - optimized

Is it possible to achieve this task with a single MySQL query?
Table urls. Fields {id, url}
1, www.mysite.kom
2, mysite.kom
3, anothersite.kom
Table logs. Fields {id, url_id, group_type - a number in the range of 1..10}
1, 1, 4
2, 1, 4
3, 2, 5
4, 2, 5
5, 3, 9
The result of the query in this example should be: 1 (mysite.com and www.mysite.com = 1)
THE GOAL:
Need to count all distinct urls recorded in logs table, but with a few conditions:
1) Urls with and without www. prefix, like mysite.kom and www.mysite.kom, should be counted as 1 (not 2).
2) Have group_type in the range of 4..6
3) Now, any of these urls with group_type 4..6, which appear in the list of those with group_type lower than 4 - should be ignored and not counted at all.
The SQL code:
SELECT COUNT(DISTINCT TRIM(LEADING 'www.' FROM b.url))
FROM logs a
INNER JOIN urls b
ON a.url_id = b.id
WHERE (group_type BETWEEN 4 AND 6)
----- and this condition below -----
AND TRIM(LEADING 'www.' FROM b.url)
NOT IN (
SELECT TRIM(LEADING 'www.' FROM b.url)
FROM logs a
INNER JOIN urls b
ON a.url_id = b.id
WHERE (group_type < 4)
)
If my sql query is correct, can it be optimized (to look more compact)?
SELECT COUNT(DISTINCT u.id) AS COUNT_QUES FROM urls u
INNER JOIN logs l
ON u.id=l.url_id
WHERE u.url NOT IN (SELECT A.url FROM
(SELECT * FROM urls u
WHERE SUBSTR(u.url,1,3)!='www')A,
(SELECT * FROM urls v
WHERE SUBSTR(v.url,1,3)='www')B
WHERE A.url=SUBSTR(B.url,5,LENGTH(B.url))
)
AND l.group_type BETWEEN 4 AND 6
AND u.id NOT IN
(SELECT DISTINCT u.id FROM urls u
INNER JOIN logs l
ON u.id=l.url_id
WHERE u.url NOT IN (SELECT A.url FROM
(SELECT * FROM urls u
WHERE SUBSTR(u.url,1,3)!='www')A,
(SELECT * FROM urls v
WHERE SUBSTR(v.url,1,3)='www')B
WHERE A.url=SUBSTR(B.url,5,LENGTH(B.url))
)
AND l.group_type < 4
)
OR
SELECT COUNT(DISTINCT CASE WHEN B.URL_ID IS NOT NULL AND FLAG1 = 1 AND FLAG2 = 0 THEN TRIM(LEADING 'www.' FROM A.URL) END)
FROM URLS A
LEFT JOIN (SELECT URL_ID,
MAX(CASE WHEN GROUP_TYPE BETWEEN 4 AND 6 THEN 1 ELSE 0 END) FLAG1,
MAX(CASE WHEN GROUP_TYPE < 4 THEN 1 ELSE 0 END) FLAG2
FROM LOGS
GROUP BY URL_ID) B
ON A.ID = B.URL_ID
Hope this works for you.Check this on SQLFIDDLE - http://sqlfiddle.com/#!2/1fde2/39
Here's one way:
SELECT trimmed_url
FROM ( SELECT TRIM(LEADING 'www.' FROM urls.url) AS trimmed_url,
MIN(logs.group_type) AS min_group_type
FROM logs
JOIN urls
ON urls.id = logs.url_id
GROUP
BY trimmed_url
) t
WHERE min_group_type BETWEEN 4 AND 6
;
But only you can judge whether it looks more compact to you, and only testing can determine whether it performs better.

mysql statistics data for users - how do I get columns per date range?

I have 3 tables in a query:
apiusers, users
these contain a user id, and a name.
download_stats:
this contains usertype (1 = users, 2 = apiusers), date, file downloaded_id.
What I want to do is get a layout of:
| user id | name | download stats for january | download stats for february
etc.
I'm currently trying with this query, which takes forever:
SELECT name,queryuserid,count(ROWA.id) ,count(ROWB.id)
FROM (SELECT IFNULL(u.name, au.companyname) AS name,IFNULL(u.id, au.id) AS queryuserid
FROM apiusers as au, users as u
GROUP BY 2 ) AS users
LEFT JOIN stats_download as ROWA ON ROWA.userid=queryuserid AND ROWA.date > date('2011-01-01') AND ROWA.date < date('2011-02-01')
LEFT JOIN stats_download as ROWB ON ROWB.userid=queryuserid AND ROWB.date > date('2011-01-01') AND ROWB.date < date('2011-02-01')
GROUP BY 2;
Is there a better way of going about this? The client wants supports to "group" the output statistics by year, month and day. So there could potentionally be 30+ LEFT JOIN's in there.
This should get you the basis, and runs an entire year sample. Look at the pattern. By doing a sum of a qualified IF() condition returning 1 or 0 you get the total count per each month. Now, if you are looking for SIZE (such as download size), instead of 1, 0, you can just substitute the fileSize instead of 1 and you'll have the total downloaded size... put them as different columns and you can have both Count of downloads and totalSize of downloads. Expand the date range over year, just keep going with the pattern...
SELECT
AllUsers.Name,
AllUsers.QueryUserID,
SUM( if( SD.Date BETWEEN '2011-01-01' and '2011-01-31', 1, 0 )) as CountJan2011,
SUM( if( SD.Date BETWEEN '2011-02-01' and '2011-02-28', 1, 0 )) as CountFeb2011,
SUM( if( SD.Date BETWEEN '2011-03-01' and '2011-03-31', 1, 0 )) as CountMar2011,
SUM( if( SD.Date BETWEEN '2011-04-01' and '2011-04-30', 1, 0 )) as CountApr2011,
SUM( if( SD.Date BETWEEN '2011-05-01' and '2011-05-31', 1, 0 )) as CountMay2011,
SUM( if( SD.Date BETWEEN '2011-06-01' and '2011-06-30', 1, 0 )) as CountJun2011,
SUM( if( SD.Date BETWEEN '2011-07-01' and '2011-07-31', 1, 0 )) as CountJul2011,
SUM( if( SD.Date BETWEEN '2011-08-01' and '2011-08-31', 1, 0 )) as CountAug2011,
SUM( if( SD.Date BETWEEN '2011-09-01' and '2011-09-30', 1, 0 )) as CountSep2011,
SUM( if( SD.Date BETWEEN '2011-10-01' and '2011-10-31', 1, 0 )) as CountOct2011,
SUM( if( SD.Date BETWEEN '2011-11-01' and '2011-11-30', 1, 0 )) as CountNov2011,
SUM( if( SD.Date BETWEEN '2011-12-01' and '2011-12-31', 1, 0 )) as CountDec2011
FROM
( select distinct
APIUsers.CompanyName as Name,
APIUsers.QueryUserID
from APIUsers
UNION
select
Users.Name,
Users.QueryUserID
from Users ) AllUsers
LEFT JOIN stats_download SD
ON AllUsers.QueryUserID = SD.UserID
AND SD.Date BETWEEN '2011-01-01' and '2011-12-31'
GROUP BY
2;
There is a better way.
You need to do just one join with the stats_download and aggregate on months, I assume the method GETMONTH extracts the month from a date (every database has its own method, you didn't specify what you are using)
(
SELECT name,queryuserid,count(stats_download.id) as cnt,GETMONTH(stats_download.date) as month
FROM (SELECT IFNULL(u.name, au.companyname) AS name,IFNULL(u.id, au.id) AS queryuserid
FROM apiusers as au, users as u
GROUP BY 2 ) AS users
LEFT JOIN stats_download ON stats_download.userid=queryuserid
GROUP BY name, queryuserid, GETMONTH(stats_download.date)
) as TableA
so now we have a table that create columns according to the different groups, so we inner join the table with itself (should be much faster since this table is smaller)
Select name, queryuserid, A.cnt as January, B.cnt as February from TableA left join TableA as A on (TableA.queryuserid = A.queryuserid and A.month=1) left join TableA as B on (TableA.queryuserid = B.queryuserid and B.month=2)
I haven't run it so I may have some typos but this is the direction.
Hope it helps...

mysql day report query

The query below gives me a report of items that are out for an equipment rental company. this is a super complicated query that takes almost 20 seconds to run. This is obviously not the correct way to get the data that I'm looking for. I build this query from PHP and add in the start date of 02-01-2011 and the end date of 03-01-2011, the product code (p_code = 1) and product pool (i_pool =1). Those 4 pieces of information are passed to a PHP function and injected into the following sql to return the report I need for a calendar control displaying how many items are out. My question is: Is there any way to simplify or do this better, or run more efficiently, using better joins or a better way to display the individual days.
SELECT DISTINCT reportdays.reportday, count(*)
FROM
(SELECT '2011-02-01' + INTERVAL a + b DAY reportday
FROM
(SELECT 0 a UNION SELECT 1 a UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
UNION SELECT 8 UNION SELECT 9 ) d,
(SELECT 0 b UNION SELECT 10 UNION SELECT 20
UNION SELECT 30 UNION SELECT 40) m
WHERE '2011-02-01' + INTERVAL a + b DAY < '2011-03-01'
ORDER BY a + b) as reportdays
JOIN rental_inv as line
ON DATE(FROM_UNIXTIME(line.ri_delivery_dte)) <= reportdays.reportday
AND DATE(FROM_UNIXTIME(line.ri_pickup_dte)) >= reportdays.reportday
LEFT OUTER JOIN rental_in as rent on line.ri_num = rent.ri_num
LEFT OUTER JOIN rental_cancels cancelled on rent.ri_num = cancelled.ri_num
LEFT OUTER JOIN inv inventory on line.i_num = inventory.i_num
LEFT OUTER JOIN product ON inventory.p_code = product.p_code
WHERE rent.ri_extend = 0 -- disregard extended rentals
AND cancelled.ri_num is null -- disregard cancelled rentals
AND inventory.p_code = 1
AND inventory.i_pool = 1
GROUP BY reportdays.reportday
If there is any other information needed, let me know and I'll post it.
You can use:
SELECT DATE(ri_delivery) as day,
count(*) as itemsout,
FROM rental_inv
GROUP BY day;
I'm not sure if you need this or a different thing.
SELECT dates.day, count (*)
FROM rental_inv line
INNER JOIN (SELECT DATE(ri_delivery_dte) as day FROM rental_inv
WHERE ri_delivery_dte >= '2011/02/01'
AND ri_delivery_dte <= '2011/02/28'
GROUP BY day
UNION
SELECT DATE(ri_pickup_dte) as day FROM rental_inv
WHERE ri_pickup_dte >= '2011/02/01'
AND ri_pickup_dte <= '2011/02/28'
GROUP BY day) dates
ON line.ri_delivery_dte <= dates.day and line.ri_pickup_dte >= dates.day
LEFT JOIN rental_cancels canc on line.ri_num = canc.ri_num
LEFT JOIN rental_in rent on line.ri_num = rent.ri_num
WHERE canc.ri_num is null
AND rent.ri_extend = 0
GROUP BY dates.day
to find all days:
SELECT DATE(IFNULL(ri_delivery,ri_pickup)) AS date FROM rental_inv AS dateindex WHERE [YEAR-MONTH-1] <= ri_delivery <= LAST_DAY([YEAR-MONTH-1]) OR [YEAR-MONTH-1] <= ri_pickup <= LAST_DAY([YEAR-MONTH-1]) GROUP BY date HAVING NOT ISNULL(date)
to find items out
SELECT COUNT(id) FROM rental_inv WHERE ri_pickup = [DATE];
to find items in
SELECT COUNT(id) FROM rental_inv WHERE ri_delivery = [DATE];
to find balance
SELECT COUNT(out.id) - COUNT(in.id) FROM rental_inv AS out INNER JOIN rental_inv AS in
ON DATE(out.ri_pickup) = DATE(in.ri_delivery) WHERE out.ri_pickup = [DATE] OR in.ri_delivery = [DATE]
You probably can join up everything but since its procedure its more clear;
I am not sure if this would be the exact answer to your problem but I would do something like this I guess. (I didn't use any SQL editor so u need to check syntax I guess)
SELECT
reportdays.d3 as d,
( COALESCE(outgoing.c1,0) - COALESCE(incoming.c2,0) ) as c
FROM
-- get report dates
(
SELECT DATE(FROM_UNIXTIME(COALESCE(l3.ri_delivery_dte, l3.ri_pickup_dte)) d3
FROM rental_inv l3
WHERE
(l3.ri_delivery_dte >= UNIX_TIMESTAMP('2011-02-01')
AND l3.ri_delivery_dte < UNIX_TIMESTAMP('2011-03-01'))
OR (l3.ri_pickup_dte >= UNIX_TIMESTAMP('2011-02-01')
AND l3.ri_pickup_dte < UNIX_TIMESTAMP('2011-03-01'))
GROUP BY d3
) as reportdays
-- get outgoing
LEFT JOIN (
SELECT DATE(FROM_UNIXTIME(l1.ri_delivery_dte)) as d1, count(*) as c1
FROM rental_inv l1
LEFT JOIN rental_cancels canc1 on l.ri_num = canc1.ri_num
LEFT JOIN rental_in rent1 on l.ri_num = rent1.ri_num
WHERE
l1.ri_delivery_dte >= UNIX_TIMESTAMP('2011-02-01')
AND l1.ri_delivery_dte < UNIX_TIMESTAMP('2011-03-01')
AND canc1.ri_num is null
AND rent1.ri_extend = 0
GROUP BY d1
) as outgoing ON reportdays.d3 = outgoing.d1
-- get incoming
LEFT JOIN (
SELECT DATE(FROM_UNIXTIME(l2.ri_pickup_dte)) as d2, count(*) as c2
FROM rental_inv l2
LEFT JOIN rental_cancels canc2 on l2.ri_num = canc2.ri_num
LEFT JOIN rental_in rent2 on l2.ri_num = rent2.ri_num
WHERE
l2.ri_pickup_dte >= UNIX_TIMESTAMP('2011-02-01')
AND l2.ri_pickup_dte < UNIX_TIMESTAMP('2011-03-01')
AND canc2.ri_num is null
AND rent2.ri_extend = 0
GROUP BY d2
) as incoming ON reportdays.d3 = incoming.d2

Union with Count OR Join with Sum - MySQL

I want to combine three tables - date, lead and click - in a query.
The tables looks like this:
date:
|date|
lead:
id|time|commission
click:
id|time|commission
The table date is just storing dates and is used when getting dates with no click or lead.
So if we have the following data in the tables:
date:
2009-06-01
2009-06-02
2009-06-03
lead:
1|2009-06-01|400
2|2009-06-01|300
3|2009-06-03|350
click:
1|2009-06-01|1
2|2009-06-03|2
3|2009-06-03|2
4|2009-06-03|0
I would like to get date, number of click, commission generated by clicks (there are clicks that don't give commission), number of leads, commission generated by leads and total commission. So with the tables above I would like to get:
2009-06-01|1|1|2|700|701|
2009-06-02|0|0|0|0|0
2009-06-03|3|4|1|350|354|
I have tried with the following union:
SELECT
campaign_id,
commission_date,
SUM( click_commission ) AS click_commission,
click,
SUM( lead_commission ) AS lead_commission ,
lead,
SUM( total_commission ) as total_commission
FROM(
SELECT
click.campaign_id AS campaign_id,
DATE( click.time ) AS commission_date,
click.commission AS click_commission,
(SELECT count(click.id) from click GROUP BY date(click.time)) as click,
0 as lead_commission,
0 as lead,
click.commission AS total_commission
FROM click
UNION ALL
SELECT
lead.campaign_id AS campaign_id,
DATE( lead.time ) AS commission_date,
0 as click_commission,
0 as click,
lead.commission AS lead_commission,
lead.id as lead,
lead.commission AS total_commission
FROM lead
UNION ALL
SELECT
0 AS campaign_id,
date.date AS commission_date,
0 AS click_commission,
0 as click,
0 AS lead_commission,
0 as lead,
0 AS total_commission
FROM date
) AS foo
WHERE commission_date BETWEEN '2009-06-01' AND '2009-07-25'
GROUP BY commission_date
ORDER BY commission_date LIMIT 0, 10
But this does not work to count both the number of clicks and leads, the code above gives the right amount of clicks bot 0 on all leads. If I move the code around and put the select from the lead table I get the leads right bot 0 on all clicks. I have not been able to find a way to get both of the counts from the query.
So I tried a left-join instead:
SELECT
date.date as date,
count( DISTINCT click.id ) AS clicks,
sum(click.commission) AS click_commission,
count( lead.id ) AS leads,
sum(lead.commission) AS lead_commission
FROM date
LEFT JOIN click ON ( date.date = date( click.time ) )
LEFT JOIN lead ON ( date.date = date( lead.time ) )
GROUP BY date.date
LIMIT 0 , 30
The problem with this query is if there are more than one clicks or leads on a date it will return the expected value * 2. So on 2009-06-01 it will return 1400 instead on the expected 700 for lead commission.
So in the UNION I have problems with the count and in the left join it is the SUM that is not working.
I would really like to stick to the UNION if possible, but I haven't found a way to get both counts from it.
(This is a follow up to this earlier question, but since I didn't ask for the count in that I posted a new question.)
SELECT date,
COALESCE(lcomm, 0), COALESCE(lcnt, 0),
COALESCE(ccomm, 0), COALESCE(ccnt, 0),
COALESCE(ccomm, 0) + COALESCE(lcomm, 0),
COALESCE(ccnt, 0) + COALESCE(lcnt, 0)
LEFT JOIN
(
SELECT date, SUM(commission) AS lcomm, COUNT(*) AS lcnt
FROM leads
GROUP BY
date
) l
ON l.date = d.date
LEFT JOIN
(
SELECT date, SUM(commission) AS ccomm, COUNT(*) AS ccnt
FROM clicks
GROUP BY
date
) с
ON c.date = d.date
FROM date d
The code that I used, built from the suggestion from Quassnoi:
SELECT date,
COALESCE(ccomm, 0) AS click_commission, COALESCE(ccnt, 0) AS click_count,
COALESCE(lcomm, 0) AS lead_commision, COALESCE(lcnt, 0) AS lead_count,
COALESCE(ccomm, 0) + COALESCE(lcomm, 0) as total_commission
FROM date d
LEFT JOIN
(
SELECT DATE(time) AS lead_date, SUM(commission) AS lcomm, COUNT(*) AS lcnt
FROM lead
GROUP BY
lead_date
) l
ON lead_date = date
LEFT JOIN
(
SELECT DATE(time) AS click_date, SUM(commission) AS ccomm, COUNT(*) AS ccnt
FROM click
GROUP BY
click_date
) с
ON click_date = date