2016-07-21 6 views
0

2 테이블을 만들었습니다 : INFORMATIONFEED.동일한 테이블의 다른 열에 값을 삽입/업데이트/삭제할 때 열에 값이 자동으로 반영되도록하는 방법은 무엇입니까?

INFORMATION has 2 attributes : ID(Primary Key), TOT_AMOUNT. 

FEED has 4 attributes : ID(Foreign key refer INFORMATION(ID)), S_AMOUNT, S_DATE, TOT_REM. 

는 지금, 나는 S_AMOUNTTOT_AMOUNT의 삽입/제거/업데이트에 따라,// ​​업데이 트를 삽입 TOT_REM로/값을 삭제해야합니다.

샘플 내용은 다음과 같습니다

INFORMATION Table 
------------------ 
ID | TOT_AMOUNT 
1 | 100 
2 | 20 
3 | 50 
... 

       FEED Table 
---------------------------------------- 
ID | S_AMOUNT | S_DATE | TOT_REM 
1 |  10  |10.10.2010| 90 
1 |  10  |13.10.2010| 80 
1 |  30  |17.10.2013| 50 
1 |  10  |20.10.2016| 40 
... 

우리는 자동으로 TOT_AMOUNT & S_AMOUNT의 도움으로/업데이트/삽입을 기반으로, TOT_REM 속성에 값을 삽입 작업이 S_AMOUNT 수행 삭제해야합니다. 언제든지

이 TOT_REM가 0보다 작은 수 없으며, TOT_REM 자동/제거/삽입 업데이트해야하는 등 그

TOT_REM for i(at a specific date) = (TOT_AMOUNT for ID=i) - 
            SUM(S_AMOUNT of all instances of ID=i, 
            which is later than the S_DATE for ID=i); 

그래서, 우리는 2 튜플 (1을 삭제하면 가정, 10 '13 .10.2010 ', 80)의 반사 BR_FEED 상태이어야한다 : I가

ORA-04091: table SSUMAN.FEED is mutating, trigger/function may not see it 
실패를 나타내는 트리거를 썼다
   FEED Table 
---------------------------------------- 
ID | S_AMOUNT | S_DATE | TOT_REM 
1 |  10  |10.10.2010| 90 
1 |  30  |17.10.2013| 60 
1 |  10  |20.10.2016| 50 
... 

트리거 617,451,515,

코드는 다음과 같습니다

CREATE OR REPLACE TRIGGER BR_INSERT_TRB 
AFTER DELETE OR INSERT OR UPDATE OF S_AMOUNT ON FEED 
FOR EACH ROW 
BEGIN 

IF DELETING THEN 
UPDATE FEED bf 
SET  bf.TOT_REM = bf.S_AMOUNT + :OLD.S_AMOUNT; 
END IF; 

