创建一个视图,允许您向 LEFT JOIN ... ON 添加条件?

Create a view that lets you add conditions to the LEFT JOIN ... ON?

我正在创建一个将由许多客户端应用程序使用的数据库(使用 Oracle 12c)。为了简化,我尝试通过创建不同的视图将尽可能多的逻辑保留在数据库中,这样客户就可以提出简单的问题,而无需像 JOINGROUP 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

其中 xyz 是来自客户端的输入。我不希望客户必须构造该查询。我宁愿让他们做更类似于此的事情:

SELECT * FROM a_view WHERE b_type = x AND c_type = y AND d_type = z

当然,我可以为 xyz 的每种可能组合创建一个视图,但那样会产生很多视图。有没有更好的方法来解决这个问题,还是我应该放弃并让客户用 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 所有可能的值组合...)