이전 및 실제 행 값을 기반으로 행 값 계산


9

여러분 안녕하세요, 도와 주셔서 감사합니다.
나는 id (int), stmnt_date (date), debit (double), credit (double) 및 balance (double) 필드를 포함하는 statement라는 테이블이 있습니다.내 테이블의 구조

다음 규칙에 따라 잔액을 계산하고 싶습니다.

첫 번째 행 잔액 ( 시간순 ) = 차변 대변 및 나머지 행

현재 행 잔액 = 시간순으로 이전 행 잔액 + 현재 행 차변-현재 행 크레딧

위 그림에서 알 수 있듯이 행은 날짜별로 정렬되지 않았으므로 stmnt_date 값의 중요성을 강조하기 위해 시간순으로 단어를 두 번 사용했습니다.

당신의 도움을 주셔서 대단히 감사합니다.


직불 및 신용 필드를 하나의 필드로 결합 할 수 있습니까? 그렇다면 음수 값을 차변으로 사용하고 양수 값을 신용으로 사용할 수 있습니다.
Mike

1
향후 질문 (답변이 있기 때문에)은 인쇄 화면이 아닌 텍스트로 코드를 게시하십시오. 또한 CREATE TABLE문과 샘플 데이터를 포함합니다 (with INSERT).
ypercubeᵀᴹ

당신의 응답 @ypercube에 경의,이 I를 읽는 사람을 위해 아래 표와 INSERT 예를 CREATE 추가 dba.stackexchange.com/a/183207/131900
잭 모리스

답변:


8

그 가정 stmnt_dateUNIQUE제약이 창 / 분석 기능을 매우 쉽게 될 것이다 :

SELECT 
    s.stmnt_date, s.debit, s.credit,
    SUM(s.debit - s.credit) OVER (ORDER BY s.stmnt_date
                                  ROWS BETWEEN UNBOUNDED PRECEDING
                                           AND CURRENT ROW)
        AS balance
FROM
    statements AS s
ORDER BY
    stmnt_date ;

불행히도 MySQL은 아직 분석 기능을 구현하지 않았습니다. 엄격한 SQL, 테이블을 자체 조인 (100 % 작업하더라도 다소 비효율적 임)하거나 특정 MySQL 기능인 변수 (매우 효율적이지만 테스트해야 함)를 사용하여 문제를 해결할 수 있습니다. mysql을 업그레이드 할 때 결과가 여전히 정확하고 최적화 개선으로 인해 엉망이되지 않도록하십시오)

SELECT 
    s.stmnt_date, s.debit, s.credit,
    @b := @b + s.debit - s.credit AS balance
FROM
    (SELECT @b := 0.0) AS dummy 
  CROSS JOIN
    statements AS s
ORDER BY
    stmnt_date ;

데이터를 사용하면 다음과 같은 결과가 발생합니다.

+------------+-------+--------+---------+
| stmnt_date | debit | credit | balance |
+------------+-------+--------+---------+
| 2014-05-15 |  3000 |      0 |    3000 |
| 2014-06-17 | 20000 |      0 |   23000 |
| 2014-07-16 |     0 |   3000 |   20000 |
| 2014-08-14 |     0 |   3000 |   17000 |
| 2015-02-01 |  3000 |      0 |   20000 |
+------------+-------+--------+---------+
5 rows in set (0.00 sec)

6

나는 당신이 다음을 시도 할 수 있다고 생각합니다.

set @balance := 0;

SELECT stmnt_date, debit, credit, (@balance := @balance + (debit - credit)) as Balance
FROM statements
ORDER BY stmnt_date;

2

ypercube의 답변 은 매우 훌륭합니다 (나는 더미 선택을 통해 단일 쿼리 내에서 변수 생성을 본 적이 없었습니다). 여기에 편의를 위해 CREATE TABLE 문이 있습니다.

Google 이미지 검색의 표 형식 데이터 이미지의 경우 https://convertio.co/ocr/ 또는 https://ocr.space/ 를 사용 하여 텍스트 문서로 변환 할 수 있습니다. 그런 다음 OCR이 열을 제대로 감지하지 못하고 Mac이있는 경우 옵션 키를 누른 상태에서 TextWrangler 를 사용하여 사각형을 선택 하고 열을 이동하십시오. Sequel Pro , TextWrangler와 같은 SQL 편집기와 Google Docs 와 같은 스프레드 시트를 조합 하면 탭으로 구분 된 표 형식 데이터를 매우 효율적으로 처리 할 수 ​​있습니다.

