mysql 如何显示从可变键列中获取的累积键=值?

wtlkbnrh  于 2023-05-05  发布在  Mysql
关注(0)|答案(2)|浏览(113)

我有一个MySQLtransfers表,结构如下:

CREATE TABLE `transfers` (
 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
 `id_account_destination` bigint(20) unsigned NOT NULL,
 `id_account_origin` bigint(20) unsigned NOT NULL,
 `amount` decimal(10, 2) signed NOT NULL DEFAULT 0,
 `created_at` datetime DEFAULT CURRENT_TIMESTAMP,

 PRIMARY KEY (`id`),
 KEY `id_account_destination` (`id_account_destination`),
 KEY `id_account_origin` (`id_account_origin`),
 KEY `created_at` (`created_at`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这张表显然存储了转账。记录了 * 转账**金额 * 和涉及的两个 * 账户 *:origindestination
我需要的是创建一个SELECT语句,它从一个时期(通过created_at过滤)获取所有给定的 * 转账 *,并向我显示所有当前账户在该部分中的收入和结果。类似于:

+------------+---------------+-----------------|
| id_account | income_amount | outcome_ammount |
+------------+---------------+-----------------|
|         19 |     27690.87  |        57204.80 |
|        112 |      1000.00  |         2349.00 |
|       1011 |    575877.56  |        17454.50 |
|         17 |    135002.61  |          204.30 |
+------------+---------------+-----------------|

这里的困难在于,id_account列将从任何传输中获取id_account_originid_account_destination,并通过其余传输找到其所有其他出现。如果账户在“原点”位置,转账的 * 金额 * 将被添加到outcome_ammount列;但如果在“目的地”位置找到该帐户,则应将转账的 * 金额 * 添加到income_ammount列。
因此,输出表与传输表完全不同,尽管所有需要的信息都已经存在。
到目前为止,我只通过一种方式获得了这些信息:

SELECT
    id_account_origin,
    SUM(t.amount) AS outcome_amount
FROM transfers t
GROUP BY t.id_account_origin;

它返回:

+-------------------+----------------+
| id_account_origin | outcome_amount |
+-------------------+----------------+
|             10009 |     2761390.87 |
|             10012 |        1000.00 |
|             10011 |      575877.56 |
|             10007 |      135002.61 |
+-------------------+----------------+

并且比上面预期的跨列容易得多。

qaxu7uf2

qaxu7uf21#

id_account_destination编写另一个查询。然后将它们与UNION组合以取消透视。

SELECT id_account, SUM(outcome_amount) AS outcome_amount, SUM(income_amount) AS income_amount
FROM (
    SELECT id_account_origin AS id_account, SUM(t.amount) AS outcome_amount, 0 AS income_amount
    FROM transfers t
    GROUP BY id_account
    UNION ALL
    SELECT id_account_destination AS id_account, 0 AS outcome_amount, SUM(-t.amount) AS income_amount
    FROM transfers t
    GROUP BY id_account
) AS x 
GROUP BY id_account
2w2cym1i

2w2cym1i2#

一种方法是对数据进行反透视,然后进行聚合。
在最近的MySQL版本中,我们可以使用横向连接,这避免了使用union all扫描表两次:

select x.id_account, 
    sum(x.income_amount) income_amount, 
    sum(x.outcome_amount) outcome_amount
from transfers t
cross join lateral (
    select t.id_account_destination, t.amount, 0 
    union all select t.id_account_origin, 0, t.amount
) x(id_account, income_amount, outcome_amount)
group by x.id_account

参考:MySQL - How to unpivot columns to rows?
这里是a small demo
样本数据:
| 身份证|id_account_destination|id_account_origin|数量|创建于|
| --------------|--------------|--------------|--------------|--------------|
| 1|1|二|一百|2023-05-04 19:59:37|
| 二|1|三|50块|2023-05-04 19:59:37|
| 三|四个|1|三十|2023-05-04 19:59:37|
结果:
| id_account|收入额|产出量|
| --------------|--------------|--------------|
| 1|一百五十|三十|
| 二|零点|一百|
| 三|零点|50块|
| 四个|三十|零点|

相关问题