【问题标题】:Oracle VIEW 显示在我的表中创建最后一条记录的时间
【发布时间】:2022-01-17 15:42:34
【问题描述】:

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

现在我想创建一个视图来显示我的表和相应表中上次创建记录的时间戳 (MAX(created_on))。

结果应该是这样的:

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

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

SELECT * FROM USER_TABLES WHERE table_name LIKE 'T%'

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

如何创建这个视图?

【问题讨论】:

  • 我想要某种列表中的表列表。
  • @MT0,你为什么关闭这个问题?您是否阅读了 sbrbot 撰写的所有内容(包括 cmets)?链接问题中没有任何内容可以解决这个问题(至少,我没有找到)。
  • @Littlefoot 然后找一个更好的副本。我已经链接了另一个,你可以重新关闭它。
  • 这也不是,@MT0,恐怕。 OP 有一堆包含 CREATED_ON 列的表,并希望动态地获取所有这些表及其 MAX(CREATED_ON) 列值的列表。可能会创建新表;旧的可能会被删除 - 表列表动态更改,生成的查询 应该反映所有这些更改。 找到更好的副本:不,我不会那样做,抱歉。

标签: sql oracle greatest-n-per-group


【解决方案1】:

这可能取决于表格的描述;我想它们在某种程度上是相互关联的。

无论如何:这就是我对这个问题的理解。在代码中读取 cmets。

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>

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

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>

【讨论】:

  • 我更改了我的 Q 以更清楚地显示结果应该是什么样子。表名应该在结果中。
  • 那就更简单了。请查看编辑后的答案。
  • 好的,没关系。我有 30 多个表,并希望避免对这些表中的每一个表进行硬编码 SELECT 语句并将它们全部联合起来。我期待一些解决方案,我会在有点数组中插入表名并创建 JOIN 以显示所有最后记录的结果。我知道问题出在表名是可变的! DDL/DML
  • 例如查询 SELECT * FROM USER_TABLES WHERE table_name LIKE 'T%' 我可以看到我的表,但我想获取每个表中最后创建记录的时间戳
  • 这样不行;您将需要某种动态 SQL。一种选择是创建一个返回引用光标的函数(这就是我在上面发布的内容;看看)。
【解决方案2】:

我有 30 多个表,并且希望避免为每个表硬编码 SELECT 语句并将它们全部联合起来。我期待一些解决方案,我会在有点数组中插入表名并创建 JOIN 以显示所有最后记录的结果。我知道问题出在表名是可变的!

您不能在 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小提琴here

【讨论】:

  • 非常感谢,感谢您为快速响应所做的努力,特别是在制作小提琴示例方面。实际上,我只需要一个解决方案或坚定的确认(您给我们的)不可能使用动态表名创建 VIEW。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
  • 2015-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多