在连接表中求和

时间:2012-08-06 09:18:11

标签: mysql sql join sum unique

请考虑以下情形:用户拥有一个或多个(银行)帐户。账户余额的历史变化在表格中进行跟踪。我希望在他的所有帐户中及时显示用户资金的历史记录。这些是表格定义:

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `accounts` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
);


CREATE TABLE `balances` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `account_id` int(11) DEFAULT NULL,
  `amount` int(11) DEFAULT NULL,
  `created_at` date DEFAULT NULL,
  PRIMARY KEY (`id`)
);

以下是一些示例数据:

INSERT INTO `users` (`id`, `name`)
VALUES
  (1,'Bob');

INSERT INTO `accounts` (`id`, `user_id`)
VALUES
  (1,1),
  (2,1);

INSERT INTO `balances` (`id`, `account_id`, `amount`, `created_at`)
VALUES
  (1,1,100, '2012-01-01'),
  (2,1,150, '2012-01-02'),
  (3,2,1000,'2012-01-04'),
  (4,2,1100,'2012-01-08'),
  (5,1,175, '2012-01-10');

用户每个帐户只允许一次存款/取款,因此created_at值可视为唯一。

给定样本数据,我想写的查询结果应为:

|'2012-01-01'|100 |
|'2012-01-02'|150 |
|'2012-01-04'|1150|
|'2012-01-08'|1250|
|'2012-01-10'|1275|

计划如下:

  1. 从余额表中抓取所有独特日期。
  2. 对于每个日期,请选择每个帐户中的最新余额,以使余额的日期不超过步骤1中的日期。
  3. 将步骤2中找到的数量相加,忽略NULL值。 NULL值意味着该帐户的第一个记录余额是以后的日期。
  4. 我在制定第2步的条件时遇到了问题。

    MySQL Fiddle

3 个答案:

答案 0 :(得分:0)

我试过这个(用我的纯英语理解:);

SELECT b.created_at, Sum(amount) amount, u.id, u.name 
FROM balances b 
LEFT JOIN accounts a ON a.id=b.account_id 
LEFT JOIN users u ON u.id=a.user_id 
GROUP BY b.created_at 
ORDER BY b.created_at

得到了这个结果;

created_at  amount    id    name
2012-01-01  100       1     Bob
2012-01-02  150       1     Bob
2012-01-04  1000      1     Bob
2012-01-08  1100      1     Bob
2012-01-10  175       1     Bob

我认为你写的所有日期字段都是独立的。

答案 1 :(得分:0)

select user_id,created_at,sum(accAmount) from
(
select a.id account_id,a.user_id user_id, dt.created_at created_at,
( select amount from balances b3 where (b3.account_id=a.id)
and b3.created_at=
(select max(created_at) as lastAccDate from balances b
where b.created_at<=dt.created_at and b.account_id=a.id)
) AccAmount
from accounts a,
(select distinct created_at from balances) dt
) AccountAmounts
group by user_id,created_at
order by 2

答案 2 :(得分:0)

我不是一个大的MySQL用户,但我创建了一个适用于MS SQL Server的查询。它不是特别高效(3个子查询和一个独特的,嘘!),所以你可能想要考虑是否有更好的方法而不是简单地在单个查询中导出它。

SELECT
  b.created_at,
  SUM(b.amount),

  (
    SELECT SUM(acc_amt)
    FROM
      (
        SELECT DISTINCT b2.account_id,
        (
           SELECT TOP 1 b3.amount
           FROM balances AS b3
           WHERE b3.account_id = b2.account_id
           AND b3.created_at <= b.created_at
           ORDER BY b3.created_at DESC
        ) AS acc_amt
        FROM balances AS b2
        WHERE b2.created_at <= b.created_at
      ) temp_bal
  )

FROM
  balances AS b
GROUP BY
  b.created_at

要转换为MySQL,您需要删除 TOP 1 并在b3子查询中的'DESC'之后添加 LIMIT 1 ,然后修改直到MySQL为对语法感到满意。我会去看看我是否可以转换它。