创建一个视图,让您向 LEFT JOIN ... ON? 添加条件?
Posted
技术标签:
【中文标题】创建一个视图,让您向 LEFT JOIN ... ON? 添加条件?【英文标题】:Create a view that lets you add conditions to the LEFT JOIN ... ON? 【发布时间】:2015-11-13 15:51:38 【问题描述】:我正在创建一个可供许多客户端应用程序使用的数据库(使用 Oracle 12c)。为了简化,我尝试通过创建不同的视图将尽可能多的逻辑保留在数据库中,这样客户就可以只提出简单的问题,而无需像JOIN
或GROUP BY
这样的更复杂的结构。他们应该只需要从一个视图中执行一个简单的SELECT
和一些WHERE
条件,然后让视图完成繁重的工作。
现在我的问题是我想在表单上提问
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
写查询?
【问题讨论】:
left join
的使用使这变得相当困难。我可能会建议您用更好的表格示例和您想要支持的where
子句的类型提出另一个问题。可能有办法做到这一点。只是切换到inner join
是一种可能的解决方案。
你能告诉我什么会使这些例子更好吗?我考虑过使用INNER JOIN
,但由于我总是想返回左表(a
)中的所有行,我想我需要一个LEFT JOIN
。
在 MSSQL 中,这可以通过表值函数实现。我不确定甲骨文。
您可以使用管道功能做您想做的事情。请参阅此问题的答案:***.com/questions/2059299/…。
我将研究管道功能并返回报告。看起来很有希望。
【参考方案1】:
这可以做到,但您必须拥有所有有效类型的来源,并假设用户/应用程序只会查询有效类型的视图。换句话说,假设表 T 是您的“类型表”,并且您的所有 B、C 和 D 表都在 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 不是“有效”类型(在这种情况下,视图定义将不返回任何行)。
编辑:澄清每条评论;我假设“类型”是表 B、C 和 D 的公共域。如果 B.type 与 C.type 不同(即 B.TYPE 是 NUMERIC(9) 并且 C.type 是 VARCHAR(2) 并且D.TYPE 是 NUMERIC(1)) 那么交叉连接需要独立引用每个“有效类型值集”:
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;
也就是说,你确实有同样的限制:内置在视图def中。必须是“所有有效的 B 类型”、“所有有效的 C 类型”和“所有有效的 D 类型”的某个有限源。除此之外,这在纯 SQL 中是不可行的(事实上,就纯 SQL 而言,它成为一个棘手的问题 - 一个支持通过任何可能的值组合进行过滤的视图,没有过滤器,应该返回所有可能的值组合。 ..)
【讨论】:
感谢您的回答。这是一个非常有趣的选择。正如您所提到的,限制是所有类型都必须是离散的。如果其中一个人说NUMBER(9)
,事情就会崩溃。
一点也不——如果 B 类型不同于 C 类型并且不同于 D 类型,那么您将使用 CROSS JOIN <All valid B types> BT
而不是 CROSS JOIN T BT
等等。但原始限制仍然适用:如果 B 类型、C 类型和 D 类型来自 3 组不同的值,您仍然需要 一些 有效 B 类型的来源,一些有效 C 类型的来源,以及一些有效 D 类型的来源。否则,没有什么说类型必须相同(这是我可能不应该做出的假设)
对不起,我表达不清楚。我想说的是:如果其中一种类型有很多很多不同的值(比如一千个),那么视图将返回大量的行,我想会有性能问题吗?跨度>
不——只要视图被需要 B_TYPE、C_TYPE 和 D_TYPE 的离散规范过滤,那么这些规范将被推送到视图定义中......换句话说,没有 将执行实际的笛卡尔积,除非用户没有指定他们想要返回的参数组合【参考方案2】:
或许,您可以使用“旧式连接语法”:
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
【讨论】:
感谢您的回答。我的目标是客户只需要了解一个视图,而不必担心多个表及其相互关系。如果我理解正确,客户仍然需要了解所有表格。以上是关于创建一个视图,让您向 LEFT JOIN ... ON? 添加条件?的主要内容,如果未能解决你的问题,请参考以下文章