이 모든 것을 의견에 넣을 수 있다면이 답변을 찬성하지 마십시오.

-- DROP TABLE statements;

CREATE TABLE IF NOT EXISTS statements (
  id integer NOT NULL AUTO_INCREMENT,
  stmnt_date date,
  debit integer not null default 0,
  credit integer not null default 0,
  PRIMARY KEY (id)
);

INSERT INTO statements
(stmnt_date  , debit, credit) VALUES
('2014-06-17', 20000, 0     ),
('2014-08-14', 0    , 3000  ),
('2014-07-16', 0    , 3000  ),
('2015-02-01', 3000 , 0     ),
('2014-05-15', 3000 , 0     );

-- this is slightly modified from ypercube's (@b := 0 vs @b := 0.0)
SELECT 
    s.stmnt_date, s.debit, s.credit,
    @b := @b + s.debit - s.credit AS balance
FROM
    (SELECT @b := 0) AS dummy 
CROSS JOIN
    statements AS s
ORDER BY
    stmnt_date ASC;

/* result
+------------+-------+--------+---------+
| stmnt_date | debit | credit | balance |
+------------+-------+--------+---------+
| 2014-05-15 |  3000 |      0 |    3000 |
| 2014-06-17 | 20000 |      0 |   23000 |
| 2014-07-16 |     0 |   3000 |   20000 |
| 2014-08-14 |     0 |   3000 |   17000 |
| 2015-02-01 |  3000 |      0 |   20000 |
+------------+-------+--------+---------+
5 rows in set (0.00 sec)
*/

1

자체 조인 테이블 큰 테이블에서는 그리 빠르지 않습니다. PostgreSQL 에서이 작업을 처리하기 위해 저장된 필드 "밸런스"를 계산하기 위해 트리거 기능을 사용하기로 결정했습니다. 모든 계산은 각 행마다 한 번만 발생합니다.

DROP TABLE IF EXISTS statements;

CREATE TABLE IF NOT EXISTS statements (
  id BIGSERIAL,
  stmnt_date TIMESTAMP,
  debit NUMERIC(18,2) not null default 0,
  credit NUMERIC(18,2) not null default 0,
  balance NUMERIC(18,2)
);

CREATE OR REPLACE FUNCTION public.tr_fn_statements_balance()
RETURNS trigger AS
$BODY$
BEGIN

    UPDATE statements SET
    balance=(SELECT SUM(a.debit)-SUM(a.credit) FROM statements a WHERE a.stmnt_date<=statements.stmnt_date)
    WHERE stmnt_date>=NEW.stmnt_date;

RETURN NULL;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

CREATE TRIGGER tr_statements_after_update
  AFTER INSERT OR UPDATE OF debit, credit
  ON public.statements
  FOR EACH ROW
  EXECUTE PROCEDURE public.tr_fn_statements_balance();


INSERT INTO statements
(stmnt_date  , debit, credit) VALUES
('2014-06-17', 20000, 0     ),
('2014-08-14', 0    , 3000  ),
('2014-07-16', 0    , 3000  ),
('2015-02-01', 3000 , 0     ),
('2014-05-15', 3000 , 0     );


select * from statements order by stmnt_date;

-1

예를 들어, MSSQL에서 :

with () 문을 사용하여 CTE를 생성하십시오. 이것은 본질적으로 각 행의 값을 표시하는 임시 결과 집합입니다. with 문에서 math를 사용하여 마지막에 열을 만들 수 있으며 math를 사용하여 행의 총계가 DEBIT-CREDIT임을 표시 할 수 있습니다. with 문에서 각 행에 행 번호를 지정하고 WITH ()의 OVER 절을 사용하여 stmnt_date로 정렬하십시오.

그런 다음 a.ROWNUMBER = b.ROWNUMBER-1 또는 +1을 사용하여이 행과 이전 행의 a.total + b.total = 총계를 참조 할 수 있도록 테이블을 재귀 적으로 결합합니다.

코드를 제공하지 않아서 고맙지 만 이것이 달성하기위한 실용적인 방법입니다. 요청하면 코드를 제공 할 수 있습니다 :)


1
문제는 MySQL에 관한 것입니다. Postgres, SQL-Server, DB2, Oracle 등과 같은 DBMS에서 CTE 또는 창 기능 으로이 작업을 수행하는 방법에 대한 코드를 제공하는 것은 나쁘지 않지만 (목록이 길다) 적어도 MySQL 에서이 작업을 수행하는 방법에 대한 코드를 제공해야합니다.
ypercubeᵀᴹ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.