web-dev-qa-db-ja.com

Oracleのプラス(+)表記とANSI JOIN表記の違いは?

ANSI標準のjoin表記法に対してOracleのプラス表記法(+)を使用することの違いは何ですか?

パフォーマンスに違いはありますか?

プラス表記は非推奨ですか?

71
Franz See

知る限り、(+)表記は下位互換性のためにのみ存在します。これは、結合に関するANSI標準が導入される前にOracleがデビューしたためです。これはOracle固有のものであり、利用可能な標準に準拠した同等のバージョンがある場合は、新しいコードで使用しないでください。

2つの間に違いがあるようで、(+)表記にはANSI結合構文にはない制限があります。 Oracle自体は、(+)表記を使用しないことを推奨しています。ここで詳細な説明は Oracle®Database SQL言語リファレンス11gリリース1(11.1)

Oracleでは、Oracleの結合演算子ではなく、FROMOUTER JOIN構文を使用することをお勧めします。 Oracleの結合演算子(+)を使用する外部結合クエリには、FROMOUTER JOIN構文には適用されない以下の規則と制限が適用されます。

  • FROM句の結合構文も含むクエリブロックでは、(+)演算子を指定できません。
  • (+)演算子は、WHERE句でのみ使用できます。または、TABLE句の左相関のコンテキスト(FROM句を指定する場合)で使用できます。また、テーブルまたはビューの列にのみ適用できます。
  • AとBが複数の結合条件で結合されている場合、これらすべての条件で(+)演算子を使用する必要があります。そうしないと、Oracle Databaseは単純な結合の結果の行のみを返しますが、外部結合の結果がないことを警告またはエラーなしで通知します。
  • 外部クエリで1つのテーブルを指定し、内部クエリで別のテーブルを指定した場合、(+)演算子は外部結合を生成しません。
  • 自己結合は有効ですが、(+)演算子を使用してテーブルをそれ自体に外部結合することはできません。

たとえば、次のステートメントは無効です。

SELECT employee_id, manager_id
FROM employees
WHERE employees.manager_id(+) = employees.employee_id;

ただし、次の自己結合は有効です。

SELECT e1.employee_id, e1.manager_id, e2.employee_id
FROM employees e1, employees e2
WHERE e1.manager_id(+) = e2.employee_id;
  • (+)演算子は、任意の式ではなく、列にのみ適用できます。ただし、任意の式には、(+)演算子でマークされた1つ以上の列を含めることができます。
  • (+)演算子を含むWHERE条件は、OR論理演算子を使用して別の条件と組み合わせることができません。
  • WHERE条件は、IN比較条件を使用して、(+)演算子でマークされた列を式と比較できません。

WHERE句に、テーブルBの列と定数を比較する条件が含まれる場合、(+)演算子を列に適用して、OracleがテーブルAの行を返すようにする必要があります。この列に対して生成されたヌル。それ以外の場合、Oracleは単純な結合の結果のみを返します。

3組以上のテーブルの外部結合を実行するクエリでは、1つのテーブルが他の1つのテーブルに対してのみヌル生成テーブルになる場合があります。このため、AとBの結合条件とBとCの結合条件の(+)演算子をBの列に適用することはできません。外部結合の構文については、SELECTを参照してください。

97
nagul

Tony Millerの答えに同意し、(+)シンタックスではできないこともいくつかあると付け加えます。

  • 2つのテーブルを完全に外部結合することはできません。2つの結合のUNION ALLを使用して手動で行う必要があります。
  • テーブルを2つ以上のテーブルに外部結合することはできません。手動でサブクエリを作成する必要があります(つまり:b.id = a.id (+) AND c.id = a.id (+)は受け入れられない句です)
12
Vincent Malgrat

この表記は、Oracle 10(および11)でも引き続きサポートされています。この使用法は「昔ながらの」ものと見なされており、ANSI JOIN構文ほどデータベースに移植性がありません。 +バックグラウンドから来た場合、ANSI JOINに慣れるには少し時間がかかることがありますが、読みやすさもはるかに低いと考えられています。オラクルでブリックバットを投げかける前に知っておくべき重要なことは、ANSI委員会が結合の定義を完了する前に+構文を開発したことです。

パフォーマンスの違いはありません。彼らは同じことを表現しています。

編集:「移植性が低い」とは、「Oracle SQLでのみサポートされている」と言うべきでした。

12
Tony Miller

最も包括的な答えは、明らかに nagul によるものです。

ANSI構文への迅速な変換/マッピングを探している人のための追加:

