创建一个视图,允许您向 LEFT JOIN ... ON 添加条件?
Create a view that lets you add conditions to the LEFT JOIN ... ON?
我正在创建一个将由许多客户端应用程序使用的数据库(使用 Oracle 12c)。为了简化,我尝试通过创建不同的视图将尽可能多的逻辑保留在数据库中,这样客户就可以提出简单的问题,而无需像 JOIN
或 GROUP BY
这样更复杂的结构。他们应该只需要从视图中用一些 WHERE
条件做一个简单的 SELECT
,然后让视图完成繁重的工作。
现在我的问题是我想在表格上提问
SELECT
-- Some fields.
FROM a
LEFT JOIN b ON a.id = b.id AND b.type = x
LEFT JOIN c ON a.id = c.id AND c.type = y
LEFT JOIN d ON a.id = d.id AND d.type = z
其中 x
、y
和 z
是来自客户端的输入。我不希望客户必须构造该查询。我宁愿让他们做更类似于此的事情:
SELECT * FROM a_view WHERE b_type = x AND c_type = y AND d_type = z
当然,我可以为 x
、y
和 z
的每种可能组合创建一个视图,但那样会产生很多视图。有没有更好的方法来解决这个问题,还是我应该放弃并让客户用 JOIN
?
编写查询
或许,你可以使用 "old style join syntax":
SELECT
-- Some fields.
FROM a, b, c, d
WHERE a.id = b.id(+) AND b.type(+) = x
AND a.id = c.id(+) AND c.type(+) = y
AND a.id = d.id(+) AND d.type(+) = z
例如:
SQL> with
t as (select rownum r from dual connect by level < 6),
t1 as (select rownum r from dual connect by level < 5),
t2 as (select rownum r from dual connect by level < 4)
select *
from t, t1, t2
where t.r = t1.r(+) and t1.r(+) = 3
and t.r = t2.r(+) and t2.r(+) = 2
order by 1, 2, 3;
R R R
---------- ---------- ----------
1
2 2
3 3
4
5
这可以做到,但您必须拥有所有有效类型的来源,并假设 user/application 只会查询有效类型的视图。换句话说,假设 table T 是你的 "type table" 并且你所有的 B、C 和 D table 都有(或可能有)在 T 上定义的 FK。
在这种情况下,您的视图定义。将是:
CREATE OR REPLACE VIEW V AS
SELECT A.ID, BT.TYPE BTYPE, CT.TYPE CTYPE, DT.DTYPE DTYPE, ...
FROM A
CROSS JOIN T BT
CROSS JOIN T CT
CROSS JOIN T DT
LEFT JOIN B ON A.ID = B.ID AND B.TYPE = BT.TYPE
LEFT JOIN C ON A.ID = C.ID AND C.TYPE = CT.TYPE
LEFT JOIN D ON A.ID = D.ID AND D.TYPE = DT.TYPE;
当然,如果模型中有一组固定的有效类型,您可以将 T 替换为 (SELECT 'X' TYPE FROM DUAL UNION ALL SELECT 'Y' FROM DUAL UNION ALL ...)
唯一的区别:
SELECT
-- Some fields.
FROM a
LEFT JOIN b ON a.id = b.id AND b.type = x
LEFT JOIN c ON a.id = c.id AND c.type = y
LEFT JOIN d ON a.id = d.id AND d.type = z
和
SELECT * FROM V WHERE B_TYPE = X AND C_TYPE = Y AND D_TYPE = Z
如果 X、Y 或 Z 不是 "valid" 类型(在这种情况下,视图定义将 return 没有行)。
编辑:根据评论澄清;我假设 "type" 是 tables B、C 和 D 的公共域。如果 B.type 与 C.type 不同(即 B.TYPE 是 NUMERIC (9) 并且 C.type 是 VARCHAR(2) 并且 D.TYPE 是 NUMERIC(1)) 那么交叉连接需要独立地引用每个 "set of valid type values":
CREATE OR REPLACE VIEW V AS
SELECT A.ID, BT.TYPE BTYPE, CT.TYPE CTYPE, DT.DTYPE DTYPE, ...
FROM A
CROSS JOIN (--SELECT ALL DISTINCT VALID B.TYPE VALUES--) BT
CROSS JOIN (--SELECT ALL DISTINCT VALID C.TYPE VALUES--) CT
CROSS JOIN (--SELECT ALL DISTINCT VALID D.TYPE VALUES--) DT
LEFT JOIN B ON A.ID = B.ID AND B.TYPE = BT.TYPE
LEFT JOIN C ON A.ID = C.ID AND C.TYPE = CT.TYPE
LEFT JOIN D ON A.ID = D.ID AND D.TYPE = DT.TYPE;
也就是说,您确实有相同的限制:内置在视图定义中。必须是 "all valid B types"、"all valid C types" 和 "all valid D types" 的某个有限来源。除此之外,这在纯 SQL 中是不可行的(事实上,就纯 SQL 而言,它变成了一个 intractable 问题——支持按任何可能的值组合进行过滤的视图,没有过滤器,应该 return 所有可能的值组合...)
我正在创建一个将由许多客户端应用程序使用的数据库(使用 Oracle 12c)。为了简化,我尝试通过创建不同的视图将尽可能多的逻辑保留在数据库中,这样客户就可以提出简单的问题,而无需像 JOIN
或 GROUP BY
这样更复杂的结构。他们应该只需要从视图中用一些 WHERE
条件做一个简单的 SELECT
,然后让视图完成繁重的工作。
现在我的问题是我想在表格上提问
SELECT
-- Some fields.
FROM a
LEFT JOIN b ON a.id = b.id AND b.type = x
LEFT JOIN c ON a.id = c.id AND c.type = y
LEFT JOIN d ON a.id = d.id AND d.type = z
其中 x
、y
和 z
是来自客户端的输入。我不希望客户必须构造该查询。我宁愿让他们做更类似于此的事情:
SELECT * FROM a_view WHERE b_type = x AND c_type = y AND d_type = z
当然,我可以为 x
、y
和 z
的每种可能组合创建一个视图,但那样会产生很多视图。有没有更好的方法来解决这个问题,还是我应该放弃并让客户用 JOIN
?
或许,你可以使用 "old style join syntax":
SELECT
-- Some fields.
FROM a, b, c, d
WHERE a.id = b.id(+) AND b.type(+) = x
AND a.id = c.id(+) AND c.type(+) = y
AND a.id = d.id(+) AND d.type(+) = z
例如:
SQL> with
t as (select rownum r from dual connect by level < 6),
t1 as (select rownum r from dual connect by level < 5),
t2 as (select rownum r from dual connect by level < 4)
select *
from t, t1, t2
where t.r = t1.r(+) and t1.r(+) = 3
and t.r = t2.r(+) and t2.r(+) = 2
order by 1, 2, 3;
R R R
---------- ---------- ----------
1
2 2
3 3
4
5
这可以做到,但您必须拥有所有有效类型的来源,并假设 user/application 只会查询有效类型的视图。换句话说,假设 table T 是你的 "type table" 并且你所有的 B、C 和 D table 都有(或可能有)在 T 上定义的 FK。
在这种情况下,您的视图定义。将是:
CREATE OR REPLACE VIEW V AS
SELECT A.ID, BT.TYPE BTYPE, CT.TYPE CTYPE, DT.DTYPE DTYPE, ...
FROM A
CROSS JOIN T BT
CROSS JOIN T CT
CROSS JOIN T DT
LEFT JOIN B ON A.ID = B.ID AND B.TYPE = BT.TYPE
LEFT JOIN C ON A.ID = C.ID AND C.TYPE = CT.TYPE
LEFT JOIN D ON A.ID = D.ID AND D.TYPE = DT.TYPE;
当然,如果模型中有一组固定的有效类型,您可以将 T 替换为 (SELECT 'X' TYPE FROM DUAL UNION ALL SELECT 'Y' FROM DUAL UNION ALL ...)
唯一的区别:
SELECT
-- Some fields.
FROM a
LEFT JOIN b ON a.id = b.id AND b.type = x
LEFT JOIN c ON a.id = c.id AND c.type = y
LEFT JOIN d ON a.id = d.id AND d.type = z
和
SELECT * FROM V WHERE B_TYPE = X AND C_TYPE = Y AND D_TYPE = Z
如果 X、Y 或 Z 不是 "valid" 类型(在这种情况下,视图定义将 return 没有行)。
编辑:根据评论澄清;我假设 "type" 是 tables B、C 和 D 的公共域。如果 B.type 与 C.type 不同(即 B.TYPE 是 NUMERIC (9) 并且 C.type 是 VARCHAR(2) 并且 D.TYPE 是 NUMERIC(1)) 那么交叉连接需要独立地引用每个 "set of valid type values":
CREATE OR REPLACE VIEW V AS
SELECT A.ID, BT.TYPE BTYPE, CT.TYPE CTYPE, DT.DTYPE DTYPE, ...
FROM A
CROSS JOIN (--SELECT ALL DISTINCT VALID B.TYPE VALUES--) BT
CROSS JOIN (--SELECT ALL DISTINCT VALID C.TYPE VALUES--) CT
CROSS JOIN (--SELECT ALL DISTINCT VALID D.TYPE VALUES--) DT
LEFT JOIN B ON A.ID = B.ID AND B.TYPE = BT.TYPE
LEFT JOIN C ON A.ID = C.ID AND C.TYPE = CT.TYPE
LEFT JOIN D ON A.ID = D.ID AND D.TYPE = DT.TYPE;
也就是说,您确实有相同的限制:内置在视图定义中。必须是 "all valid B types"、"all valid C types" 和 "all valid D types" 的某个有限来源。除此之外,这在纯 SQL 中是不可行的(事实上,就纯 SQL 而言,它变成了一个 intractable 问题——支持按任何可能的值组合进行过滤的视图,没有过滤器,应该 return 所有可能的值组合...)