【问题标题】:MYSQL group by in subquery but need all dataMYSQL 在子查询中分组但需要所有数据
【发布时间】:2020-04-06 17:00:20
【问题描述】:

我有两张桌子,一张是transactions,另一张是expenses

交易表:

id  amount  created
1   300     2019-10-01 00:00:00
2   200     2019-11-01 00:00:00
3   230     2019-11-13 00:00:00
4   130     2019-11-13 00:00:00

费用表:

id  amount  created
1   600     2019-11-13 00:00:00

两个表的总和,我在下面写了对我来说很好的查询。

(SELECT IFNULL(date(t1.created), date(ex.created)) as Date , sum(t1.amount) as ReceiveAmount,ex.amount as ExpensesAmount 
    FROM transactions as t1
    LEFT JOIN (
        SELECT sum(e.amount) as amount, created
           FROM expenses as e 
           group by date(e.created)
        ) as ex
    ON date(ex.created) =  date(t1.created)
    GROUP BY date(t1.created))

    UNION

    (SELECT IFNULL(date(t1.created), date(ex.created)) as Date, sum(t1.amount) as Receive,ex.amount as ExpensesAmount 
    FROM transactions as t1

    RIGHT JOIN (
        SELECT sum(e.amount) as amount, created
        FROM expenses as e 
        group by date(e.created)
    ) as ex
    ON date(t1.created) = date(ex.created)
    GROUP BY date(t1.created)) ORDER BY Date

输出:

Date        ReceiveAmount   ExpensesAmount  
2019-10-01  300             NULL
2019-11-01  200             NULL
2019-11-13  360             600

但是现在如果我想从两个表中获取所有金额而不求和。我错过了日期2019-11-13 的一笔交易。

(SELECT IFNULL(date(t1.created), date(ex.created)) as Date , t1.amount as ReceiveAmount,ex.amount as ExpensesAmount 
FROM transactions as t1
LEFT JOIN (
    SELECT e.amount as amount, created
       FROM expenses as e 
       group by date(e.created)
    ) as ex
ON date(ex.created) =  date(t1.created)
GROUP BY date(t1.created))

UNION

(SELECT IFNULL(date(t1.created), date(ex.created)) as Date, t1.amount as Receive,ex.amount as ExpensesAmount 
FROM transactions as t1

RIGHT JOIN (
    SELECT e.amount as amount, created
    FROM expenses as e 
    group by date(e.created)
) as ex
ON date(t1.created) = date(ex.created)
GROUP BY date(t1.created)) ORDER BY Date

输出:

2019-10-01  300     NULL
2019-11-01  200     NULL
2019-11-13  230     600

这里缺少日期2019-11-13的一笔交易。

预期结果:

2019-10-01  300     NULL
2019-11-01  200     NULL
2019-11-13  230     600
2019-11-13  130     NULL

在这里,我怎样才能得到我想要的结果?

【问题讨论】:

    标签: mysql sql join mariadb


    【解决方案1】:

    如果您运行的是 MySQL 8.0,您可以将 row_number()s 分配给来自具有 created 分区的每个表的记录,然后创建一个 left join

    select t.created, t.amount, e.amount
    from (
        select 
            t.*, 
            row_number() over(partition by created order by id)  rn 
        from transactions t
    ) t
    left join (
        select
            e.*, 
            row_number() over(partition by created order by id)  rn 
        from expenses e
    ) e
        on e.created = t.created and e.rn = t.rn
    

    如果两个表中的任何一个可能具有另一个表中不存在的日期,那么它有点复杂。基本上我们需要模拟full join,这在MySQL中是不存在的。这是使用union all 的一种方法:

    select created, max(t_amount) t_amount, max(e_amount) e_amount
    from (
        select 
            created,
            amount t_amount,
            null e_amount,
            row_number() over(partition by created order by id)  rn 
        from transactions
        union all
        select 
            created,
            null,
            amount,
            row_number() over(partition by created order by id)
        from expenses
    ) d
    group by created, rn
    

    【讨论】:

    • 这个查询对事务表很好,但是现在如果费用表有 2 个相同的日期数据,那么它就不起作用了。
    • @SatuSultana:您的示例数据中没有显示!好的,我用一个解决方案编辑了我的答案。
    • 低于响应 #1064 - 您的 SQL 语法有错误;检查与您的 MariaDB 服务器版本相对应的手册,以在第 4 行的“select created, amount t_amount, null e_amount,”附近使用正确的语法
    • @SatuSultana:刚刚修正了一个错字。
    • 创建的最后一行组出错。 #1064 - 您的 SQL 语法有错误;检查与您的 MariaDB 服务器版本相对应的手册,以在第 17 行的“group by created, rn LIMIT 0, 25”附近使用正确的语法
    【解决方案2】:

    如果您不想求和,则不应分组。其他 rdbms 会对此抛出错误。 如果不分组,您应该得到所有记录。

    但我认为你不会得到想要的结果,因为这些费用将在 2019 年 11 月 13 日加入到两笔交易中

    【讨论】:

    • 如果没有分组,它会为同一日期结果提供重复的实体。
    • 如果一天有不止一项支出,您的示例将缺乏您的期望。我认为这会导致麻烦。我建议用两个表做一个简单的联合,填充 RecieveAmount 或 ExpensesAmount
    猜你喜欢
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多