如何加入两个不相关的mysql表并按日期使用group

时间:2018-02-11 11:21:51

标签: mysql cross-join

我有两张桌子凭证和分类帐 的总帐:

id  total_sale  cancel_amount  date
1    3000           0           2018-01-20
2    3000           0           2018-01-29
3    5000           0           2018-01-30
4    10000          500         2018-01-30
5    2000           100         2018-01-31
6    2000           0           2018-01-31

凭证:

id  expenditure    date
1    500          2018-01-20
2    800          2018-01-30
3    1000         2018-01-30
4    200          2018-01-31
5    300          2018-01-31  

我想要的结果如[2018-01-29到2018-01-31之间的日期]

date           total_sale   total_expenditure
2018-01-29       3000           0
2018-01-30       15000         1800
2018-01-31       4000          500

请有人帮忙

3 个答案:

答案 0 :(得分:0)

对于此类要求,请始终使用维度表。然后,你永远不会因为加入两个不相同的表而感到困惑。

表:

create schema test;

create table date_dim(date date);
insert into date_dim values ('2018-01-20'),
('2018-01-21'),
('2018-01-22'),
('2018-01-23'),
('2018-01-24'),
('2018-01-25'),
('2018-01-26'),
('2018-01-27'),
('2018-01-28'),
('2018-01-29'),
('2018-01-30'),
('2018-01-31');

create table ledger(id int,total_sale int, cancel_amount int, date date);

insert into ledger values
(1,3000,0,'2018-01-20'),
(2,3000,0,'2018-01-29'),
(3,5000,0,'2018-01-30'),
(4,10000,500,'2018-01-30'),
(5,2000,100,'2018-01-31'),
(6,2000,0,'2018-01-31');

create table voucher(id int, expenditure int, date date);
insert into voucher values
(1,500,'2018-01-20'),
(2,800,'2018-01-30'),
(3,1000,'2018-01-30'),
(4,200,'2018-01-31'),
(5,300,'2018-01-31');

SQL脚本(用于解决方案):

 select l.date,total_sale,
total_expenditure
from 
(select d.date date,sum(total_sale)total_sale
 from ledger l right join date_dim d on l.date=d.date
 where d.date between '2018-01-29' and '2018-01-31'
group by 1)l

 join 
(select d.date date,sum(expenditure)total_expenditure
 from voucher v right join date_dim d on v.date=d.date
 where d.date between '2018-01-29' and '2018-01-31'
group by 1)v
on l.date=v.date
group by 1,2,3;

结果集:

date       total_sale   total_expenditure
2018-01-29   3000        (null)
2018-01-30   15000        1800
2018-01-31   4000         500

检查SQL Fiddle

处的解决方案

答案 1 :(得分:0)

您希望将三个不同的聚合呈现为结果集的列。

  1. 不同的日期
  2. 净销售额(总取消次数减少)(我猜测这就是你想要的。)
  3. 支出。
  4. 您需要创建三个子查询并加入它们。

    日期:(http://sqlfiddle.com/#!9/666dcb/1/0

              SELECT DISTINCT DATE(date) date FROM Ledger
               UNION 
              SELECT DISTINCT DATE(date) date FROM Voucher
    

    净销售额:(http://sqlfiddle.com/#!9/666dcb/2/0

             SELECT DATE(date) date, 
                    SUM(total_sale) - SUM(cancel_amount) total_sale
               FROM Ledger
              GROUP BY DATE(date)
    

    支出:(http://sqlfiddle.com/#!9/666dcb/3/0

             SELECT DATE(date) date, 
                    SUM(expenditure) total_expenditures
               FROM Voucher
              GROUP BY DATE(date)
    

    然后你需要在约会时加入他们。 (http://sqlfiddle.com/#!9/666dcb/5/0

    SELECT d.date, s.total_sale, e.total_expenditures
      FROM (
              SELECT DISTINCT DATE(date) date FROM Ledger
               UNION 
              SELECT DISTINCT DATE(date) date FROM Voucher
           ) d
      LEFT JOIN (
             SELECT DATE(date) date, 
                    SUM(total_sale) - SUM(cancel_amount) total_sale
               FROM Ledger
              GROUP BY DATE(date)
           ) s ON d.date = s.date
      LEFT JOIN (
             SELECT DATE(date) date, 
                    SUM(expenditure) total_expenditures
               FROM Voucher
              GROUP BY DATE(date)
           ) e ON d.date = e.date
     WHERE d.date >= somedate AND d.date <= anotherdate
    ORDER BY d.date
    

    为什么第一个子查询 - 具有日期的子查询?它确保您在最终结果集中找到没有任何销售或任何支出的日期。

    为什么要单独的子查询?因为您希望最终加入三个虚拟表 - 三个子查询 - 每个日期具有零行或一行。如果你连接每个日期有多行的表,你会得到销售和支出的组合爆炸,这将夸大你的总和。

    为什么要使用DATE(date)?因为这样可以使详细信息表中的date列包含日期/时间值,以备不时之需。

答案 2 :(得分:0)

select l.dates,l.total_sale,
v.total_expenditure
from 

 (select l.dates dates,sum(total_sale)total_sale
 from ledger l 
 where l.dates between '2018-01-29' and '2018-01-31'
 group by l.dates)l

left join 

 (select v.dates,sum(expenditure)total_expenditure
  from voucher v 
  where v.dates between '2018-01-29' and '2018-01-31'
  group by v.dates)v

 on l.dates=v.dates;