--
-- INNER JOIN
--
SELECT *
FROM EMP e
INNER JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

 -- Synonym in deprecated Oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO = e.DEPTNO;

--
-- LEFT OUTER JOIN
--
SELECT *
FROM EMP e
LEFT JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

 -- Synonym in deprecated Oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO (+) = e.DEPTNO;

--
-- RIGHT OUTER JOIN
--
SELECT *
FROM EMP e
RIGHT JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

-- Synonym in deprecated Oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO = e.DEPTNO(+);

--
-- CROSS JOIN
--
SELECT *
FROM EMP e
CROSS JOIN DEPT d;

 -- Synonym in deprecated Oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d;

--
-- FULL JOIN
--
SELECT *
FROM EMP e
FULL JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

-- Synonym in deprecated Oracle (+) syntax !NOT WORKING!
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO (+) = e.DEPTNO(+);
11
schnatterer

[〜#〜] ansi [〜#〜]構文を古いOracle結合構文よりも使用する理由の1つはつまり、誤ってデカルト積を作成する可能性はありません。テーブルの数が増えると、古いOracle結合構文でimplicit結合を見逃す可能性がありますが、ANSI構文では、必要な結合を逃すことはできませんexplicitlyそれらに言及します。

Oracle外部結合構文ANSI/ISO構文の違い。

LEFT OUTER JOIN-

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id = d.department_id(+);

SELECT e.last_name,
  d.department_name
FROM employees e
LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id);

右外側結合-

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id(+) = d.department_id;

SELECT e.last_name,
  d.department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON (e.department_id = d.department_id);

完全外部結合-

11gR1でハッシュ完全外部結合がネイティブにサポートされる前は、Oracleは次のように内部で完全外部結合を変換していました。

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id = d.department_id(+)
UNION ALL
SELECT NULL,
  d.department_name
FROM departments d
WHERE NOT EXISTS
  (SELECT 1 FROM employees e WHERE e.department_id = d.department_id
  );

SELECT e.last_name,
  d.department_name
FROM employees e
FULL OUTER JOIN departments d
ON (e.department_id = d.department_id);

this をご覧ください。

2
Lalit Kumar B

Oracle Apps r12に関連するクエリのほとんどすべてがそれに基づいているため、(+)表記を使用します。 Oracle APPSクエリに標準の「結合」式を持つ単一のSQLクエリを見たことはありません(Oracle自体が提供するものも)。信じられない場合は、Oracleアプリ関連の情報をGoogleで検索してください。例: 固定資産関連クエリ

1
Ahmedov

Oracle(+)表記はOracleでのみ使用されます。これはベンダー固有です。そして、ANSI標準結合表記法RDBMS(Sql Server、MySqlなど)で使用にできます。それ以外の場合、Oracle(+)表記とANSI標準結合表記の間に違いはありません。

SQLクエリでANSI標準の結合表記法を使用している場合、任意のRDBMSで同じクエリを使用できます。そして、あなたがportingデータベースOracleから他のRDBMSへその条件でANSI構文を使用にする必要があります。

1
abhishek
  1. 暗黙的ではなく明示的なJOINを使用すると(外部結合であるかどうかに関係なく)、暗黙的な結合を使用して誤ってデカルト積を作成することがはるかに簡単になります。明示的なJOINを使用すると、「誤って」作成することはできません。関係するテーブルが多いほど、1つの結合条件を見逃すリスクが高くなります。
  2. 基本的に(+)はANSI結合と比較して厳しく制限されています。さらに、ANSI結合構文はすべての主要なDBMSでサポートされていますが、Oracleでのみ使用可能です
  3. ANSI構文への移行後、SQLのパフォーマンスは向上しません。これは単なる構文です。
  4. 前の例に示した、より柔軟なFROM句の結合構文を使用することを強くお勧めします。過去にはANSI構文にいくつかのバグがありましたが、最新の11.2または12.1を使用している場合は、すでに修正されているはずです。
  5. JOIN演算子を使用すると、SQLコードがANSIに準拠するようになり、フロントエンドアプリケーションを他のデータベースプラットフォームに簡単に移植できるようになります。
  6. 結合条件は、各テーブルで非常に低い選択性を持ち、理論上のクロス積のタプルで高い選択性を持ちます。 whereステートメントの条件は、通常、選択性がはるかに高くなります。
  7. Oracleは、ANSI構文を内部的に(+)構文に変換します。これは、実行プランの述部情報セクションで確認できます。
1
SriniV