我需要在Oracle数据库上查询补丁状态。自Oracle 12c版以来,视图sys.REGISTRY $ HISTORY被视图DBA_REGISTRY_SQLPATCH替换。在像11g这样的旧版本上,视图dba_registry_sqlpatch不存在。以下查询在oracle版本上创建错误< 12c因为视图dba_registry_sqlpatch不存在。我需要构建一个在所有oracle数据库版本上运行的查询。我不能使用PL / SQL。我认为它应该通过案例表达来解决。
/* Query for version < 11g: */
SELECT MIN (diff) diff, MIN (zeile) zeile
FROM (SELECT TO_CHAR (TRUNC (SYSDATE - TRUNC (action_time)), '9999') DIFF,
'DIFF : '
|| TO_CHAR (TRUNC (SYSDATE - TRUNC (action_time)), '9999')
|| ' DAYS '
|| 'ACTION='
|| action
|| ' VERSION='
|| version
|| ' DATE='
|| TO_CHAR (action_time, 'yyyymmdd')
|| ' ID='
|| TO_CHAR (id, '09')
|| ' COMMENTS='
|| comments
|| ' PORT='
|| (SELECT DBMS_UTILITY.port_string
FROM DUAL)
ZEILE
FROM sys.REGISTRY$HISTORY
WHERE action_time = (SELECT MAX (action_time)
FROM sys.REGISTRY$HISTORY
WHERE action IN ('APPLY', 'ROLLBACK'))
UNION ALL
/*Query for version 12c: */
(SELECT TO_CHAR (TRUNC (SYSDATE - TRUNC (action_time)), '9999') DIFF,
'DIFF : '
|| TO_CHAR (TRUNC (SYSDATE - TRUNC (action_time)), '9999')
|| ' DAYS '
|| 'ACTION='
|| action
|| ' VERSION='
|| version
|| ' DATE='
|| TO_CHAR (action_time, 'yyyymmdd')
|| ' ID='
|| TO_CHAR (patch_id)
|| ' COMMENTS='
|| description
|| ' PORT='
|| (SELECT DBMS_UTILITY.port_string
FROM DUAL)
ZEILE
FROM dba_registry_sqlpatch
WHERE action_time = (SELECT MAX (action_time)
FROM dba_registry_sqlpatch
WHERE action IN ('APPLY', 'ROLLBACK')))
UNION ALL
/* Query for no patch installed: */
SELECT (SELECT TO_CHAR (TRUNC (SYSDATE - TRUNC (created)), '9999')
FROM v$database)
DIFF,
'DIFF : '
|| (SELECT TO_CHAR (TRUNC (SYSDATE - TRUNC (created)), '9999')
FROM v$database)
|| ' DAYS ACTION=N./A. VERSION='
|| (SELECT SUBSTR (version, 1, 8)
FROM v$instance)
|| ' DATE='
|| (SELECT TO_CHAR (created, 'yyyymmdd')
FROM v$database)
|| ' ID= 99 COMMENTS='
|| (SELECT SUBSTR (version, 1, 8)
FROM v$instance)
|| ' PORT='
|| (SELECT DBMS_UTILITY.port_string
FROM DUAL)
ZEILE
FROM DUAL)
WHERE ROWNUM = 1;
11天前修补的Oracle 12c数据库上的示例输出: DIFF:11天操作=应用版本= 12.1.0.2 DATE = 20160429 ID = 22809813 COMMENTS = WINDOWS DB BUNDLE PATCH 12.1.0.2.160419(64bit):22809813 PORT = IBMPC / WIN_NT64-9.1.0
答案 0 :(得分:2)
案例表达不会解决您的问题。要查询的表必须在分析时知道 - 在执行查询时,您无法动态选择表名,并且案例在评估案例之前仍会得到ORA-00942。
假设您只想要旧表和新视图中存在的列,您可以使用一些XML转换来从任何存在的数据中获取数据:
select x.*
from (
select dbms_xmlgen.getxml(q'[select to_char(action_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF9')
as action_time, action, version, id as patch_id, comments as description
from sys.REGISTRY$HISTORY]') as data
from dba_tables
where table_name = 'REGISTRY$HISTORY'
and not exists (select null from dba_views where view_name = 'DBA_REGISTRY_SQLPATCH')
union all
select dbms_xmlgen.getxml(q'[select to_char(action_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF9')
as action_time, action, version, patch_id, description
from DBA_REGISTRY_SQLPATCH]') as data
from dba_views
where view_name = 'DBA_REGISTRY_SQLPATCH'
) t
cross join xmltable('/ROWSET/ROW' passing xmltype(t.data)
columns action_time timestamp path 'ACTION_TIME',
action varchar2(30) path 'ACTION',
version varchar2(30) path 'VERSION',
patch_id number path 'PATCH_ID',
comments varchar2(100) path 'DESCRIPTION'
) x;
然后将select x.*
替换为您想要处理数据的任何内容,基本上将其插入现有查询中,添加联合以获取未修补的版本信息:
...
union all
select vd.created as action_time, 'N/A' as action, substr(vi.version, 1, 8) as version,
99 as patch_id, substr(vi.version, 1, 8) as description
from v$database vd
cross join v$instance vi;
to_char()
是将时间戳值转换为XML中预期的ISO格式。 dbms_xmlgen()
调用将数据从表/视图转换为XML表示形式;并XMLTable()
将其转换回来。这似乎有点无意义,但它让你不知道对象名称,直到运行时。
由于列略有不同(ID, COMMENTS
与PATCH_ID, DESCRIPTION
),因此会通过union all
从表或视图中获取单独的XML,但不能同时从两者中获取XML无效的XML文档。在12c中,REGISTRY$HISTORY
似乎是空的,但如果DBA_REGISTRY_SQLPATCH
存在,则不会从中获取任何数据。 (我有点懒,不检查所有权,所以其他人创建一个具有该名称的表将是一个问题,但很容易修复)。它对列名称进行别名,使它们看起来与最终使用的表/视图相同,从而允许解压缩XML。
将它与字符串格式放在一起,消除子查询,并使用the last
analytic function仅保留最新的行,最终可能会出现以下情况:
select to_char (trunc (sysdate - trunc (max(action_time))), '9999') diff,
'DIFF : ' || to_char (trunc (sysdate - trunc (max(action_time))), '9999') || ' DAYS'
|| ' ACTION=' || max(action) keep (dense_rank last order by action_time)
|| ' VERSION=' || max(version) keep (dense_rank last order by action_time)
|| ' DATE=' || to_char (max(action_time), 'yyyymmdd')
|| ' ID=' || to_char (max(patch_id) keep (dense_rank last order by action_time), '09')
|| ' COMMENTS=' || max(comments) keep (dense_rank last order by action_time)
|| ' PORT=' || dbms_utility.port_string zeile
from (
select x.* from (
select dbms_xmlgen.getxml(q'[select to_char(action_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF9')
as action_time, action, version, id as patch_id, comments as description
from sys.REGISTRY$HISTORY]') as data
from dba_tables
where table_name = 'REGISTRY$HISTORY'
and not exists (select null from dba_views where view_name = 'DBA_REGISTRY_SQLPATCH')
union all
select dbms_xmlgen.getxml(q'[select to_char(action_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF9')
as action_time, action, version, patch_id, description
from DBA_REGISTRY_SQLPATCH]') as data
from dba_views
where view_name = 'DBA_REGISTRY_SQLPATCH'
) t
cross join xmltable('/ROWSET/ROW' passing xmltype(t.data)
columns action_time timestamp path 'ACTION_TIME',
action varchar2(30) path 'ACTION',
version varchar2(30) path 'VERSION',
patch_id number path 'PATCH_ID',
comments varchar2(100) path 'DESCRIPTION'
) x
union all
select vd.created as action_time, 'N./.A' as action, substr(vi.version, 1, 8) as version,
99 as patch_id, substr(vi.version, 1, 8) as comments
from v$database vd
cross join v$instance vi
);
在11.2.0.4和10.2.0.5上测试过,但我没有一个未修补的实例或一个12c实例来验证它的行为是否符合您的预期。
答案 1 :(得分:0)
编辑:正如Alex Poole在评论中所显示的那样(对他的回答而不是我的回答),我在下面描述的内容将无效。这实际上很好地说明了在这种情况下不起作用的内容。
我将它留在这里,所以可能已经看过这个的人已经有机会看到它并不好。我会在一段时间后删除答案。
谢谢Alex指出来!
-
显然你可以自己编写查询,所以我只会在这里展示一种方法来做&#34;切换&#34;你问过的表达方式。我只有版本11(免费版)所以我无法完全测试,但这应该有效。要查找会话所在的Oracle DB版本,可以查询视图V $ VERSION。在我的机器上,我看到Oracle版本显示为:
SQL> select * from v$version where banner like 'Oracle%';
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
假设v $版本在Oracle 12c中没有变化(即:仍有视图v $版本,该列仍称为banner,Oracle DB版本显示为Oracle Database 12c ... 。),为了获得action_time,你可以做这样的事情:
select case
regexp_substr((select banner from v$version where banner like 'Oracle%'), '\d{1,2}')
when '11' then (select action_time from sys.REGISTRY$HISTORY)
when '12' then (select action_time from dba_registry_sqlpatch)
end as action_time ...
您不需要为来自&#34;注册表&#34;的每一位数据编写Oracle版本的案例表达式。 table - 您可以在case表达式的两个分支中构建完整的字符串。你可以调整它以适应&#34;没有安装补丁&#34;分支也是如此。
祝你好运!