3

次のシナリオを考えてみましょう: ユーザーは 1 つ以上の (銀行) 口座を持っています。アカウントの残高の履歴変更はテーブルで追跡されます。すべてのアカウントにわたって、ユーザーの資金の履歴を時系列で表示したいと考えています。これらはテーブル定義です:

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');

ユーザーは、アカウント全体で 1 日 1 回の入出金しか許可されていないため、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. NULL 値を無視して、手順 2 で見つかった金額を合計します。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

私は MySQL の熱烈なユーザーではありませんが、MS SQL Server で動作するクエリを作成しました。これは特にパフォーマンスが高いわけではない (3 つのサブクエリと 1 つの 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

MySQL に変換するには、TOP 1を削除し、b3 サブクエリの「DESC」の後にLIMIT 1を追加して、 MySQL が構文に満足するまで調整する必要があります。変換できるか試してみます。

于 2012-08-07T08:29:21.793 に答える
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 に答える