用于连接父子审计表的 Postgres SQL

发布于 2024-09-26 05:07:10 字数 2344 浏览 6 评论 0原文

我们使用 "1 审核表对于每个受监控的表” 设计;但是,在我们的示例中,emp(PARENT) 表有一个子表 emp_address,也需要对其进行监控,因此我们有 emp_auditemp_addr_audit 表

postgres 审计 SQL:如何连接 PARENT 和 CHILD 表以进行报告。

/* Employee table */    
create table emp (
 emp_id integer primary key,
 empnum  integer,
 empname varchar(50),
);

/* Address table */    
create table emp_addr (
 addr_id integer primary key,
 emp_id integer, -- references table emp
 line1 varchar(30),
);

/* Audit table for emp table */    
create table emp_audit (
 operation   character(1),
 emp_id integer,
 empnum  integer,
 empname varchar(50),
 updatetime timestamp,
 txid bigint
);

/* Audit table for emp_addr table */    
create table emp_addr_audit (
 operation   character(1),
 addr_id integer,
 emp_id integer,
 line1 varchar(30),
 updatetime timestamp,
 txid bigint
);

我们使用 hibernate(java) 来实现持久性,并且 hibernate 仅更新那些在更新操作中修改了列的表。鉴于此,我可能在 emp_addr_audit 表中拥有多行(例如 5 行),而 emp_audit 表中的 1 行。反之亦然。

每笔交易(修改)报告需要 1 行。 该报告将包含以下列

empname、line1、操作(插入/删除/更新)、更新时间

让我们考虑 2 个场景来了解所需内容:

  1. 在初始事务中,仅创建 emp 属性。然后在单独的事务中,创建 emp_addr 中的相应行。因此,现在,emp_audit 表中有 1 行,emp_addr_audit 表中有 1 行。该报告将有 2 行(每笔交易各一行)。
  2. empemp_addr 属性都是在单个事务中创建的。这将确保 emp_audit 中有 1 行,emp_addr_audit 中有 1 行。现在,报告将只有 1 行(因为两个表行都是在单个事务中创建的)。

场景
事务#1:我在 emp 和 emp_addr 中插入一行。这会在 emp_audit 和 emp_addr_audit 中各生成一行。(插入)
事务#2:我更新了上面的 emp' 属性。这会在 emp_audit 中产生 UPDATE 行。
事务#3:我更新了上面的 emp_addr 的属性。这会导致 emp_addr_audit 中出现 UPDATE 行。

我尝试了以下 SQL #1,它返回了 3 行(如预期);

SQL #1

SELECT emp.*, addr.*
 FROM  emp_audit emp 
 FULL OUTER JOIN emp_addr_audit addr USING(emp_id, txid);

但是,当我向 SQL 添加 where 子句时,它仅返回 2 行。丢失的行是事务 #3 的结果,其中仅 emp_addr 表行被更新,而 emp 表行未受影响。
SQL #2

SELECT emp.*, addr.*
 FROM  emp_audit emp 
        FULL OUTER JOIN emp_addr_audit addr USING(emp_id, txid);
WHERE  emp.empnum = 20;

什么 SQL仍然能够为我的 3 个事务获取 3 行,以便我仍然可以根据 empnum 进行过滤?

We're using a "1 audit table for each monitored Table" design; However, in our case emp(PARENT) table has a child table emp_address which also needs to be monitored, so we have emp_audit and emp_addr_audit tables.

postgres audit SQL : how to join PARENT and CHILD tables for reporting purposes.

/* Employee table */    
create table emp (
 emp_id integer primary key,
 empnum  integer,
 empname varchar(50),
);

/* Address table */    
create table emp_addr (
 addr_id integer primary key,
 emp_id integer, -- references table emp
 line1 varchar(30),
);

/* Audit table for emp table */    
create table emp_audit (
 operation   character(1),
 emp_id integer,
 empnum  integer,
 empname varchar(50),
 updatetime timestamp,
 txid bigint
);

/* Audit table for emp_addr table */    
create table emp_addr_audit (
 operation   character(1),
 addr_id integer,
 emp_id integer,
 line1 varchar(30),
 updatetime timestamp,
 txid bigint
);

We're using hibernate(java) for persistence and hibernate updates only those tables whose columns were modified in the update operation. Given this, I might have multiple(say, 5) rows in the emp_addr_audit table for 1 row in emp_audit table. And vice-versa as well.

The report needs 1 row for each transaction(modification).
The report will have the following columns

empname, line1, operation(insert/delete/update), updatetime

Let's consider 2 scenarios to understand what's needed:

  1. In the initial transaction only emp attributes are created. Then in a separate transaction, the corresponding row in emp_addr is created. So, now, we have 1 row in emp_audit table and 1 row in emp_addr_audit table. The report will have 2 rows (one each for each transaction).
  2. Both emp and emp_addr attributes are created in a single transaction. This will ensure that there is 1 row in emp_audit and 1 row in emp_addr_audit. Now, the report will have ONLY 1 row (since both table rows were created in a single transaction).

Scenario :
Transaction #1 : I insert a row into both emp and emp_addr. This results in a row each in emp_audit and emp_addr_audit.(INSERT)
Transaction #2 : I update the above emp' attribute. This results in a UPDATE row in emp_audit.
Transaction #3 : I update the above emp_addr's attribute. This results in a UPDATE row in emp_addr_audit.

I tried the following SQL #1 and it returned 3 rows (as expected);

SQL #1

SELECT emp.*, addr.*
 FROM  emp_audit emp 
 FULL OUTER JOIN emp_addr_audit addr USING(emp_id, txid);

However, when I added a where clause to the SQL, it returns only 2 rows. The missing row was the result of Transaction #3, where only emp_addr table row was UPDATED and emp table row was untouched.
SQL #2

SELECT emp.*, addr.*
 FROM  emp_audit emp 
        FULL OUTER JOIN emp_addr_audit addr USING(emp_id, txid);
WHERE  emp.empnum = 20;

What SQL will STILL be able to get me 3 rows for the 3 transactions so that I can still filter out based on empnum ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

初心未许 2024-10-03 05:07:10

FULL JOIN 将从两个表创建一个表,并用 NULL 值填充空(不匹配)行。当您仅选择 emp.empnum = 20 的行时,它当然不会返回 emp.empnum 中具有 NULL 的最后一行。

也许您可以仅在 emp_id 上加入,然后执行一些 GROUP BY txid。但这不会那么容易。您可能必须始终对两个表进行更新。或者使用一些更高级的逻辑(例如:选择一个 emp_id 的所有事务,其中一侧为空,直到下一个完整行,并用最后一个完整行填充缺失的部分)。

The FULL JOIN will create a table from both tables and fill in empty (non matching) rows with NULL values. When you select only the rows with emp.empnum = 20 it will of course not return the last row that has NULL in emp.empnum.

Maybe you can JOIN only on emp_id and then do some GROUP BY txid. But this wont be so easy. You might have to make always an update on both tables. Or use some more advanced logic (something like: select all transaction of one emp_id where one side is null until the next full row and fill the missing parts with the last full row).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文