从非审计跟踪表到审计跟踪表

时间:2015-11-10 03:16:04

标签: sql postgresql database-schema

在现有架构中,我仅为其中一个表引入审计跟踪/里程碑支持。为了讨论这个问题,我们将使用简化的玩具示例来更好地说明问题。

DEPARTMENT
ID   |  NAME  | CREATED_TS | MODIFIED_TS | VERSION
1    | "ABC"  | 11/20/2015 | 12/1/9999   | 1

现在,当每次{id} 1的department记录的更新请求进入时,系统会执行以下操作。基本上每次更新都是INSERT - 将现有记录的MODIFIED_TS更改为UPDATE次请求,最新记录的MODIFIED_TS始终保持为12/1/9999(aka { {1}} TIMESTAMP)

说更新ID = 1记录,其中名称已更改,以下是db。中的内容。

INFINITY

现在假设存在DEPARTMENT ID | NAME | CREATED_TS | MODIFIED_TS | VERSION 1 | "ABC" | 11/20/2015 | 11/22/2015 | 1 1 | "XYZ" | 11/22/2015 | 12/1/9999 | 2 表,其中EMPLOYEE作为外键。请注意,DEPT_ID表没有审计跟踪要求,因此那里没有EMPLOYEE时间戳或INFINITY概念。 VERSION表格如下所示

EMPLOYEE

对于与DEPT有FK关系的EMPLOYEE而言,一切都很好,其中DEPT之前有ID作为PK。现在EMPLOYEE ID | NAME | AGE | DEPT_ID 1 | "John" | 31 | 1 表的PK被更改为复合PK(ID,VERSION)

DEPARTMENT表的这些模式更改为其数据创建auit跟踪之后,DEPARTMENT中的FK将不得不以某种方式创建FK,不仅EMPLOYEE而且还DEPT_ID包含INFINITYMODIFIED_TS记录的DEPT时间戳(EMPLOYEE),因为DEPT将始终引用最新的EMPLOYEE记录(要求)

更改DEPT表的FK以指向Nov 9 02:16:59 ip-172-31-6-86 [service_variant=lms][openedx.core.djangoapps.user_api.helpers][env:sandbox] ERROR [ip-172-31-6-86 2138] [helpers.py:75] - An unexpected error occurred when calling 'request_password_change' with arguments '(u'ariestiyansyah.rizky@gmail.com', 'xxx.org', True)' and keyword arguments '{}': ValueError('incomplete format',) Traceback (most recent call last): File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_api/helpers.py", line 46, in _wrapped return func(*args, **kwargs) File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_api/accounts/api.py", line 403, in request_password_change use_https=is_secure File "/edx/app/edxapp/edx-platform/common/djangoapps/student/forms.py", line 78, in save email = loader.render_to_string(email_template_name, context) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/template/loader.py", line 171, in render_to_string return t.render(Context(dictionary)) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/template/base.py", line 140, in render return self._render(context) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/template/base.py", line 134, in _render return self.nodelist.render(context) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/template/base.py", line 823, in render bit = self.render_node(node, context) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/template/base.py", line 837, in render_node return node.render(context) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/template/defaulttags.py", line 31, in render output = self.nodelist.render(context) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/template/base.py", line 823, in render bit = self.render_node(node, context) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/template/base.py", line 837, in render_node return node.render(context) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/templatetags/i18n.py", line 151, in render result = result % data ValueError: incomplete format Nov 9 02:16:59 ip-172-31-6-86 [service_variant=lms][root][env:sandbox] ERROR [ip-172-31-6-86 2138] [exceptions.py:9] - Uncaught exception from <class 'django.core.handlers.wsgi.WSGIHandler'> Traceback (most recent call last): File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 109, in get_response response = callback(request, *callback_args, **callback_kwargs) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/views/decorators/http.py", line 41, in inner return func(request, *args, **kwargs) File "/edx/app/edxapp/edx-platform/lms/djangoapps/student_account/views.py", line 153, in password_change_request_handler request_password_change(email, request.get_host(), request.is_secure()) File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_api/helpers.py", line 76, in _wrapped raise api_error(msg) UserAPIInternalError: An unexpected error occurred when calling 'request_password_change' with arguments '(u'ariestiyansyah.rizky@gmail.com', 'xxx.org', True)' and keyword arguments '{}': ValueError('incomplete format',) Nov 9 02:16:59 ip-172-31-6-86 [service_variant=lms][django.request][env:sandbox] ERROR [ip-172-31-6-86 2138] [base.py:213] - Internal Server Error: /account/password Traceback (most recent call last): File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 109, in get_response response = callback(request, *callback_args, **callback_kwargs) File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/django/views/decorators/http.py", line 41, in inner return func(request, *args, **kwargs) File "/edx/app/edxapp/edx-platform/lms/djangoapps/student_account/views.py", line 153, in password_change_request_handler request_password_change(email, request.get_host(), request.is_secure()) File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_api/helpers.py", line 76, in _wrapped raise api_error(msg) UserAPIInternalError: An unexpected error occurred when calling 'request_password_change' with arguments '(u'ariestiyansyah.rizky@gmail.com', 'xxx.org', True)' and keyword arguments '{}': ValueError('incomplete format',) 表中最新记录的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

这是一个可怕的数据建模黑客,可以解决你的问题;不要在家里试试......

由于部门的PK是{id,modified_ts},员工的FK也必须是复合的(或者它可以指向另一组唯一的列)。 所以解决方案是给它想要的东西:一个具有恒定值'无穷大'的列。 ('infinity'是postgres中日期和时间戳的有效值,您不需要发明自己的哨兵值)

CREATE TABLE department
        ( id INTEGER NOT NULL
        , name varchar
        , created_ts timestamp
        , modified_ts timestamp
        , version integer not null default 0
        , PRIMARY KEY (id, modified_ts)
        );

INSERT INTO department (id, name, created_ts, modified_ts, version) VALUES
 (1  , 'ABC', '2015-11-20' , '2015-11-22' , 1) ,
 (1  , 'XYZ', '2015-11-22' , 'infinity'  , 2) ;

-- CREATE UNIQUE INDEX ON department (id) WHERE modified_ts = 'infinity'::timestamp;

-- Now assume there is an existing EMPLOYEE table with DEPT_ID as a foreign key. Note that EMPLOYEE table doesn't have an audit trail requirement so there is no INFINITY timestamp or VERSIONing concept there. EMPLOYEE table looks like as below

CREATE TABLE employee
        ( id INTEGER NOT NULL PRIMARY KEY
        , name varchar
        , age  integer not null default 0
        , modified_ts timestamp NOT NULL DEFAULT 'infinity'::timestamp CHECK (modified_ts = 'infinity'::timestamp)
        , dept_id INTEGER NOT NULL
        , FOREIGN KEY (id,modified_ts)
                REFERENCES department(id, modified_ts)
        );
INSERT INTO employee(id ,name,age,dept_id) VALUES
(1  , 'John'  , 31  , 1);
  • 一个FK真的不应该指向一个移动目标
  • 为了使上述工作,FK约束将需要DEFERRABLE INITIALLY DEFERRED
  • 但实际上你应该使用 stable 键,(并将路径移到另一张表中)
  • 在现实生活中, 员工和部门都应该允许历史记录,他们的(M:N)联结表也应如此。