Oracle VIEW 显示在我的表中创建最后一条记录的时间

Oracle VIEW showing when last records were created in my tables

我有 tables t1t2,它们都有包含创建每条记录时的时间戳的列 created_on。平常事。

现在我想创建一个视图来显示我的 tables 和最后创建的记录的时间戳 (MAX(created_on)) 在相应的 table.

结果应如下所示:

table | last_record
======+============
t1    | 10.05.2019
t2    | 12.11.2020

例如,我可以通过以下方式检索我的 table 的列表:

SELECT * FROM USER_TABLES WHERE table_name LIKE 'T%'

我想获取每个 table 的最后一条记录的时间戳。

如何创建这个视图?

这可能取决于表的描述;我认为它们之间存在某种关联。

无论如何:这就是我对这个问题的理解。阅读代码中的注释。

SQL> with
  2  -- sample data
  3  t1 (id, name, created_on) as
  4    (select 1, 'Little', date '2021-12-14' from dual union all  --> max for Little
  5     select 2, 'Foot'  , date '2021-12-13' from dual union all  --> max for Foot
  6     select 2, 'Foot'  , date '2021-12-10' from dual
  7    ),
  8  t2 (id, name, created_on) as
  9    (select 2, 'Foot'  , date '2021-12-09' from dual union all
 10     select 3, 'SBrbot', date '2021-12-14' from dual            --> max for SBrbot
 11    )
 12  -- query you'd use for a view
 13  select id, name, max(created_on) max_created_on
 14  from
 15     -- union them, so that it is easier to find max date
 16    (select id, name, created_on from t1
 17     union all
 18     select id, name, created_on from t2
 19    )
 20  group by id, name;

        ID NAME   MAX_CREATE
---------- ------ ----------
         1 Little 14.12.2021
         2 Foot   13.12.2021
         3 SBrbot 14.12.2021

SQL>

在您解决问题之后,这就更容易了;查看查询从第 12 行开始:

SQL> with
  2  -- sample data
  3  t1 (id, name, created_on) as
  4    (select 1, 'Little', date '2021-12-14' from dual union all  
  5     select 2, 'Foot'  , date '2021-12-13' from dual union all  
  6     select 2, 'Foot'  , date '2021-12-10' from dual
  7    ),
  8  t2 (id, name, created_on) as
  9    (select 2, 'Foot'  , date '2021-12-09' from dual union all
 10     select 3, 'SBrbot', date '2021-12-14' from dual            
 11    )
 12  select 't1' source_table, max(created_on) max_created_on from t1
 13  union
 14  select 't2' source_table, max(created_on) max_created_on from t2;

SO MAX_CREATE
-- ----------
t1 14.12.2021
t2 14.12.2021

SQL>

如果它必须是 动态的,一种选择是创建一个 returns 引用游标的函数:

SQL> create or replace function f_max
  2    return sys_refcursor
  3  is
  4    l_str varchar2(4000);
  5    rc    sys_refcursor;
  6  begin
  7    for cur_r in (select distinct c.table_name
  8                  from user_tab_columns c
  9                  where c.column_name = 'CREATED_ON'
 10                  order by c.table_name
 11                 )
 12    loop
 13      l_str := l_str ||' union all select ' || chr(39) || cur_r.table_name || chr(39) ||
 14                       ' table_name, max(created_on) last_updated from ' || cur_r.table_name;
 15    end loop;
 16
 17    l_str := ltrim(l_str, ' union all ');
 18
 19    open rc for l_str;
 20    return rc;
 21  end;
 22  /

Function created.

测试:

SQL> select f_max from dual;

F_MAX
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

TA LAST_UPDAT
-- ----------
T1 14.12.2021
T2 14.12.2021


SQL>

I have 30+ tables and wanted avoid hard coding SELECT statements for each of these tables and UNION them all. I expected some solution where I would insert tablenames in kinda array and create JOIN to show result with all last records. I know problem is here that tablename is variable!

您不能在 SQL 中执行此操作,因为 VIEW 是在编译时设置的,并且表必须是已知的;你能做的最好的事情是在 PL/SQL 中动态创建一个 SQL 语句,然后使用 EXECUTE IMMEDIATE 然后重新 运行 如果你想重新创建视图:

DECLARE
  v_tables SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST(
    'TABLE1', 'TABLE2', 'table3', 'TABLE5'
  );
  v_sql CLOB := 'CREATE OR REPLACE VIEW last_dates (table_name, last_date) AS ';
BEGIN
  FOR i in 1 .. v_tables.COUNT LOOP
    IF i > 1 THEN
      v_sql := v_sql || ' UNION ALL ';
    END IF;
    v_sql := v_sql || 'SELECT '
                   || DBMS_ASSERT.ENQUOTE_LITERAL(v_tables(i))
                   || ', MAX(created_on) FROM '
                   || DBMS_ASSERT.ENQUOTE_NAME(v_tables(i), FALSE);
  END LOOP;
  
  EXECUTE IMMEDIATE v_sql;
END;
/

然后对于示例表:

CREATE TABLE table1 (created_on) AS
SELECT SYSDATE - LEVEL FROM DUAL CONNECT BY LEVEL <= 3;

CREATE TABLE table2 (created_on) AS
SELECT SYSDATE - LEVEL FROM DUAL CONNECT BY LEVEL <= 3;

CREATE TABLE "table3" (created_on) AS
SELECT SYSDATE - LEVEL FROM DUAL CONNECT BY LEVEL <= 3;

CREATE TABLE table5 (created_on) AS
SELECT SYSDATE FROM DUAL;

运行在 PL/SQL 块之后,然后:

SELECT * FROM last_dates;

输出:

TABLE_NAME LAST_DATE
TABLE1 2021-12-13 13:21:58
TABLE2 2021-12-13 13:21:59
table3 2021-12-13 13:21:59
TABLE5 2021-12-14 13:21:59

db<>fiddle here