2014-10-21 2 views
1

일일 계정 잔액을 포함하여 은행 계좌 정보를 저장해야하는 애플리케이션을 개발 중입니다. 예를 들면 그래서계정 잔액 : SQL에서 올바르게 계산하는 방법

:

17/10/2014 - (+) - Starting/Initial balance - 5,000.00 
17/10/2014 - (=) - Balance - 5,000.00 
- 
18/10/2014 - (-) - Payment - (1,000.00) 
18/10/2014 - (=) - Balance - 4,000.00 
- 
19/10/2014 - (=) - Balance - 4,000.00 
- 
20/10/2014 - (-) - Payment - (1,000.00) 
20/10/2014 - (=) - Balance - 3,000.00 

난 내가 매일 모든 계정 잔액을 저장할 수있는 특정 "account_balance"테이블을 만들 수 있다고 생각.

내가 잘못하면 가장 좋은 방법을 찾도록 도와 줄 수 있습니까? 그러나 맞다면 데이터베이스를 매일 일일 잔액을 계산할 수있게 만들고 특별히 사용자가 이전 값을 편집하기 시작할 때 어떻게 데이터베이스 업데이트 잔액을 만들 수 있습니까?

그리고 "나이 값"에 의해

가, 내 말은 :

1 - 이것은 "계정 A"문은 모습입니다 :

18/10/2014 - (+) - Starting/Initial balance - 5,000.00 
18/10/2014 - (=) - Balance - 5,000.00 
- 
19/10/2014 - (=) - Balance - 5,000.00 
- 
20/10/2014 - (=) - Balance - 5,000.00 

2 - 그러나 사용자가 소득을 등록하는 것을 잊었다, 그래서 그는 (이제 균형을 업데이트해야합니다) 새로운 소득을 추가하여 작업을 수행합니다

대신 저장 균형의
18/10/2014 - (+) - Starting/Initial balance - 5,000.00 
18/10/2014 - (+) - Sales commission - 2,500.00 <- USER ADDED THIS. 
18/10/2014 - (=) - Balance - 7,500.00 <- THIS BALANCE HAS BEEN UPDATED. 
- 
19/10/2014 - (=) - Balance - 7,500.00 <- THIS BALANCE HAS BEEN UPDATED. 
- 
20/10/2014 - (=) - Balance - 7,500.00 <- THIS BALANCE HAS BEEN UPDATED. 
+0

http://stackoverflow.com/questions/2494343/database-schema-design-for-a-double-entry-accounting-system 도움이 될 수 – radar

+0

무엇 단지 트랜잭션을 저장하고 뷰를 사용하는 방법에 대한 실제 잔액을 표시 하시겠습니까? –

+0

@RADAR 살펴보기로하겠습니다. 감사! – Felipe

답변

2

는 각 사용자의 트랜잭션을 저장하는 테이블이 있습니다.

예를 들어

:

Date   Transactions  Comment 
17/10/2014  +5,000.00   Starting/Initial balance - 
18/10/2014  -1,000.00   Payment 
20/10/2014  -1,000.00   Payment 

그런 다음 당신이 균형보기를 만들 수 있습니다 (같은) :

create view balance as 
    select userId, sum(transactions) as balance from TransactionTable group by userId 

당신이 (즉, 시작 및 종료 날짜보다 정확하고 포함 할 경우에 어느 시점에서든 균형을 잡을 수 있도록) parametrized view을 만들 수 있습니다 (날짜를 사용하여 시도하지 않았지만 잘 작동한다고 가정합니다).

+0

오른쪽. 그러나 서버 리소스는 어떻습니까? 이 방법을 사용하면 서버는 사용자가 새로운 필터 날짜를 입력 할 때마다 잔액을 계산해야합니다. 하루에 저울을 저장하면 데이터 만 복구됩니다. 하지만 ... 글쎄, 난 경험이 풍부한 사람이 아니야. 그래서 이것에 대해 어떻게 생각하십니까? – Felipe

+0

유효한 고려 사항. 적절한 인덱싱은 많은 도움이되지만 MySQL은 여전히 ​​모든 행을 합해야합니다. 많은 일은 사용자 당 하루에 예상되는 거래 수와 일일 잔액을 확인하는 데 필요한 거래 수에 따라 다릅니다. 그러나 이전 레코드를 업데이트 할 수 있기를 원한다면 이러한 종류의보기는 데이터가 항상 정확한지 확인해야합니다. –

1

이 답변은 OP가 원래 질문에 대한 의견에 대해 물었던 PostgreSQL에 대한 것입니다.

데이터 무결성이 가장 중요합니다. 그래서 나는 a) 성능이 좋지 않다면 집계 값을 저장하는 것을 꺼리고 b) dbms는 집계 값이 정확하다는 것을 보장 할 수있다.

이 표부터 시작했습니다. 이 같은 응용 프로그램은 일반적으로 타임 스탬프를 지원하기 위해을 필요로하고 있기 때문에 일반적인 경우에 날짜보다 더 수행해야하기 때문에

