在Oracle中,我有一个非常大的select语句。我想将它保存为视图,以便我可以从.NET程序中调用它并将其用作某些统计信息的基础,我们必须生成。使用视图时,它总是在日期过滤。
我想要这样的事情:
select * from my_view
where my_view.date = '2014-01-01';
问题是我需要在子查询的where条件中使用date作为参数:
select * from table1
left outer join (
select * from table2
where table2.date = :somedate)
on table1.Id = table2.Id;
...无法制作视图。
有没有办法,我可以在子查询之外移动日期比较而不会弄乱左外连接?
什么不该做:
这会创建一个内连接 - 这不是我想要的:
select * from table1
left outer join
table2
on table1.Id = table2.Id
where table2.date = '2014-01-01';
此选择过滤掉table1中的行,这些行不会在指定日期的某一行上连接,但会在另一个日期的某一行上连接:
select * from table1
left outer join
table2
on table1.Id = table2.Id
where table2.Id is null
or table2.date = '2014-01-01';
答案 0 :(得分:1)
有一些参数化视图的方法 - 例如使用包或应用程序上下文(您可以使用内置上下文CLIENTCONTEXT)。但是所有这些方法都需要完全控制参数,你必须使用附加功能设置参数值,这可能是一个严重的缺点:
SQL> create or replace view param_view
2 as
3 select d.name, e.firstname, e.lastname, e.email
4 from department d left join employee e
5 on (d.id = e.departmentid
6 and e.firstname = sys_context('CLIENTCONTEXT','EMPNAME'))
7 /
View created.
SQL> exec dbms_session.set_context('CLIENTCONTEXT','EMPNAME','Scott')
PL/SQL procedure completed
SQL> select * from param_view;
NAME FIRSTNAME LASTNAME EMAIL
-------------------- ---------- -------------------- --------------------
Department A Scott Tiger xxx@gmail.com
Department B
Department C
SQL> exec dbms_session.set_context('CLIENTCONTEXT','EMPNAME','Allen')
PL/SQL procedure completed
SQL> select * from param_view;
NAME FIRSTNAME LASTNAME EMAIL
-------------------- ---------- -------------------- --------------------
Department A Allen Dirk yyy@gmail.com
Department B
Department C
或
SQL> create or replace package pck_test
2 is
3 function get return varchar2;
4 procedure set (x in varchar2);
5 end;
6 /
Package created.
SQL> create or replace package body pck_test
2 is
3 name employee.firstname%type;
4
5 function get return varchar2
6 is
7 begin
8 return name;
9 end;
10
11 procedure set (x in varchar2)
12 is
13 begin
14 name := x;
15 end;
16
17 end;
18 /
Package body created.
SQL> create or replace view param_view
2 as
3 select d.name, e.firstname, e.lastname, e.email
4 from department d left join employee e
5 on (d.id = e.departmentid
6 and e.firstname = pck_test.get)
7 /
View created
SQL> exec pck_test.set('Scott')
PL/SQL procedure completed.
SQL> select * from param_view;
NAME FIRSTNAME LASTNAME EMAIL
-------------------- ---------- -------------------- --------------------
Department A Scott Tiger xxx@gmail.com
Department B
Department C
SQL> exec pck_test.set('Allen')
PL/SQL procedure completed.
SQL> select * from param_view;
NAME FIRSTNAME LASTNAME EMAIL
-------------------- ---------- -------------------- --------------------
Department A Allen Dirk yyy@gmail.com
Department B
Department C
SQL> select d.name, e.firstname, e.lastname, e.email
2 from department d left join employee e
3 on (d.id = e.departmentid)
4 /
NAME FIRSTNAME LASTNAME EMAIL
-------------------- ---------- -------------------- --------------------
Department A Allen Dirk yyy@gmail.com
Department A Scott Tiger xxx@gmail.com
Department B
Department C
答案 1 :(得分:1)
如果您只是想避免在底部创建内部联接,请添加合并语句,例如:
coalesce(table1.date,'2015-01-28') = '2015-01-28'
这将不会创建内部联接,因为所有空值仍将返回。
答案 2 :(得分:0)
删除原始回复。 这就是我提出的问题
create view my_view as
select * from (
select t1.*, t2.*, to_date(null) filter_date from table1 t1 left outer join table2 t2
on t2.id <> t2.id
union all
select t1.*, t2.*, t2.date filter_date from table1 t1 inner outer join table2 t2
on t1.id = t2.id)
第二个数据集是从t1内连接获取t2的所有记录 作为查询的结果,您将始终有1或2条记录可供选择。如果有2条记录,请选择一条日期:
select * from (
select *, row_number() over (partition by id order by filter_date NULLS LAST) rnum
from my_view where filter_date = :date or filter_date is null
) where rnum = 1
或
select * from (
select *, rownum rnum
from my_view where filter_date = :date or filter_date is null
order by filter_date NULLS LAST
) where rnum = 1