【问题标题】:Oracle get table names based on column valueOracle根据列值获取表名
【发布时间】:2017-11-28 02:14:56
【问题描述】:

我有这样的表:

Table-1
Table-2
Table-3
Table-4
Table-5

每个表都有很多列,其中一个列名为employee_id。

现在,我想写一个查询

1) 返回所有包含此列的表和

2) 如果列具有值或通过传递employee_id 为空值,结果应显示表格。

例如显示表名、Table-1、Table-2、Table-3 中的列名,... whereemployee_id='1234'。

如果其中一个表没有此列,则不需要显示。

我已经通过link 进行了验证,但它只显示表名和列名,而不是通过将某些列值传递给它。

还验证了this,但这里验证了我不想这样做的整个架构。

更新:

找到了解决方案,但使用的是deprecated的xmlsequence,

1)如何将此代码设为 xmltable?

2) 如果表中没有值,则输出应为空/null。或默认为“YES”值

WITH  char_cols AS
  (SELECT /*+materialize */ table_name, column_name
   FROM   cols
  WHERE  data_type IN ('CHAR', 'VARCHAR2') and table_name in ('Table-1','Table-2','Table-3','Table-4','Table-5')) 
SELECT DISTINCT SUBSTR (:val, 1, 11) "Employee_ID",
       SUBSTR (table_name, 1, 14) "Table",
       SUBSTR (column_name, 1, 14) "Column"
FROM   char_cols,
       TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select "'
       || column_name
       || '" from "'
       || table_name
       || '" where upper("'
       || column_name
       || '") like upper(''%'
       || :val
       || '%'')' ).extract ('ROWSET/ROW/*') ) ) t ORDER  BY "Table" 
/ 

【问题讨论】:

  • 样本数据和期望的结果真的很有帮助。
  • 我认为您可能需要分两步执行此操作 - 获取包含该列的表列表,然后查询每个表(单独或使用 UNION ALL)以获取数据。
  • 最大的问题是不能一次性完成(在单个 SQL 查询中)。这是因为您必须查询具有 EMPLOYEE_ID 列的表以获取输入值,但您还必须首先查询数据目录才能找到这些表。但是,对表的查询必须事先知道表的名称。您正在寻找“动态 SQL”,这是一个高级主题 - 您是否觉得高级到可以询问此类问题?
  • 在您说您已验证的第二个链接中,该过程正在使用 cols 搜索整个架构,这是 USER_TAB_COLUMNS 的同义词。为什么不通过添加 where 子句条件以仅包含您的表来修改相同的内容?

标签: sql oracle


【解决方案1】:

可以使用(未​​弃用的)XMLTABLE 一步完成此查询。

示例架构

--Table-1 and Table-2 match the criteria.
--Table-3 has the right column but not the right value.
--Table-4 does not have the right column.
create table "Table-1" as select '1234' employee_id from dual;
create table "Table-2" as select '1234' employee_id from dual;
create table "Table-3" as select '4321' employee_id from dual;
create table "Table-4" as select 1          id from dual;

查询

--All tables with the column EMPLOYEE_ID, and the number of rows where EMPLOYEE_ID = '1234'.
select table_name, total
from
(
    --Get XML results of dynamic query on relevant tables and columns.
    select
        dbms_xmlgen.getXMLType(
            (
                --Create a SELECT statement on each table, UNION ALL'ed together.
                select listagg(
                    'select '''||table_name||''' table_name, count(*) total
                     from "'||table_name||'" where employee_id = ''1234'''
                    ,' union all'||chr(10)) within group (order by table_name) v_sql
                from user_tab_columns
                where column_name = 'EMPLOYEE_ID'
            )
        ) xml
    from dual
) x
cross join
--Convert the XML data to relational.
xmltable('/ROWSET/ROW'
    passing x.xml
    columns
        table_name varchar2(128) path 'TABLE_NAME',
        total      number        path 'TOTAL'
);

结果

TABLE_NAME   TOTAL
----------   -----
Table-1      1
Table-2      1
Table-3      0

【讨论】:

    【解决方案2】:

    请尝试使用下面的代码。 请注意,可能需要在循环中澄清方案名称。 此代码适用于我的本地数据库。 设置服务器输出;

    DECLARE
      ex_query VARCHAR(300);
      num      NUMBER;
      emp_id number;
    BEGIN
      emp_id := <put your value>;
      FOR rec IN
      (SELECT table_name
      FROM all_tab_columns
      WHERE column_name LIKE upper('employee_id')
      )
      LOOP
        num      :=0;
        ex_query := 'select count(*) from ' || rec.table_name || ' where employee_id = ' || emp_id;
        EXECUTE IMMEDIATE ex_query into num;
        if (num>0) then
          DBMS_OUTPUT.PUT_LINE(rec.table_name);
        end if;
      END LOOP;
    END;
    

    【讨论】:

      【解决方案3】:

      我尝试使用 xml 的东西,但我得到一个我无法解决的错误。关于零大小的结果。解决这个问题而不是引发异常有多困难?!询问甲骨文。

      无论如何。 您可以做的是使用COLS 表来了解哪个表有employee_id 列。

      1) 表TABLE_LIKE_THIS 中的哪个表(我假设表名列是C)有这个列?

       select * 
         from COLS, TABLE_LIKE_THIS t
        where cols.table_name = t
          and cols.column_name = 'EMPLOYEE_ID' 
       -- think Oracle metadata/ think upper case
      

      2) 哪一个具有您要查找的值:用EXECUTE IMMEDIATE 编写一小段Dynamic PL/SQL 来计算符合上述条件的表

      declare
        v_id varchar2(10) := 'JP1829';       -- value you are looking for
        v_col varchar2(20) := 'EMPLOYEE_ID'; -- column
        n_c  number := 0;
      begin
        for x in (
         select table_name
           from all_tab_columns cols
              , TABLE_LIKE_THIS t
          where cols.table_name = t.c
            and cols.column_name = v_col
        ) loop
          EXECUTE IMMEDIATE 
          'select count(1) from '||x.table_name
        ||' where Nvl('||v_col||', ''@#'') = ''' ||v_id||''''  -- adding quotes around string is a little specific
          INTO n_c;
          if n_c > 0 then
            dbms_output.put_line(n_C|| ' in ' ||x.table_name||' has '||v_col||'='||v_id);
          end if;
        -- idem for null values
        -- ... ||' where '||v_col||' is null '
        -- or
        -- ... ||' where Nvl('||v_col||', ''@#'') = ''@#'' '
        end loop;
        dbms_output.put_line('done.');
      end;
      /
      

      希望对你有帮助

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-14
        • 1970-01-01
        相关资源
        最近更新 更多