create table transactions (
    trans_id serial primary key, 
    cust_id integer not null, -- foreign key, references customers, not shown 
    trans_time timestamp not null default current_timestamp, 
    trans_amt numeric(14,2) not null 
); 

create index on transactions (cust_id); 

내가 대신 날짜의 타임 스탬프를 선택했다. 우리가 타임 스탬프로 좋은 성능을 얻으면, 우리는 날짜와 함께 좋은 성능을 얻을 수 있어야합니다. 단일 고객에 대한 타임 스탬프가 고유하다고 가정하지 않았습니다.

이 테이블에 2 천만 개의 임의 틱 데이터 행을로드 한 다음 통계를 업데이트했습니다. 데이터에는 양수 및 음수가 포함되었습니다. 시각적 검사를 쉽게하기 위해 금액은 수백 달러였습니다.

이러한 유형의 응용 프로그램에서보다 일반적인 쿼리 중 하나는 단일 고객에 대한 등록 (실행중인 잔액이있는 모든 트랜잭션)을 반환하는 것입니다.

처음 3 일 동안 고객 128에 대한 원시 데이터가 있습니다.

 
cust_id trans_time   trans_amt 
-- 
128  2014-01-01 08:36:09 200.00 
128  2014-01-01 14:18:10 200.00 
128  2014-01-01 14:26:56  0.00 
128  2014-01-01 18:17:31 400.00 
128  2014-01-01 20:18:53 100.00 
128  2014-01-02 00:10:35  0.00 
128  2014-01-02 01:44:26 300.00 
128  2014-01-02 15:49:31 -300.00 
128  2014-01-03 00:33:23 400.00 
128  2014-01-03 11:55:13 -200.00 
128  2014-01-03 11:56:34 -100.00 
128  2014-01-03 14:58:42 -400.00 
128  2014-01-03 17:31:11  0.00 

처음 3 일 동안이 금액을 예상해야합니다.

 
2014-01-01 900.00 
2014-01-02  0.00 
2014-01-03 -300.00 

그리고 처음 3 일 동안의 잔액은 다음과 같아야합니다. 매일 균형 레지스터

실행 계획에 대한

select 
     cust_id 
    , trans_date 
    , sum(daily_amt) over (partition by cust_id order by trans_date) daily_balance 
from (select 
      cust_id 
      , trans_time::date trans_date 
      , sum(trans_amt) daily_amt 
     from transactions 
     where cust_id = 128 
     group by cust_id, trans_date) x 
order by cust_id, trans_date; 
 
cust_id trans_date daily_balance 
-- 
128  2014-01-01 900.00 
128  2014-01-02 900.00 
128  2014-01-03 600.00 
. . . 

실행 계획의

 
2014-01-01 900.00 
2014-01-02 900.00 
2014-01-03 600.00 

레지스터 보여줍니다 12 밀리 실행 위의 쿼리가. 나는 이런 종류의 응용이 합리적이라고 생각하지만 식 (trans_time::date)이나 복합 색인을 색인화하여 실행 시간을 12 밀리 초 이하로 줄일 수 있습니다.

 
"WindowAgg (cost=7232.14..7252.94 rows=1040 width=40) (actual time=11.728..12.093 rows=294 loops=1)" 
" -> Sort (cost=7232.14..7234.74 rows=1040 width=40) (actual time=11.700..11.733 rows=294 loops=1)" 
"  Sort Key: transactions.cust_id, ((transactions.trans_time)::date)" 
"  Sort Method: quicksort Memory: 38kB" 
"  -> HashAggregate (cost=7156.62..7169.62 rows=1040 width=16) (actual time=11.392..11.466 rows=294 loops=1)" 
"    -> Bitmap Heap Scan on transactions (cost=39.66..7141.89 rows=1964 width=16) (actual time=0.839..9.753 rows=1961 loops=1)" 
"     Recheck Cond: (cust_id = 128)" 
"     -> Bitmap Index Scan on transactions_cust_id_idx (cost=0.00..39.17 rows=1964 width=0) (actual time=0.501..0.501 rows=1961 loops=1)" 
"       Index Cond: (cust_id = 128)" 
"Total runtime: 12.272 ms" 
+0

위대한 답변과 설명에 감사드립니다! 하지만 MySQL로 할 수 있습니까? 큰 차이점이 있습니까? – Felipe

+0

MySQL은 창 함수 또는 창 집합체를 지원하지 않으므로 MySQL에서는 다른 방식으로 처리해야합니다. 성능은 떨어지지 만 여전히 충분히 빠를 수 있습니다. 시간이되면 MySQL 용으로 다시 작성하겠습니다. –

+0

마이크, 당신의 제안 (PostgreSQL과 함께) 후에 두 데이터베이스의 차이점과 사용 사례에 대한 기사를 읽었습니다. PostgreSQL은 좋은 선택 인 것 같습니다. 어쨌든, MySQL 접근 방식은 훌륭합니다! PostgreSQL에는 MySQL Workbench와 비슷한 것이 있습니까? 나는 데비안에있어 저장소에서 아무 것도 찾지 못했습니다. – Felipe

관련 문제