3

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

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 值意味着该帐户的第一个记录余额用于以后的日期。

我无法为步骤 2 制定条件。

MySQL 小提琴

4

3 回答 3

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

我认为您所写的所有日期字段都是唯一的。

于 2012-08-06T10:06:23.570 回答
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
于 2012-08-06T13:31:56.270 回答
0

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

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

To convert to MySQL you'll need to remove the TOP 1 and add a LIMIT 1 after 'DESC' in the b3 sub query, and tinker until MySQL is happy with the syntax. I will have a go and see if I can convert it.

于 2012-08-07T08:29:21.793 回答