IF INSERTING THEN 
INSERT INTO FEED (TOT_REM) VALUES(
((SELECT TOT_AMOUNT FROM INFORMATION bi WHERE bi.ID=:NEW.ID) - 
(SELECT SUM(S_AMOUNT) FROM FEED bf where bf.ID=:NEW.ID) - 
:NEW.S_AMOUNT); 
END IF; 

IF UPDATING THEN 
UPDATE FEED bf 
SET  bf.TOT_REM = (SELECT TOT_AMOUNT FROM BR_INFORMATION bi WHERE bi.ID=bf.ID) - 
(SELECT SUM(S_AMOUNT) FROM FEED bf where bf.ID=:NEW.ID) - 
:NEW.S_AMOUNT 
WHERE :NEW.ID IS NOT NULL; 
END IF; 

END; 

질문 :

  1. 이 방법은

    을 결함이 있습니까? 이 방법으로 원하는 것을 달성 할 수 없습니까? [선택 사항]
  2. 여기에 볼 수있는 범위가 있습니까? 나는 그 라인에서 생각할 수 없다! 아마, 경험 부족은 ... [선택] 그 TOT_REM 값이 자동으로 반영 할 수 있도록
  3. 더 나은 접근? 나는 뷰를 생성하는 것이 좋습니다 생각
+0

"TOT_REM은 0보다 작을 수 없습니다"라고 말하면 TOT_REM을 계산하는 논리의 일부로, 또는 TOT_REM이 음수가 될 수 있으므로 문제의 삽입/업데이트/삭제가 거부되어야합니까? 이 둘은 매우 다르며 다른 방식으로 해결됩니다. – mathguy

+0

@mathguy - 설명을 요구해 주셔서 감사합니다. 다른 세부 정보가 필요합니까? –

+0

여기 몇 가지 어려움이 있습니다. Biggest는 처음에 TOT_REM을 계산하는 것입니다. 10.10.2010 행을 삭제하면 다음 행의 TOT_REM은 위의 행 대신 정보 테이블에서 읽어야합니다. 첫 번째 행 (10.10.2010 이상) 위에 행을 추가하면 10.10.2010 TOT_ROM이 INFORMATION 대신에 위 행을 기준으로 계산되어야합니다. 더 큰 문제는 여전히 : TOT_ROM을 음수로 만들기 때문에 행을 거부합니다. 나중에 더 오래된 날짜가있는 행을 제거하면 ... 처음에 거절 한 행을 다시 가져와야합니까? – mathguy

답변

1

을 [강제는 대답하기 위해]. 이

테스트 데이터

create table feed(ID,S_AMOUNT,S_DATE) as (
    SELECT 1,10, TO_DATE('10.10.2010','dd.mm.yyyy') FROM dual UNION all 
    SELECT 1,10,TO_DATE('13.10.2010','dd.mm.yyyy') FROM dual UNION all 
    SELECT 1,30,TO_DATE('17.10.2013','dd.mm.yyyy') FROM dual UNION all 
    SELECT 2,10,TO_DATE('20.10.2016','dd.mm.yyyy') FROM dual) 

create table INFORMATION (id, TOT_AMOUNT) as (
    SELECT 1,100 FROM DUAL UNION ALL 
    SELECT 2,20 FROM DUAL UNION ALL 
    SELECT 3,50 FROM DUAL) 

쿼리

create or replace view result_feed as 
    SELECT f.*,i.TOT_AMOUNT - NVL(SUM(S_AMOUNT) OVER(PARTITION BY f.ID ORDER BY f.S_DATE),0) AS tot_rem FROM FEED f, INFORMATION i 
    WHERE f.ID = i.id 
    ORDER BY f.ID, f.S_DATE; 
    -- used NVL to prevent side-effect of null values 


    SELECT * from RESULT_FEED; 

트리거가이 상황에서 적합하지 않습니다와 가진 당신의 접근 방식 봐. 데이터가 거의 추가되지 않고 쿼리가 특수한 경우에만 필요하다고 생각합니다. 물론 테이블 (패키지 변수, 복합 트리거, 자율 트랜잭션)을 회피하는 해결 방법에는 몇 가지 접근법이 있지만 나는 데이터베이스에 성능 문제 만 추가한다고 생각합니다. 이 내 비즈니스 문제, 그리고 내가 (귀하의 경우 가능하지 않을 수있는) 처음부터 시작할 수 있다면있는 그대로, 나는 FEED에서 TOT_REM 열을 제거 할

+0

감사합니다. 도움이되었으며 내 문제를 해결했습니다. 가상 컬럼을 사용하지 않고 뷰를 선호하는 이유는 무엇입니까? –

+0

@Am_I_Helpful이 경우에는 분석 함수가 사용되지 않기 때문에 가상 열을 사용하지 않습니다. (분석 함수가없는 상태에서 로직을 구현하는 방법을 모르겠습니다). 미래를 위해 : 일부 복잡한 쿼리에서 조건 자로 사용되거나 제약 조건으로 사용되는 경우 가상 열을 사용하거나 일부 목적을 위해 인덱스가 필요합니다. 일부 개발자는 자신의 비즈니스가 복잡한 논리를 가지고 있고보기 대신 테이블을 사용하는 것이 좋다고 말하면서 뷰를 좋아하지 않습니다. 일반적으로 사용자 데이터에 대한 일부 보고서 또는 일부 추상화 결과로 뷰를 사용했습니다. –

1

, 나는 INFORMATION 테이블을 유지하는 것, 나는 것 현재 FEED 테이블처럼 보이는 뷰를 생성하십시오.뷰 정의에 필요한 모든 로직을 작성할 수 있습니다.

ADDED :

먼저, 여기에서 정의하는 도면이다; 기본 테이블 INFORMATIONFEEDTOT_REM 열이 FEED에없는 OP로 설명 된 것과 같습니다.

create view remaining_balance (id, s_amount, s_date, tot_rem) as 
select i.id, f.s_amount, f.s_date, 
     i.tot_amount - nvl(sum(f.s_amount) over (partition by f.id order by f.s_date), 0) 
from information i left outer join feed f 
        on i.id = f.id 
; 

보기는 FEED 어떠한 대응하는 행이없는 INFORMATION 테이블에서 id 년대를 포함하는, 외부 조인 이용한다. (그리고, I는 0NULL 변환 할 nvl() 함수를 사용 TOT_REM 계산에 널을 처리한다.) 여기서

뷰 실행의 예이다 : 지금

SQL> select * from information; 

     ID TOT_AMOUNT 
---------- ---------- 
     1  100 
     2   20 
     3   50 

3 rows selected. 

SQL> select * from feed; 

     ID S_AMOUNT S_DATE 
---------- ---------- ---------- 
     1   10 2010-10-10 
     1   10 2010-10-13 
     1   30 2010-10-17 
     1   10 2016-10-20 

4 rows selected. 

SQL> select * from remaining_balance order by id, s_date; 

     ID S_AMOUNT S_DATE  TOT_REM 
---------- ---------- ---------- ---------- 
     1   10 2010-10-10   90 
     1   10 2010-10-13   80 
     1   30 2010-10-17   50 
     1   10 2016-10-20   40 
     2        20 
     3        50 

6 rows selected. 

를 잘 -을 복잡한 제약 조건을 적용하는 기존 방법은 구체화 된보기를 사용하는 것입니다. 완전한 점검 제한 조건은 행 레벨에서만 작동하며 조건에 둘 이상의 테이블이 관련된 경우에는 사용할 수 없습니다. 현재 문제에서 검사는 두 테이블에 대해 수행되며 TOT_REMFEED 테이블의 다른 행에 따라 달라 지므로 FEED 테이블의 제약 조건이 작동하지 않습니다.

구체화 된보기 접근법은 작성한 것과 같은 뷰를 구체화 된보기로 정의하여 refresh fast on commit으로 정의하고 (기본 테이블에서 DML 조작 직후에 제한 조건이 점검되도록), 구체화 된보기에서 제한 조건을 점검하십시오. 현재 당면한 문제는 TOT_RM >= 0입니다.

아아, refresh fast on commit은 뷰 정의가 분석 함수를 사용하는 경우 (최소한 내가 소유하고있는 Oracle 버전 11.2 이상) 금지됩니다. sum() 함수의 분석 버전을 사용 했으므로 작동하지 않습니다.

아래와 같은 다른 뷰를 구체화 정의하지만, 이해하는 것이가 유일하게 남아있는 잔액을 표시하도록되어 있기 때문에

create materialized view remaining_balance (id, tot_rem) as 
select i.id, i.tot_amount - f.sum_s_amount 
from information i inner join (select id, sum(s_amount) as sum_s_amount 
           from  feed 
           group by id) f 
        on i.id = f.id 
; 

SQL> select * from remaining_balance; 

     ID TOT_REM 
---------- ---------- 
     1   40 

나는, 외부 더 이상 조인을 사용하지 않습니다. 나는 INFORMATION 확신이 아닌 음수 할 TOT_AMOUNT에 대한 점검 제한 조건을 가지고 있으며, FEED에서 idINFORMATION에서 id에 기본 키를 가리키는 가정, 그래서보기이 버전의 외부 조인에 의해 밝혀 추가 정보가 없습니다. (그러나 원하는 경우 모든 id을 포함하도록 만들 수 있습니다).

refresh fast on commit으로보기를 정의하고 tot_rem >= 0 효과에 점검 제한 조건을 추가 할 수 있어야합니다. 아아, 나는 그것을 시험 할 수 없다. 고급 복제 (구체화 된보기 로그를 작성하는 데 필요하며 차례로 refresh fast에 필요함)는 Oracle의 무료 Express 버전에서 사용할 수 없거나 사용할 수 없습니다. 이것을 시도해보십시오 - 필요한 솔루션 일 수 있습니다. 행운을 빕니다!

+0

뷰 정의 (코드)를 확장 할 수 있습니까? 뷰의 정의를 디자인 할 수 없었습니다. –

+0

할 수는 있지만 필요한 솔루션이 실제로 제약 사항 일 경우 도움이되지 않습니다. – mathguy

+0

정말 좋은 답변입니다. 불행히도 s_date 부분은 포함되지 않으므로 달성 할 수 없으므로 (피드 테이블에서 원했던 부분). 어쨌든 고마워. 이 대답으로 인해 여러 가지 새로운 것을 배웠습니다. –