Here is the dummy data, it's a calls record data table.
This is a glimpse of it:
|  call_id  |   customer   |   company   |     call_start      | 
|-----------|--------------|-------------|---------------------|
|1411482360 | 001143792042 | 08444599175 | 2014-07-31 13:55:03 |
|1476992122 | 001143792042 | 08441713191 | 2014-07-31 14:05:10 |
The customer and company fields represents their telephone numbers.
EDIT:
-Customer A calls Company A. 
-If customer A calls Company B then Company B will have +1 gain and Company A will have +1 lost. 
 -If customer A calls Company C then Company C will have +1 gain and Company B will have +1 lost.
-If customer A calls Company C again then the spill/gain will not be affected.
-The gain/lost only comes into play once a 2nd call has been made by customer A.
 - If a customer calls companies in this order: A, B, B, C, A, A, C, B, D the process should be like this:
A ->  
B ->  B +1 gain,  A +1 lost
B ->  
C ->  C +1 gain,  B +1 lost
A ->  A +1 gain,  C +1 lost
A ->  
C ->  C +1 gain,  A +1 lost
B ->  B +1 gain,  C +1 lost
D ->  D +1 gain,  B +1 lost
After above process we should have the total values as:
Company    Total gain    Total lost
  A            1             2            
  B            2             2       
  C            2             2         
  D            1             0     
I started working on this but it's wrong, it's just an ideea, it doesn't give me separate incremented gain and lost values based on the above conditions:
DROP TABLE IF EXISTS GetTotalGainAndLost;
CREATE TEMPORARY TABLE IF NOT EXISTS GetTotalGainAndLost
    AS 
        (
        SELECT SUM(count) as 'TotalGainAndLost', `date`, DAY(`date`) as 'DAY' 
        FROM (SELECT count(*) as 'count', customer, `date` 
            FROM (SELECT customer, company, count(*) AS 'count', DATE_FORMAT(`call_end`,'%Y-%m-%d') as 'date' 
                FROM calls 
                WHERE `call_end` LIKE CONCAT(2014, '-', RIGHT(CAST(concat('0', 01) AS CHAR),2),'-%')
                GROUP BY customer, company, DAY(`call_end`) ORDER BY `call_end` ASC)
            as tbl1 group by customer, `date` having count(*) > 1) 
        as tbl2 GROUP by `date`
        );
Select * from GetTotalGainAndLost;
DROP TABLE GetTotalGainAndLost;
This query doesn't show any results.
Should be one row per company and date (total gain and lost calls by day in e.g. january)
|  company    |  totalGain |  totalLost  |     date     |  DAY  | 
|-------------|------------|-------------|--------------|-------|
| 08444599175 |     17     |       6     | 2014-07-01   |  1    |
| 08444599175 |     12     |      10     | 2014-07-02   |  2    |
| 08444599175 |      3     |       6     | 2014-07-02   |  3    |
| 08444599175 |   ....     |      ...    |     ...      | ...   |
| 08444599175 |      7     |       6     | 2014-07-31   | 31    |
                Let denote N as the number times company has appeared. Lets try to simplify the formula in three simple rules.
In your example:
Result
Company      Gain           Lost  
  A            2             3            
  B            3             3       
  C            2             2         
  D            1             0    
First we start by counting the number appearance of each company.
SELECT
    company, COUNT(*) AS gain, COUNT(*) AS lost, DATE(call_start) AS date
FROM calls 
GROUP BY DATE(call_start), company
Then, we start select the number that each company appear the first time for each customer.
SELECT company, -COUNT(*) AS gain, 0 AS lost, DATE(call_start) AS `date`
FROM calls INNER JOIN (
    SELECT MIN(call_id) AS call_id FROM calls GROUP BY DATE(call_start), customer
) AS t ON (calls.call_id = t.call_id)
GROUP BY DATE(call_start), calls.company
The number of company that appear last.
SELECT company, 0 AS gain, -COUNT(*) AS lost, DATE(call_start) AS `date`
FROM calls INNER JOIN (
    SELECT MAX (call_id) AS call_id FROM calls GROUP BY DATE(call_start), customer
) AS t ON (calls.call_id = t.call_id)
GROUP BY DATE(call_start), calls.company
Finally, we can combine the whole SQL together using UNION ALL and then do another group by.
SELECT company, SUM(gain) AS gain, SUM(lost) AS lost, `date` FROM (
    (
        SELECT
            company, COUNT(*) AS gain, COUNT(*) AS lost, DATE(call_start) AS `date`
        FROM calls 
        GROUP BY DATE(call_start), company
    ) UNION ALL (
        SELECT company, -COUNT(*) AS gain, 0 AS lost, DATE(call_start) AS `date`
        FROM calls INNER JOIN (
            SELECT MIN(call_id) AS call_id FROM calls GROUP BY DATE(call_start), customer
        ) AS t ON (calls.call_id = t.call_id)
        GROUP BY DATE(call_start), calls.company
    ) UNION ALL (
        SELECT company, 0 AS gain, -COUNT(*) AS lost, DATE(call_start) AS `date`
        FROM calls INNER JOIN (
            SELECT MAX(call_id) AS call_id FROM calls GROUP BY DATE(call_start), customer
        ) AS t ON (calls.call_id = t.call_id)
        GROUP BY DATE(call_start), calls.company
    )
) AS t
GROUP BY `date`, company
The above query make assumption that each new day is independence. For example,
The result would be
COM   G     L   DAY
 ----------------
A     0     1    1
B     1     1    1
C     1     0    1
D     0     1    2
E     1     0    2
                        I think the easiest way to do this is with two queries. First we can get total gains counting every call made to a different company by each customer:
select g.company company, count(g.call_id) gain
from calls c
join calls g on c.customer = g.customer and c.company <> g.company and c.call_start < g.call_start
left join calls m on g.customer = m.customer and g.company <> m.company and g.call_start > m.call_start and m.call_start > c.call_start
where m.call_id is null
group by g.company;
Left join is needed to don't count extra gains if customer makes various calls to various companies (i. e. if customer calls in order to company a, b and c company c only has one gain, not two).
Total lost with the same approach:
select l.company company, count(l.call_id) lost
from calls c
join calls l on c.customer = l.customer and c.company <> l.company and c.call_start > l.call_start
left join calls m on l.customer = m.customer and l.company <> m.company and c.call_start > m.call_start and l.call_start < m.call_start
where m.call_id is null
group by l.company;
Here's a little fiddle demoing the solution: http://sqlfiddle.com/#!2/3236ab/7
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With