问题:
我最近遇到了一个有趣的 SQL 问题。
我必须获得租赁对象的租赁契约(Contract)。
问题是,每个房间可能有多个租赁契约(Contract),每个房间可能有多个租赁对象。
但是,由于糟糕的数据库修补,租赁契约(Contract)分配给了房间,而不是租赁对象。因此,我必须获取契约(Contract)编号,并将其与租赁对象编号进行比较,以获得正确的结果。
我认为这样可以:
SELECT *
FROM T_Room
LEFT JOIN T_MAP_Room_LeasingObject
ON MAP_RMLOBJ_RM_UID = T_Room.RM_UID
LEFT JON T_LeasingObject
ON LOBJ_UID = MAP_RMLOBJ_LOBJ_UID
LEFT JOIN T_MAP_Room_LeasingContract
ON T_MAP_Room_LeasingContract.MAP_RMCTR_RM_UID = T_Room.RM_UID
LEFT JOIN T_Contracts
ON T_Contracts.CTR_UID = T_MAP_Room_LeasingContract.MAP_RMCTR_CTR_UID
AND T_Contracts.CTR_No LIKE ( ISNULL(T_LeasingObject.LOBJ_No, '') + '.%' )
WHERE ...
但是,因为在我有契约(Contract)号之前就加入了映射表,没有映射表我就无法获得契约(Contract)号,所以我有双倍的条目。
问题有点复杂,因为没有租赁契约(Contract)的房间也需要出现,所以我不能只使用内部连接。
经过一些试验,我发现这可以按预期工作:
SELECT *
FROM T_Room
LEFT JOIN T_MAP_Room_LeasingObject
ON MAP_RMLOBJ_RM_UID = T_Room.RM_UID
LEFT JON T_LeasingObject
ON LOBJ_UID = MAP_RMLOBJ_LOBJ_UID
LEFT JOIN T_MAP_Room_LeasingContract
LEFT JOIN T_Contracts
ON T_Contracts.CTR_UID = T_MAP_Room_LeasingContract.MAP_RMCTR_CTR_UID
ON T_MAP_Room_LeasingContract.MAP_RMCTR_RM_UID = T_Room.RM_UID
AND T_Contracts.CTR_No LIKE ( ISNULL(T_LeasingObject.LOBJ_No, '') + '.%' )
WHERE ...
我现在明白为什么一个连接中的两个 on 条件(通常由查询设计者提供)很有用,以及它有什么不同。
我想知道这是 MS-SQL/T-SQL 特定的东西,还是标准的 sql。
所以我尝试在 PostgreSQL 中使用另外 3 个表。
所以我在另外 3 个表上写了这个查询:
SELECT *
FROM t_dms_navigation
LEFT JOIN t_dms_document
ON NAV_DOC_UID = DOC_UID
LEFT JOIN t_dms_project
ON PJ_UID = NAV_PJ_UID
并试图把它变成一个有条件的两个
SELECT *
FROM t_dms_navigation
LEFT JOIN t_dms_document
LEFT JOIN t_dms_project
ON PJ_UID = NAV_PJ_UID
ON NAV_DOC_UID = DOC_UID
所以我认为它是特定于 t-sql 的,但很快也在 MS-SQL 中进行了尝试,令我惊讶的是发现它在那里也不起作用。
我认为这可能是因为缺少外键,所以我在我的房间查询中删除了所有表上的外键,但它仍然不起作用。
所以我的问题是:
为什么 2 on conditions 甚至是合法的,它有名称吗?为什么它在我的第二个示例中不起作用?
最佳答案
这是标准的 SQL。每个 JOIN
都必须有一个相应的 ON
子句。您所做的只是改变连接在 1 中发生的顺序 - 这有点像更改表达式的括号以绕过优先规则。
A JOIN B ON <cond1> JOIN C ON <cond2>
首先根据cond1
加入A
和B
。然后它采用该组合行集并根据 cond2
将其连接到 C
。
A JOIN B JOIN C ON <cond1> ON <cond2>
首先在cond1
的基础上加入B
和C
。然后它根据 cond2
获取 A
并将其连接到之前的组合行集。
它应该在 PostgreSQL 中工作 - 这是 documentation 的相关部分SELECT 语句的:
where from_item can be one of:
[ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
( select ) [ AS ] alias [ ( column_alias [, ...] ) ]
with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ]
function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )
from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]
相关的是最后一行。请注意,这是一个递归定义 - 连接左侧和右侧可以是任何东西 - 包括更多连接。
1与 SQL 一样,这是逻辑处理顺序 - 系统可以按照它认为最有效的任何顺序自由执行物理处理,只要结果是一致的。
关于SQL:何时以及为什么允许两个 on 条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18976284/