如何在FROM中调用间接表

时间:2017-04-29 07:46:09

标签: sql oracle variables

请告诉我我做错了什么。我尝试过以下方法:

SELECT * 
FROM 'A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B'

SELECT * 
FROM CAST('A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B' AS varchar2(8))

SELECT * 
FROM table( CAST('A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B' AS varchar2(8)))

DEFINE tName = CAST('A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B' AS varchar2(8))
SELECT * 
FROM &tName

SET tName AS CAST('A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B' AS varchar2(8))
SELECT * 
FROM &tName

SET @tName AS CAST('A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B' AS varchar2(8))
SELECT * 
FROM @tName

SELECT *
FROM
(
SELECT CAST('A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B' AS varchar2(8)) 
FROM DUAL
)

(注意:我还尝试在上面的所有示例中添加表之前的所有者,如下面的第二个示例所示)

我已经验证了

SELECT CAST('A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B' AS varchar2(8)) 
FROM DUAL

显示A170429B

SELECT CAST('owner.A'||(TO_CHAR(SYSDATE, 'YYMMDD'))||'B' AS varchar2(8)) 
FROM DUAL 

显示所有者.A170429B

但我无法获取FROM语句将其视为表

数据库每天都会创建一个新表;这就是我试图这样做的原因。

2 个答案:

答案 0 :(得分:2)

正如其他人所观察到的那样,分区是安排这种方式的优雅方式。但Partitioning仍然是企业版的许可额外版本,而且价格昂贵。所以这里有几个更便宜的选择。

第一个选项是执行您现在要执行的操作,并按名称查询每个表。要使这种方法起作用,您需要使用动态SQL。

以下是一些表格 - t170428t170429t170430 - 这些都是这样的

create table t170428 (
    id number not null primary key
    , type varchar2(10)
    , col1 varchar2(10)
    , col2 number
    , col3 date not null
    )
/

要查询它们,我们需要一个带有与表格投影匹配的签名的SQL类型:

create or replace type tyymmdd_t as object (
    id number 
    , type varchar2(10)
    , col1 varchar2(10)
    , col2 number
    , col3 date
    );
/

create or replace type tyymmdd_nt as table of tyymmdd_t
/

这是一个动态从传递的日期构建表名并从该表返回一个嵌套的行表的函数:

create or replace function get_date_table
    ( p_target_date in date)
    return tyymmdd_nt
is
    return_value tyymmdd_nt;
begin
    execute immediate
        ' select tyymmdd_t(id, type, col1, col2, col3) from t'
           ||to_char(p_target_date, 'yymmdd')
        bulk collect into return_value;
    return return_value;
end;
/

要查询表格,我们使用table()函数,如下所示:

SQL> select * from table(get_date_table(sysdate));

        ID TYPE       COL1             COL2 COL3
---------- ---------- ---------- ---------- ---------
         9 D2         SUN                 1 30-APR-17
        10 D2         SUN                 2 30-APR-17

SQL> select * from table(get_date_table(date'2017-04-28'));

        ID TYPE       COL1             COL2 COL3
---------- ---------- ---------- ---------- ---------
         1 D1         FRI                 1 28-APR-17
         2 D1         FRI                 2 28-APR-17
         3 D1         FRI                 3 28-APR-17
         4 D1         FRI                 4 28-APR-17
         5 D1         FRI                 5 28-APR-17

SQL> select * from table(get_date_table(sysdate+1));
select * from table(get_date_table(sysdate+1))
                    *
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "FOX.GET_DATE_TABLE", line 7


SQL> 

第二个选项是分区视图。这是一项古老的技术(来自上一个千年!),它允许我们使用UNION ALL运算符构建多个表的视图,并获得分区修剪的许多好处,例如分区修剪 - 前提是您使用的是旧版本的Oracle。分区视图在8.0中已弃用,Oracle在9iR2中停止支持它们。文档可以追溯到Oracle7 Find out more

无论如何,分区视图的原则是:

  • 对“分区键”执行检查约束
  • 在分区键列上构建索引
  • 收集统计资料
  • 构建视图

与表格投影一样,所有表格的约束和索引必须相同。

alter table t170428 add constraint t170428_ptn_key_ck check (col3 = date '2017-04-28');
alter table t170429 add constraint t170429_ptn_key_ck check (col3 = date '2017-04-29');
alter table t170430 add constraint t170430_ptn_key_ck check (col3 = date '2017-04-30');

create unique index t170428_ptn_idx on t170428(col3, id) compress 1;
create unique index t170429_ptn_idx on t170429(col3, id) compress 1;
create unique index t170430_ptn_idx on t170430(col3, id) compress 1;

exec dbms_stats.gather_table_stats('FOX', 'T170428', cascade=>true)
exec dbms_stats.gather_table_stats('FOX', 'T170429', cascade=>true)
exec dbms_stats.gather_table_stats('FOX', 'T170430', cascade=>true)

create or replace view v_all_the_dates as
select * from t170428
union all
select * from t170429
union all
select * from t170430
/

由于Oracle在数据库的更高版本中不支持分区视图,因此这种方法不会为您提供分区修剪。但是,如果您对索引和检查约束严格,那么它仍然可以非常有效。

可能适合的第三个选项是外部表。日期表的创建表明每日负荷。如果这些只是作为数据的临时表,作为文件到达,您可以使用外部表来访问数据。该表将是一个稳定的结构;您需要更改的是每日Feed文件的位置。 Find out more

答案 1 :(得分:0)

DBMS_XMLGEN可以创建一个完全动态的SQL语句,而无需任何其他权限。

(但在您使用下面的困难SQL之前,我建议您再次尝试获取对数据库的更多访问权限并使用APC的解决方案之一。不需要对供应商的应用程序架构进行写访问。可以在单独的用户模式,不会干扰应用程序。)

首先,使用名称

中的今天日期创建一个测试表
begin
    execute immediate '
        create table a'||to_char(sysdate, 'YYMMDD')||'b
        (
            column1 number,
            column2 number
        )';
end;
/

添加测试行。此解决方案的一个潜在问题是,当内部查询没有返回任何行时,它会抛出错误ORA-06502: PL/SQL: numeric or value error/nORA-06512: at "SYS.XMLTYPE", line 272/nORA-06512: at line 1

begin
    execute immediate 'insert into a'||to_char(sysdate, 'YYMMDD')||'b values (1,2)';
    commit;
end;
/

此查询从表中读取而不知道表的名称。但它需要知道表的列。 (如果供应商在每个表中创建了不同的列,这是一个肯定需要自定义对象的更难的问题。)

--Step 3: Convert XML back into a row.
select column1, column2
from
(
    --Step 2: Create an XML result set of a dynamic query.
    select
        xmltype(dbms_xmlgen.getxml(
        (
            --Step 1: SELECT statement that generates a SELECT statement.
            select 
                'select column1, column2
                from a'||to_char(sysdate, 'YYMMDD')||'b'
            from dual
        )
    )) xml_results
    from dual
)
cross join
xmltable
(
    '/ROWSET/ROW'
    passing xml_results
    columns
        column1 number path 'COLUMN1',
        column2 number path 'COLUMN2'
);

结果:

COLUMN1   COLUMN2
-------   -------
1               2