SQL:何时以及为什么两个条件允许?

Ste*_*ger 3 sql t-sql sql-server postgresql join

题:

我最近有一个有趣的SQL问题.
我必须得到租赁合同的租赁合同.

问题是,每个房间可能有多个租赁合同,每个房间有多个租赁对象.

但是,由于糟糕的数据库修补,租赁合同被分配给房间,而不是租赁对象.因此,我必须取合同号,并将其与租赁对象号进行比较,以获得正确的结果.

我以为这会做:

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 ...
Run Code Online (Sandbox Code Playgroud)

但是,因为映射表在我有合同号之前就加入了,并且我没有映射表就无法获得合同号,所以我有两倍的条目.

问题有点复杂,因为没有租赁合同的房间也需要出现,所以我不能只使用内部连接.

通过一些实验,我发现这可以按预期工作:

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 ...
Run Code Online (Sandbox Code Playgroud)

我现在明白为什么这两个条件在一个连接中,通常是查询设计者的礼貌,可能是有用的,它有什么不同.

我想知道这是否是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 
Run Code Online (Sandbox Code Playgroud)

并尝试将其变为一个有两个条件

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 
Run Code Online (Sandbox Code Playgroud)

所以我认为它是特定于t-sql的,但很快就在MS-SQL中尝试过,只是为了让我惊讶地发现它在那里也不起作用.

我认为可能是因为缺少外键,所以我在我的房间查询中的所有表上删除了它们,但它仍然无效.

所以我的问题是:
为什么2条件条件甚至是合法的,这是否有名称,为什么它不适用于我的第二个例子?

Dam*_*ver 5

这是标准的SQL.每个人JOIN都必须有相应的ON条款.所有你正在做的就是改变连接发生在1的顺序- 这有点像改变表达式的包围以绕过优先规则.

A JOIN B ON <cond1> JOIN C ON <cond2>
Run Code Online (Sandbox Code Playgroud)

首先加入AB基于cond1.然后它采用组合的行集并将其加入到C基于cond2.

A JOIN B JOIN C ON <cond1> ON <cond2>
Run Code Online (Sandbox Code Playgroud)

首先加入BC基于cond1.然后A基于它将它连接到先前的组合行集cond2.


它应该在PostgreSQL中工作 - 这是SELECT语句文档的相关部分:

其中from_item可以是以下之一:
[仅] table_name [*] [[AS]别名[(column_alias [,...])]]
(选择)[AS]别名[(column_alias [,...])]
with_query_name [[AS]别名[(column_alias [,...])]]
function_name([argument [,...]])[AS]别名[(column_alias [,...] | column_definition [,...] )]
function_name([argument [,...]])AS(column_definition [,...])
from_item [NATURAL] join_type from_item [ON join_condition | 使用(join_column [,...])]

这是最后一行是相关的.请注意,它是一个递归定义 - 连接的左侧和右侧可以是任何东西 - 包括更多连接.


1与SQL一样,这是逻辑处理顺序 - 如果结果一致,系统可以按照感觉最好的顺序自由执行物理处理.