首页 > 解决方案 > 有没有办法根据 FROM 子句(Oracle)中使用的表显示表名作为 SELECT 子句的结果?

问题描述

我需要一些内置关键字/函数,它会根据查询的 SELECT 子句显示查询的表名。

例如:

数据库 TestDB 上的表 Products,包含以下数据

ID 产品名称
1 玩具
2 花

select ora_database_name,ProductName from Products;

上述查询将返回以下输出,

TestDB 玩具
TestDB 花

那么有没有类似的关键字或者函数来显示表名呢?

Select <keyword/function>, ProductName from Products;

预期输出:

产品 玩具
产品 花

目前我正在使用这样的东西来缓解上述问题,

Select 'Products' as TableName, ProductName from Products;

PS:对不起,如果问题令人费解/令人困惑!

标签: oracle

解决方案


以下不用于生产用途! 我这样做只是为了好玩,以展示我们在 oracle 中可以做什么:

select
   (select sql_text from v$sqlarea q,v$session s where s.sid=userenv('sid') and s.sql_id=q.sql_id) stext
  ,regexp_replace(
     (select sql_text from v$sqlarea q,v$session s where s.sid=userenv('sid') and s.sql_id=q.sql_id)
    ,'.*?from ((\s*,?\s*\w+)+)\s*(where|$)'
    ,'[\1]'
    ,1,1,'i'
  ) from_clause
from dual, dual;

结果:

STEXT                                                                            FROM_CLAUSE
-------------------------------------------------------------------------------- --------------------
select    (select sql_text from v$sqlarea q,v$session s where s.sid=userenv('sid [dual, dual]
') and s.sql_id=q.sql_id) stext   ,regexp_replace(      (select sql_text from v$
sqlarea q,v$session s where s.sid=userenv('sid') and s.sql_id=q.sql_id)     ,'.*
?from ((\s*,?\s*\w+)+)\s*(where|$)'     ,'[\1]'     ,1,1,'i'   ) from_clause fro
m dual, dual

或者来自 v$sql_plan:

select
  (  select
          listagg(obj, ',') within group(order by obj)
     from (
        select distinct object_type||':'/*||object_owner||'.'*/||object_name as obj
        from v$session s, v$sql_plan p 
        where s.sid    = userenv('sid')
          and s.sql_id = p.sql_id 
          and s.sql_child_number = p.child_number
          and p.object_name is not null
          and p.object_name not like '%$%'
     )
  ) objects
from t1,t2,t3,t4
where rownum=1;

结果:

OBJECTS
------------------------------------------------------------
INDEX (UNIQUE):PK_T2,INDEX (UNIQUE):PK_T4,TABLE:T1,TABLE:T3

通过一些预处理(用它们的表名替换索引):

select
  (  select
          listagg(obj, ',') within group(order by obj)
     from (
        select distinct 
           case 
              when object_type like 'INDEX%'
                 then 
                   (select min(table_name) from all_indexes i where i.index_name=p.object_name and i.owner=p.object_owner)
              else object_name 
           end as obj
        from v$session s, v$sql_plan p 
        where s.sid    = userenv('sid')
          and s.sql_id = p.sql_id 
          and s.sql_child_number = p.child_number
          and p.object_name is not null
          and p.object_name not like '%$%'
          and p.object_owner!='SYS'
     )
  ) objects
from t1,t2,t3,t4
where rownum=1;

结果:

OBJECTS
------------
T1,T2,T3,T4

推荐阅读