3

質問:

最近、興味深い 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 ...

ただし、契約番号を取得する前にマッピング テーブルが結合され、マッピング テーブルがないと契約番号を取得できないため、エントリが 2 倍になりました。

問題はもう少し複雑で、リース契約のない部屋も表示する必要があるため、内部結合だけを使用することはできませんでした。

少し実験したところ、これが期待どおりに機能することがわかりました。

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 ...

これで、1 つの結合で 2 つの on 条件 (通常はクエリ デザイナーの好意による) が役立つ理由と、それがもたらす違いがわかりました。

これは MS-SQL/T-SQL 固有のものなのか、それとも標準 SQL なのか疑問に思っていました。

そこで、別の 3 つのテーブルを使用して PostgreSQL で試しました。

そこで、他の 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 

条件付きで2つで1つに変えようとしました

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 条件付きでも合法なのか、これには名前があるのか​​、2 番目の例ではなぜ機能しないのか?

4

1 に答える 1

5

標準SQLです。それぞれJOINに対応するON句が必要です。結合が1で発生する順序を変更するだけです。これは、式の括弧を変更して優先順位のルールを回避するようなものです。

A JOIN B ON <cond1> JOIN C ON <cond2>

最初に結合Aし、Bに基づいていcond1ます。C次に、その結​​合された行セットを取得し、に基づいて結合しcond2ます。

A JOIN B JOIN C ON <cond1> ON <cond2>

最初に結合Bし、Cに基づいていcond1ます。次にA、に基づいて、それを取得し、以前に結合された行セットに結合しcond2ます。


PostgreSQL で動作するはずです。SELECT ステートメントのドキュメントの関連部分は次のとおりです。

from_itemはのいずれかです:
[ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
( select ) [ AS ] alias [ ( column_alias [, ...] ) ]
with_query_name [ [ AS ] エイリアス [ ( 列エイリアス [, ...] ) ] ]
関数名 ( [ 引数 [, ...] ] ) [ AS ] エイリアス [ ( 列エイリアス [, ...] | 列定義 [, ...] ) ]
関数名 ( [ 引数 [, ...] ] ) AS ( 列定義 [, ...] )
from_item [ NATURAL ] join_type from_item [ ON join_condition | ] USING (結合列 [, ...] ) ]

関連するのはその最後の行です。これは再帰的な定義であることに注意してください - 結合の左右にあるものは何でもかまいません - より多くの結合を含みます。


1 SQL の場合と同様に、これは論理的な処理順序です。システムは、結果が一貫している限り、最適と思われる順序で物理的な処理を自由に実行できます。

于 2013-09-24T08:23:04.867 に答える