sqlmysql

3 mysql table join but not getting expected result that i want


Here my table:
account

ac             name
120            Tom
130            Jony
140            Jone

bread_sale

ac             pcs        amount       date
120            12           60         2018-01-03
120            10           50         2018-01-04
140            8            40         2018-01-04
130            5            25         2018-01-05

water_sale

ac             pcs        amount       date
130            2            30         2018-01-03
130            5            75         2018-01-04
140            3            45         2018-01-04
130            4            60         2018-01-05
120            5            75         2018-01-07

Here's the query that I have tried:

select account.ac, 
       account.name, 
       bread_sale.amount as BSAmount,  
       bread_sale.date as BSDate, 
       water_sale.amount as WSAmount, 
       water_sale.date as WSDate
from account left outer join bread_sale on account.ac = bread_sale.ac 
             left outer join water_sale on water_sale.ac = account.ac 
order by account.ac

This is the result:

ac             name       BSAmount   BSdate       WSAmount   WSdate
120            Tom        30         2018-01-03   75         2018-01-07
120            Tom        75         2018-01-04   75         2018-01-07
130            Jony       45         2018-01-05   30         2018-01-03
130            Jony       60         2018-01-05   75         2018-01-04
130            Jony       75         2018-01-05   60         2018-01-05
140            Jone       75         2018-01-04   45         2018-01-04

But I want to obtain something like this:

ac             name       BSAmount   BSdate       WSAmount   WSdate
120            Tom        60         2018-01-03   75         2018-01-07
120            Tom        50         2018-01-04   0          2018-01-07
130            Jony       25         2018-01-05   30         2018-01-03
130            Jony       0          2018-01-05   75         2018-01-04
130            Jony       0          2018-01-05   60         2018-01-05
140            Jone       40         2018-01-04   45         2018-01-04

In 2018-01-07 Tom did not sale water but I get 75 amount. Someone help me, please


Solution

  • It is achievable but messy and probably not very efficient. There is a relationship between the bread water and account on ac. It is possible to establish the maximum number of row numbers spanning bread and water and then rejoining on row number. Put another way bread and water are joined on a position basis (ie the order rows appear in the tables) The resulting query is horrible and parses the data more frequently than I would be comfortable with personally.

    so

    select * from
    (
    select c.ac cac,t.name tname,d.amount bsamount,  d.dt ddt,
             e.amount wsamount ,e.dt edt
             ,
             case when d.dt is not null and d.dt < e.dt then d.dt
                   when d.dt is not null and e.dt is null then d.dt
             else e.dt
             end as sortorder
     from
    (
    select *
    from
    (
    select bs.ac,
             if(bs.ac <> @p,@rn:=1,@rn:=@rn+1) rn,
             @p:=bs.ac p
    from bs
    cross join (select @rn:=0,@p:=0) r
    order by bs.ac,bs.dt
    ) a  
    union 
    (
    select ac2,rn1,p1
    from
    (
    select ws.ac ac2,
             if(ws.ac <> @p1,@rn1:=1,@rn1:=@rn1+1) rn1,
             @p1:=ws.ac p1
    from ws
    cross join (select @rn1:=0,@p1:=0) r
    order by ws.ac,ws.dt
    ) b
    ) 
    ) c
    left join 
    (
    select bs.ac,pcs,amount,dt,
             if(bs.ac <> @p3,@rn3:=1,@rn3:=@rn3+1) rn3,
             @p3:=bs.ac p
    from bs
    cross join (select @rn3:=0,@p3:=0) r
    order by bs.ac,bs.dt
    ) d
    on d.ac = c.ac and  d.rn3 = c.rn
    left join
    (
    select ws.ac,pcs,amount,dt,
             if(ws.ac <> @p4,@rn4:=1,@rn4:=@rn4+1) rn4,
             @p4:=ws.ac p
    from ws
    cross join (select @rn4:=0,@p4:=0) r
    order by ws.ac,ws.dt
    ) e
    on e.ac = c.ac and  e.rn4 = c.rn
    join t on t.ac = c.ac
    ) f
    order by cac , sortorder;
    
    +------+-------+----------+------------+----------+------------+------------+
    | cac  | tname | bsamount | ddt        | wsamount | edt        | sortorder  |
    +------+-------+----------+------------+----------+------------+------------+
    |  120 | Tom   |       60 | 2018-01-03 |       75 | 2018-01-07 | 2018-01-03 |
    |  120 | Tom   |       50 | 2018-01-04 |     NULL | NULL       | 2018-01-04 |
    |  130 | Jony  |       25 | 2018-01-05 |       30 | 2018-01-03 | 2018-01-03 |
    |  130 | Jony  |     NULL | NULL       |       75 | 2018-01-04 | 2018-01-04 |
    |  130 | Jony  |     NULL | NULL       |       60 | 2018-01-05 | 2018-01-05 |
    |  140 | Jone  |       40 | 2018-01-04 |       45 | 2018-01-04 | 2018-01-04 |
    +------+-------+----------+------------+----------+------------+------------+
    6 rows in set (0.00 sec)