2012-08-06 95 views
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 Fiddle

+0

你可以给样品期望的输出? – Omesh 2012-08-06 09:23:44

+0

@Omesh:看看最后的代码清单。 – 2012-08-06 09:36:29

+0

我一直在搞乱SQL小提琴,我不得不说我甚至不确定它在SQL中是否可能(尽管我远不是专家)。我认为如果你想在SQL中这样做,除非有一个我不知道的特殊技巧,否则你需要每天都有一个账户值。 – ApplePie 2012-08-06 11:25:13

回答

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 
+0

太棒了!谢谢!有没有办法将查询概括为显示某个日期的所有帐户的总和? – 2012-08-07 08:31:21

+0

@NickolayKolev @NickolayKolev如果你需要所有用户帐户的总和,只需更改'select created_at,sum(accAmount)from .....)AccountAmounts where created_at <= @ YourDate group by created_at order by created_at DESC LIMIT 1' – valex 2012-08-07 09:12:39

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 

我认为所有的日期字段都是uniq,正如你写的。

+0

之后谢谢,但这不是所需的输出。查看我试图实现的结果的最后一个代码清单。 – 2012-08-06 10:36:42

0

我不是一个大的MySQL用户,但我创建了一个查询,它适用于MS SQL Server。这不是特别的表现(3个子查询和一个Distinct,boo!),因此您可能想要考虑是否有更好的方法,而不是简单地在单个查询中进行派生。

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子查询添加LIMIT 1“DESC”后,补锅匠和直到MySQL是高兴的语法。我会去看看我是否可以转换它。

+0

MySQL不高兴在内部查询中访问“b.created_at”。根据其文档,这是预期的行为。 – 2012-08-07 08:42:31