답변:
당신이 있다고 가정 해 봅시다 FOO
관리자와 사용자가 업데이트 할 수 테이블이 합니다. 대부분의 경우 FOO 테이블에 대해 쿼리를 작성할 수 있습니다. 행복한 날들.
그런 다음 FOO_HISTORY
테이블을 만듭니다 . 여기에는 FOO
테이블 의 모든 열이 있습니다 . 기본 키는 FOO와 RevisionNumber 열을 더한 것과 같습니다. 에서 외래 키 FOO_HISTORY
가 FOO
있습니다. UserId 및 RevisionDate와 같이 개정과 관련된 열을 추가 할 수도 있습니다. 모든 *_HISTORY
테이블에서 (즉, Oracle 시퀀스 또는 이와 동등한) 계속해서 수정 번호를 채 웁니다 . 1 초에 한 번만 변경되는 것에 의존하지 마십시오 (즉 RevisionDate
기본 키에 넣지 마십시오 ).
이제 업데이트 할 때마다 업데이트 FOO
를 수행하기 직전에 이전 값을FOO_HISTORY
. 프로그래머가 실수로이 단계를 놓칠 수 없도록 설계의 일부 기본 수준에서이 작업을 수행합니다.
행을 삭제하려면 FOO
몇 가지 선택 사항이 있습니다. 캐스케이드 및 모든 히스토리를 삭제하거나 삭제 된 것으로 플래그 FOO
를 지정 하여 논리적 삭제를 수행하십시오 .
이 솔루션은 현재 값에 관심이 많고 때때로 이력에만 관심이있는 경우에 좋습니다. 항상 기록이 필요한 경우 효과적인 시작 및 종료 날짜를 입력하고 모든 레코드를 FOO
자체적으로 보관할 수 있습니다. 그런 다음 모든 쿼리는 해당 날짜를 확인해야합니다.
There is a foreign key from FOO_HISTORY to FOO'
: 나쁜 생각, 기록을 변경하지 않고 foo에서 레코드를 삭제하고 싶습니다. 히스토리 테이블은 정상적인 사용시 삽입 전용이어야합니다.
BI 세계에서는 버전을 지정할 테이블에 startDate 및 endDate를 추가하여이 작업을 수행 할 수 있습니다. 첫 번째 레코드를 테이블에 삽입하면 startDate가 채워지지만 endDate는 널입니다. 두 번째 레코드를 삽입하면 첫 번째 레코드의 endDate도 두 번째 레코드의 startDate로 업데이트합니다.
현재 레코드를 보려면 endDate가 널인 레코드를 선택하십시오.
이를 유형 2 느리게 변화하는 차원 이라고도합니다 . TupleVersioning 도 참조하십시오
SQL 2008로 업그레이드하십시오.
SQL 2008에서 SQL 변경 추적을 사용해보십시오. 타임 스탬프 및 삭제 표시 열 해킹 대신이 새로운 기능을 사용하여 데이터베이스의 데이터 변경 내용을 추적 할 수 있습니다.
SQL 트리거를 통해 SQL 테이블에 대한 감사를 수행 할 수 있습니다. 트리거에서 2 개의 특수 테이블 ( 삽입 및 삭제)에 액세스 할 수 있습니다. )에 . 이 테이블에는 테이블이 업데이트 될 때마다 삽입되거나 삭제 된 정확한 행이 포함됩니다. 트리거 SQL에서 이러한 수정 된 행을 가져 와서 감사 테이블에 삽입 할 수 있습니다. 이 접근 방식은 감사가 프로그래머에게 투명하다는 것을 의미합니다. 그들의 노력이나 구현 지식이 필요하지 않습니다.
이 접근 방식의 추가 이점은 데이터 액세스 DLL 또는 수동 SQL 쿼리를 통해 SQL 작업이 수행되었는지 여부에 관계없이 감사가 발생한다는 것입니다. 감사는 서버 자체에서 수행됩니다.
어떤 데이터베이스를 말하지 않고 게시 태그에 표시되지 않습니다. Oracle의 경우 Designer에 기본 제공되는 접근 방식 : 저널 테이블 사용을 권장 할 수 있습니다 . 다른 데이터베이스를위한 것이라면 기본적으로 같은 방법을 권장합니다 ...
다른 DB에서 복제하려는 경우 또는 이해하기 쉽도록 테이블의 경우 동일한 필드 사양을 가진 일반 데이터베이스 테이블과 섀도우 테이블이 생성되는 것이 작동 방식 , 마지막으로 수행 한 작업 (문자열, 삽입의 경우 "INS", 업데이트의 경우 "UPD", 삭제의 경우 "DEL"), 작업이 발생한 날짜 시간 및 수행 한 사용자 ID와 같은 추가 필드 그것.
트리거를 통해 테이블의 행에 대한 모든 조치는 저널 테이블에 새 값, 수행 된 조치,시기 및 사용자에 의해 새 행을 삽입합니다. 적어도 지난 몇 개월 동안은 행을 삭제하지 마십시오. 예, 수백만 행이 쉽게 커지지 만 어느 시점 에서나 모든 레코드 의 값을 쉽게 추적 할 수 있습니다. 저널링이 시작되거나 이전 저널 행이 마지막으로 삭제 된 마지막으로 변경했는지 누가 .
Oracle에서는 필요한 모든 것이 SQL 코드로 자동 생성되므로 컴파일 / 실행 만하면됩니다. 기본 CRUD 응용 프로그램 (실제로는 "R")과 함께 검사합니다.
나는 또한 같은 일을하고 있습니다. 수업 계획을위한 데이터베이스를 만들고 있습니다. 이러한 계획에는 원자 변경 버전 관리 유연성이 필요합니다. 다시 말해, 수업 계획에 대한 각 변경 사항은 아무리 작아도 허용되어야하지만 이전 버전도 그대로 유지해야합니다. 이렇게하면 수업 제작자는 수업 계획을 사용하는 동안 수업 계획을 편집 할 수 있습니다.
그것이 작동하는 방식은 일단 학생이 수업을 마치면 그 결과가 완성 된 버전에 첨부되는 것입니다. 변경하면 결과는 항상 버전을 가리 킵니다.
이런 방식으로 수업 조건을 삭제하거나 이동해도 결과는 변경되지 않습니다.
현재이 작업을 수행하는 방법은 하나의 테이블에서 모든 데이터를 처리하는 것입니다. 일반적으로 하나의 id 필드 만 가지고 있지만이 시스템에서는 id와 sub_id를 사용하고 있습니다. sub_id는 항상 업데이트 및 삭제를 통해 행과 함께 유지됩니다. ID는 자동 증분됩니다. 수업 계획 소프트웨어는 최신 sub_id에 연결됩니다. 학생 결과가 ID에 연결됩니다. 또한 변경 사항이 발생한 시점을 추적하기위한 타임 스탬프도 포함 시켰지만 버전 관리를 처리 할 필요는 없습니다.
테스트 한 후에 변경할 수있는 한 가지는 앞서 언급 한 endDate null 아이디어를 사용할 수 있다는 것입니다. 내 시스템에서 최신 버전을 찾으려면 max (id)를 찾아야합니다. 다른 시스템은 endDate = null을 찾습니다. 혜택에 다른 날짜 필드가 있는지 확실하지 않습니다.
내 두 센트
@WW 동안. 또 다른 방법은 버전 열을 만들고 모든 버전을 동일한 테이블에 유지하는 것입니다.
하나의 테이블 접근 방식은 다음 중 하나입니다.
outer join
.outer join
개정 번호를 사용 하는 메소드의 SQL 예 는 다음과 같습니다.
SELECT tc.*
FROM text_content tc
LEFT OUTER JOIN text_content mc ON tc.path = mc.path
AND mc.revision > tc.revision
WHERE mc.revision is NULL
AND tc.path = '/stuff' -- path in this case is our natural id.
나쁜 소식은 위와 outer join
외부 조인이 필요하다는 점 입니다. 좋은 소식은 트랜잭션없이 한 번의 쓰기 작업 (데이터베이스가 원자 적이 라고 가정 )으로 새 항목을 만드는 것이 이론적으로 더 저렴하다는 것 입니다.
에 대한 새로운 개정의 예 '/stuff'
는 다음과 같습니다.
INSERT INTO text_content (id, path, data, revision, revision_comment, enabled, create_time, update_time)
(
SELECT
(md5(random()::text)) -- {id}
, tc.path
, 'NEW' -- {data}
, (tc.revision + 1)
, 'UPDATE' -- {comment}
, 't' -- {enabled}
, tc.create_time
, now()
FROM text_content tc
LEFT OUTER JOIN text_content mc ON tc.path = mc.path
AND mc.revision > tc.revision
WHERE mc.revision is NULL
AND tc.path = '/stuff' -- {path}
)
이전 데이터를 사용하여 삽입합니다. 이것은 하나의 열만 업데이트하고 낙관적 잠금 및 / 또는 트랜잭션을 피하려는 경우 특히 유용합니다.
플래그 접근 및 히스토리 테이블 접근은 두 개의 행을 삽입 / 업데이트해야합니다.
outer join
개정 번호 접근 방식 의 또 다른 장점 은 트리거가 본질적으로 위와 같은 작업을 수행해야하기 때문에 나중에 트리거를 사용하여 다중 테이블 접근 방식으로 언제든지 리팩토링 할 수 있다는 것입니다.
Alok는 Audit table
위에서 제안 했으며 내 게시물에 설명하고 싶습니다.
프로젝트에서이 스키마가없는 단일 테이블 디자인을 채택했습니다.
개요:
이 테이블은 각 테이블에 대한 히스토리 레코드를 한 번에 한 레코드에 보유 할 수 있으며 완전한 오브젝트 히스토리는 한 레코드에 보유 할 수 있습니다. 이 테이블은 데이터가 변경되는 트리거 / 후크를 사용하여 채워질 수 있으며 대상 행의 이전 및 새 값 스냅 샷을 저장합니다.
이 디자인의 장점 :
이 디자인과 단점 :