CREATE MASK ステートメント

CREATE MASK ステートメントは、現行サーバーで列マスクを作成します。 列マスク は列アクセス制御に使用され、指定された列に戻す値を指定します。

呼びかけ CREATE MASK

このステートメントは、アプリケーション・プログラムに組み込むか、あるいは対話式に発行することができます。 これは、DYNAMICRULES RUN動作が有効になっている場合にのみ、動的に準備できる実行可能なステートメントです。 詳細は、「Authorization IDs and dynamic SQL」 を参照してください。

承認 CREATE MASK

以下に定義する特権セットには、次に示す権限が含まれていなければなりません。

  • SECADM 権限

SECADM 権限では、任意のスキーマに列マスクを作成できます。 マスク定義内でその他のオブジェクトを参照するために必要なその他の権限はありません。 例えば、表を照会するための SELECT 特権や、ユーザー定義関数を呼び出すための EXECUTE 特権は必要ありません。

特権セット: アプリケーション・プログラムにこのステートメントを組み込む場合、特権セットは、パッケージ所有者が持つ特権セットとなります。 このステートメントが動的に準備される場合、特権セットは、プロセスの SQL 許可 ID が持つ特権セットとなります。 ただし、ROLE AS OBJECT OWNER AND QUALIFIER 文節で定義されているトラステッド・コンテキスト内でプロセスが実行されている場合、特権セットは、有効なロールが持つ特権セットとなります。

構文 CREATE MASK

構文図を読むビジュアルシンタックスダイアグラムをスキップするCREATE MASKmask-nameONtable-name AScorrelation-nameFOR COLUMNカラム名RETURNcase-expressionDISABLEENABLE

説明の対象: CREATE MASK

マスク名
列マスクの名前を指定します。 この名前 (暗黙修飾子または明示修飾子を含む) には、現行サーバーに既に存在する列マスクまたは行の許可を指定しないでください。
ON テーブル名
列マスクを作成する対象の表を指定します。 この名前は、現行サーバーに存在する表を示すものでなければなりません。 以下のオブジェクトを指定することはできません。
  • 補助表
  • 作成済みまたは宣言済みの一時表
  • ビュー
  • カタログ表
  • 別名
  • シノニム
  • マテリアライズ照会表の定義で直接または間接的に参照される、マテリアライズ照会表または表
  • XML 列のために暗黙的に作成された表
  • 期間が含まれている表
  • 履歴表
  • アクセラレーターのみの表
  • アーカイブ可能な表
  • アーカイブ表
相関名
表を指定するために case-expression 内で使用できる相関名を指定します。 相関名については、「相関名」 を参照してください。
FOR COLUMN カラム名
マスクを適用する列を指定します。 column-name は、指定された表の列を識別する非修飾名でなければなりません。 この列にはマスクが既に存在していてはなりません。 以下の列は指定できません。
  • LOB 列、または LOB に基づく特殊タイプ列
  • XML 列
  • FIELDPROC で定義されている列
RETURN ケース式
列に返される値を判別する CASE 式を指定します。 CASE 式の結果が、行の列値の位置に返されます。 CASE 式の結果のデータ・タイプ、NULL 属性、データ長、サブタイプ、コード化スキーム、および CCSID は、column-name により指定される列の属性と一致している必要があります。 column-name のデータ・タイプがユーザー定義データ・タイプの場合、CASE 式の結果のデータ・タイプは、同じユーザー定義データ・タイプでなければなりません。 CASE 式で参照してはならないオブジェクトを以下に示します。
  • リモート・オブジェクト
  • 列マスクが定義されている表
  • 作成済みのグローバル一時表または宣言済みのグローバル一時表
  • 補助表
  • XML 列のために暗黙的に作成された表
  • FIELDPROC を使用して定義されている列
  • LOB 列、または LOB に基づく特殊タイプ列
  • XML 列
  • SELECT 文節内の選択リストの表記: * または name.*
  • 表関数
  • コレクション派生表 (UNNEST)
  • 非セキュアとして定義されているユーザー定義関数
  • 非 deterministic 関数または外部アクションが含まれている関数
  • 集約関数 (副照会に指定されている場合を除く)
  • 組み込み表関数
  • XMLTABLE 表関数
  • XMLEXISTS 述部
  • OLAP 仕様
  • ROW CHANGE 式
  • シーケンス参照
  • ホスト変数、SQL 変数、SQL パラメーター、またはトリガー遷移変数
  • パラメーター・マーカー
  • 期間指定が含まれている表参照。
  • 前述のいずれかの制限が定義に含まれるビュー。
  • アクセラレーターのみの表
  • 変更の開始AI_ANALOGY、AI_COMMONALITY、AI_SEMANTIC_CLUSTER、またはAI_SIMILARITY関数。変更の終わり

表のコード化スキームは、CASE 式の評価に使用されます。 Unicode 列が入っている EBCDIC 表を除く、複数のコード化スキーム評価を必要とする表および言語エレメントを CASE 式で参照してはなりません。 複数の評価を必要とする言語要素については、 文字列の符号化スキームとCCSIDルールを参照のこと。

行アクセス制御または列アクセス制御がアクティブになっている表を CASE 式で参照している場合、これらの表のアクセス制御はカスケードされません。

無効にするか、 ENABLE
列アクセス制御のための列マスクを有効または無効にすることを指定します。
DISABLE
列アクセス制御のための列マスクを無効にすることを指定します。 表で列アクセス制御がアクティブにされているかどうかに関係なく、列マスクは無効になります。

DISABLE がデフォルトです。

ENABLE
列アクセス制御のための列マスクを有効にすることを指定します。 表で列アクセス制御が現在アクティブではない場合、表の列アクセス制御がアクティブにされる時点で列マスクが有効になります。 表で列アクセス制御が現在アクティブな場合、列マスクは直ちに有効になり、この表を参照する動的ステートメント・キャッシュ内のステートメントとパッケージはすべて無効になります。 詳細は、「パッケージが無効になる変更 」を参照してください。

注釈 CREATE MASK

カラムマスクがクエリに与える影響

有効な列マスクを適用しても、ステートメント内の他の文節 (WHERE、GROUP BY、HAVING、SELECT DISTINCT、または ORDER BY など) の操作が妨げられることはありません。 最終結果表に返される行は、結果行に含まれている値が列マスクによってマスクされた可能性があるという点を除けば、違いはありません。 このため、sort-key 式が含まれている ORDER BY 文節にマスクされた列も指定されている場合、順序は列の元の値に基づいており、最終結果表のマスクされた値にはこの順序が反映されていないことがあります。 同様に、マスクされた値は、SELECT DISTINCT ステートメントまたは COUNT (DISTINCT expression) 関数によって強制される一意性が反映されていない可能性があります。 マスクされる列が式に組み込まれていると、列マスクは式の評価が行われる前に列に適用されるため、式の結果が異なる場合があります。

カラムマスクの定義とSQLの間の矛盾
列マスクはスタンドアロン・オブジェクトとして作成され、列マスクの作成時点では、列マスクが使用されるコンテキストは不明です。 最終結果テーブルのカラムの値をマスクするには、 Db2 によって、マスクされたカラムの定義がクエリにマージされます。 列マスクの定義がステートメントのコンテキストに取り込まれるときに、この定義がステートメントの特定の SQL セマンティクスと矛盾することがあります。 したがって、特定の状況では、ステートメントと列マスクの適用方法の組み合わせによってはエラーが戻されることがあります。 この状況が発生した場合は、ステートメントを変更するか、または列マスクの削除または異なる定義での再作成を行う必要があります。 ステートメントに対してバインド時エラーが発行される可能性がある状況については、 ALTER TABLE ステートメントを参照してください。
カラムマスクとヌルカラム
NULL 可能ではない列の列マスクの定義では、ほとんどの場合、列の NULL 値が考慮されていません。 外部結合の NULL 埋め込み表の場合、表の列アクセス制御がアクティブにされた後で、最終結果表の列値が NULL になる可能性があります。 列マスクがNULL値をマスクできるようにするため、テーブルが外部結合のNULLパディングテーブルである場合、 Db2 は列マスク定義の最初のWHEN句に「WHEN 目標列 IS NULL THEN NULL 」を追加します。 これにより、NULL 値が常に NULL 値として強制的にマスクされます。 NULL 可能列の場合、これにより、NULL 値を他の値としてマスクすることができなくなります。 例 5 に、この追加される WHEN 文節を示します。
SQL データ変更ステートメントの列マスク値
INSERT、UPDATE、MERGE、または SET transition-variable 割り当てステートメントのために新しい値を導き出す目的で列を使用する場合、列の元の値 (マスクされていない値) を使用して新しい値が導き出されます。 列に列マスクがある場合、これらの列マスクが適用されます。これにより、実行時のアクセス制御ルールの評価によって、列が定数や式ではなく、その列自体にマスクされます。 これにより、マスクされた値が、元の列値と同一になります。 列マスクによって列がそれ自体に対してマスクされない場合、既存の行が更新されないか、新規行が挿入されず、実行時にエラーが戻されます。 新しい値を得るために列マスクを適用するときに使用されるルールは、照会の最終結果表の同じルールに従います。
列アクセス制御が有効化される前に作成された列マスク
CREATE MASK ステートメントは独立したステートメントであり、このステートメントを使用して、表の列アクセス制御をアクティブにする前に列アクセス制御マスクを作成することができます。 この場合の唯一の要件は、表と列がマスクの作成前に存在していることです。 単一の表に対して複数の列マスクを作成できますが、1 つの列に設定できるマスクは 1 つのみです。

マスクの定義は、 Db2 カタログに保存されています。 マスクの作成対象の表への従属関係と、定義で参照されるその他のオブジェクトへの従属関係が記録されます。 パッケージや動的キャッシュ・ステートメントは無効になりません。 列マスクの作成時には、列アクセス制御のためにその列マスクを有効にするか無効にするかを指定できます。 有効に設定されている列マスクは、ACTIVATE COLUMN ACCESS CONTROL 節が指定された ALTER TABLE ステートメントを使用して表の列アクセス制御がアクティブになった後で、初めて有効になります。 ALTER TABLE ステートメントを発行するには SECADM 権限が必要です。 表の列アクセス制御がアクティブになっても、無効な列マスクは引き続き無効です。 ALTER MASK ステートメントを使用して、ENABLE と DISABLE を切り替えることができます。

テーブルに対して列アクセス制御が有効化された後、そのテーブルがデータ操作文で参照された場合、そのテーブルに対して作成された有効な列マスクはすべて、 Db2 によって暗黙的に適用され、クエリの最終結果テーブルで参照された列の返された値をマスクしたり、データ変更文で使用される新しい値を決定したりします。

ヒント : テーブルを参照するパッケージや動的キャッシュ文が無効になることを複数回回避するには、テーブルの列アクセス制御を有効にする前に列マスクを作成します。
列アクセス制御が有効化された後に作成された列マスク
有効に設定されている列マスクは、コミット後に直ちに有効になります。 表を参照するパッケージと動的キャッシュ・ステートメントはすべて無効になります。 その後、データ操作ステートメントでテーブルが参照されると、有効なカラムマスクはすべて、 Db2 によってステートメントに暗黙的に適用されます。 表の列アクセス制御がアクティブになっても、無効な列マスクは引き続き無効です。
カラムまたは行のアクセス制御が適用されているテーブルがカラムマスク定義で参照されている場合、カスケード効果なし
列マスク定義が、行アクセス制御または列アクセス制御が現在適用されている表と列を参照することがあります。 列マスクの作成対象の表がデータ操作ステートメントで参照される場合、このような表と列のアクセス制御は無視されます。
複数のカラムマスクと行の権限が同じ環境変数を共有
単一の表に対して、複数の列マスクと行の許可を作成できます。 これらの列マスクと行の許可は同じ環境変数セットを使用する必要があります。 このような環境変数は、表に対して最初の列マスクまたは行の許可が作成される時点で決定します。

カタログ表 SYSENVIRONMENT に、環境変数のリストが含まれています。 複数の列マスクと行の許可において同一である必要がある環境変数を次の表に示します。

表 1. SYSIBM.SYSENVIRONMENT の環境変数
SYSENVIRONMENT 列として示される環境変数 説明 静的 create ステートメント 動的 create ステートメント 複数の列マスクと行の許可において同一である必要がある
ENVID 環境の内部 ID Db2 による割り当て Db2 による割り当て はい
CURRENT_SCHEMA 表やビューなどの非修飾オブジェクトを修飾するために使用される修飾子。 など。 パッケージ所有者 CURRENT_SCHEMA 特殊レジスターの値 はい
PATHSCHEMAS ユーザー定義関数やユーザー定義データ型用のCAST関数などの修飾されていないオブジェクトを修飾するために使用されるスキーマパス。 PATH バインド・オプション CURRENT_PATH 特殊レジスターの値 はい
application_
encoding_
ccsid
アプリケーション環境の CCSID ENCODING バインド・オプション CURRENT APPLICATION ENCODING SCHEME 特殊レジスター はい
オリジナル_
エンコーディング_
CCSID
ステートメント・テキスト・ストリングのオリジナル CCSID CCSID(n) プリコンパイラー・オプション、または DSNTIPF インストール・パネルの EBCDIC CCSID DSNTIPF インストール・パネルの DEF ENCODING SCHEME に基づく CCSID はい
DECIMAL_POINT 小数点の標識 COMMA または PERIOD プリコンパイラー・オプション、あるいは DSNTIPF インストール・パネルの DECIMAL POINT IS DSNTIPF インストール・パネルの DECIMAL POINT IS はい
MIN_DIVIDE_SCALE 最小除算位取り DSNTIP4 インストール・パネルの MINIMUM DIVIDE SCALE DSNTIP4 インストール・パネルの MINIMUM DIVIDE SCALE はい
STRING_DELIMITER COBOL ストリング定数で使用されるストリング区切り文字 APOST プリコンパイラー・オプション、または DSNTIPF インストール・パネルの STRING DELIMITER DSNTIPF インストール・パネルの STRING DELIMITER いいえ
sql_
string_
区切り文字
定数で使用される SQL ストリング区切り文字 APOSTSQL プリコンパイラー・オプション、または DSNTIPF インストール・パネルの SQL STRING DELIMITER DSNTIPF インストール・パネルの SQL STRING DELIMITER はい
MIXED_DATA 混合 DBCS データを使用します DSNTIPF インストール・パネルの MIXED DATA DSNTIPF インストール・パネルの MIXED DATA はい
decimal_
算術
CURRENT PRECISION と、10 進演算で両方のオペランドの精度が 15 以下であるときに使用される規則。 DEC(15) または DEC(31) プリコンパイラー・オプション、あるいは DSNTIP4 インストール・パネルの DECIMAL ARITHMETIC DSNTIP4 インストール・パネルの DECIMAL ARITHMETIC はい
DATE_FORMAT 日付形式 DATE プリコンパイラー・オプション、または DSNTIP4 インストール・パネルの DATE FORMAT DSNTIP4 インストール・パネルの DATE FORMAT はい
TIME_FORMAT 時刻形式 TIME プリコンパイラー・オプション、または DSNTIP4 インストール・パネルの TIME FORMAT DSNTIP4 インストール・パネルの TIME FORMAT はい
FLOAT_FORMAT 浮動小数点形式 FLOAT (S390 | IEEE) プリコンパイラー・オプションまたはデフォルトの FLOAT S390 デフォルトの FLOAT S390 いいえ
HOST_LANGUAGE ホスト言語 HOST プリコンパイラー・オプション、または DSNTIPF インストール・パネルの LANGUAGE DEFAULT DSNTIPF インストール・パネルの LANGUAGE DEFAULT いいえ
CHARSET 文字セット CCSID(n) プリコンパイラー・オプション、または DSNTIPF インストール・パネルの EBCDIC CCSID DSNTIPF インストール・パネルの EBCDIC CCSID いいえ
FOLD FOLD は、HOST_LANGUAGE が C または CPP である場合にのみ適用可能です。 それ以外の場合、FOLD はブランクです。 HOST(C(FOL D) プリコンパイラー・オプションまたはデフォルトの NO FOLD デフォルトの NO FOLD いいえ
ROUNDING DECFLOAT データに対して算術計算およびキャスト演算が実行される場合に使用される丸めモード. ROUNDING バインド・オプション CURRENT DECFLOAT ROUNDING MODE 特殊レジスター はい
注意: データ共有環境において、グループの各メンバに個別のDSNHDECPモジュールが提供されている場合、各環境変数のDSNHDECP設定は、データ共有グループのすべてのメンバで同じである必要があります。そうでない場合、複数の列マスクまたは行権限が作成された際にエラーが発生する可能性があります。
COBOL アプリケーションで静的 CREATE MASK ステートメントに指定される通常の SQL ID:
CREATE MASK ステートメントが COBOL アプリケーションの静的ステートメントである場合、列マスク定義で使用される通常の SQL ID は、COBOL ワードの名前指定に関する規則に準拠してはなりません。 SQLにおける識別子の命名規則に従う必要があります。 例えば、COBOL ワード 1ST-TIME は、列マスク定義では通常の SQL ID として使用できません。FIRST_TIME に変更するか、区切り文字で囲んでください。
列マスク適用後のデータ操作ステートメントのコード化スキームと CCSID:
Db2 によって暗黙的に適用される列アクセス制御用の列マスクは、データ操作文のエンコード方式やCCSIDには影響しません。 Unicode 列が入っている EBCDIC 表を除くターゲット表または参照先の表では、その表のコード化スキームおよび CCSID を使用して列マスク定義が評価されます。 Unicode 列が入っている EBCDIC 表を除くターゲット表または参照先の表では、複数のコード化スキームの規則を使用して列マスク定義が評価されます。
Db2 の制限事項への配慮:
データ操作文がすでにステートメント内でいくつかの Db2 制限に近づいている場合、有効化された列マスクと有効化された行権限が作成されるほど、制限に影響を与える可能性が高くなることに注意する必要があります。 例えば、このような列マスクと行の許可が原因で、ステートメントが、ソートを必要とし、集約関数 (MULTIPLE DISTINCT および GROUP BY) を評価する照会操作の列の最大合計長 (32600 バイト) を超える可能性があります。 これは、データ操作ステートメントで表が参照される場合に、有効な列マスク定義と行の権限の定義が暗黙にこのステートメントにマージされるためです。 ステートメントの制限については、SQL リファレンスの「 Db2 for z/OS® 」を参照してください。
保留定義変更に関する制約事項は、以下のとおりです。
マスクが、定義変更を保留している表で定義されているか、またはそれらの表を参照している場合、CREATE MASK は許可されません。

CREATE MASK

以下の例では、列 SSN のデータ・タイプは VARCHAR (11) です。

例 1
表 EMPLOYEE の列アクセス制御がアクティブになった後で、給与管理部門の Paul は、従業員番号が 123456 の従業員のソーシャル・セキュリティー番号を確認できます。 管理者 Mary は、ソーシャル・セキュリティー番号の最後の 4 文字のみを確認できます。 Peter は給与管理部門に属しておらず、また管理者でもないため、ソーシャル・セキュリティー番号を確認できません。
CREATE MASK SSN_MASK ON EMPLOYEE
   FOR COLUMN SSN RETURN
     CASE 
          WHEN (VERIFY_GROUP_FOR_USER(SESSION_USER,'PAYROLL') = 1)
			      THEN SSN
          WHEN (VERIFY_GROUP_FOR_USER(SESSION_USER,'MGR') = 1)
           THEN 'XXX-XX-' || SUBSTR(SSN,8,4)
          ELSE NULL
     END
   ENABLE;

COMMIT;

ALTER TABLE EMPLOYEE 
    ACTIVATE COLUMN ACCESS CONTROL;

COMMIT;

SELECT SSN FROM EMPLOYEE 
    WHERE EMPNO = 123456;
例 2
SELECT ステートメントで、列マスク SSN_MASK に使用されている式と同じ式に列 SSN が組み込まれています。 表 EMPLOYEE に対して列アクセス制御をアクティブにした後に、列マスク SSN_MASK が SELECT ステートメントの列 SSN に適用されます。 この特定の式の場合、SELECT ステートメントの結果は、すべてのユーザーに対して列アクセス制御をアクティブにする前と同じ結果になります。 ユーザーは SELECT ステートメントの式を列 SSN に置き換え、同じ式が 2 回評価されることを防ぐことができます。
CREATE MASK SSN_MASK ON EMPLOYEE
    FOR COLUMN SSN RETURN
      CASE 
           WHEN (1 = 1) 
            THEN 'XXX-XX-' || SUBSTR(SSN,8,4)
           ELSE NULL
      END
    ENABLE;

COMMIT;

ALTER TABLE EMPLOYEE 
    ACTIVATE COLUMN ACCESS CONTROL;

COMMIT;

SELECT 'XXX-XX-' || SUBSTR(SSN,8,4) FROM EMPLOYEE 
    WHERE EMPNO = 123456;
例 3
州政府が、各都市の世帯における図書館利用に関する調査を実施しました。 各都市から 50 世帯がこの調査対象として抽出されました。 各世帯には、調査結果から生成されるすべてのレポートにおいて各自の利用状況を表示するかどうかを指定するオプション (オプトインまたはオプトアウト) が与えられました。

SELECT ステートメントを使用して、各都市の世帯の平均利用時間を示すレポートが生成されます。 抽出された世帯が選択したオプトインまたはオプトアウトの情報に基づいて都市名をマスクするため、列マスク CITY_MASK が作成されます。 ただし、表 LIBRARY_ USAGE に対して列アクセス制御をアクティブにした後に、SELECT ステートメントがバインド時エラーを受け取りました。 このエラーは、列マスク CITY_MASK が別の列 LIBRARY_OPT を参照しており、この LIBRARY_OPT がグループ化列を識別していないために発生します。

CREATE MASK CITY_MASK ON LIBRARY_USAGE
    FOR COLUMN CITY RETURN
      CASE 
           WHEN (LIBRARY_OPT = 'OPT-IN') 
            THEN CITY
           ELSE ' '
      END
    ENABLE;

COMMIT;

ALTER TABLE LIBRARY_USAGE
   ACTIVATE COLUMN ACCESS CONTROL;

COMMIT;

SELECT CITY, AVG(LIBRARY_TIME) FROM LIBRARY_USAGE 
   GROUP BY CITY;
例 4
EMPNO が 123456 の従業員の 5 月のボーナスは $8000、給与は $80000 です。 管理職がこの従業員の給与を取り出すときに、NULL 値ではなく給与額が取り出されます。 これは、列マスク SALARY_MASK が、列マスク BONUS_MASK が定義されている列 BONUS を参照する場合、カスケード効果が発生しないためです。
CREATE MASK SALARY_MASK ON EMPLOYEE
   FOR COLUMN SALARY RETURN 
       CASE 
            WHEN (BONUS < 10000) 
             THEN SALARY
            ELSE NULL
       END
   ENABLE;

COMMIT;

CREATE MASK BONUS_MASK ON EMPLOYEE
   FOR COLUMN BONUS RETURN
       CASE 
            WHEN (BONUS > 5000) 
             THEN NULL
            ELSE BONUS
       END
   ENABLE;

COMMIT;

ALTER TABLE EMPLOYEE 
    ACTIVATE COLUMN ACCESS CONTROL;

COMMIT;

SELECT SALARY FROM EMPLOYEE 
    WHERE EMPNO = 123456;
例 5
この例では、 Db2 が「WHEN target-column IS NULL THEN NULL」をカラムマスク定義の最初のWHEN句として追加し、その後にカラムマスク定義をステートメントにマージしています。
CREATE EMPLOYEE (EMPID INT,
                 DEPTID CHAR(8),
                 SALARY DEC(9,2) NOT NULL,
                 BONUS DEC(9,2));

CREATE MASK SALARY_MASK ON EMPLOYEE
    FOR COLUMN SALARY RETURN
       CASE 
            WHEN SALARY < 10000 
             THEN CAST(SALARY*2 AS DEC(9,2))
            ELSE COALESCE(CAST(SALARY/2 AS DEC(9,2)), BONUS)
       END
    ENABLE;

COMMIT;

CREATE MASK BONUS_MASK ON EMPLOYEE
    FOR COLUMN BONUS RETURN 
      CASE 
          WHEN BONUS > 1000 
           THEN BONUS
          ELSE NULL
      END
    ENABLE;

COMMIT;

ALTER TABLE EMPLOYEE
    ACTIVATE COLUMN ACCESS CONTROL;

COMMIT;

SELECT SALARY FROM DEPT 
    LEFT JOIN EMPLOYEE ON DEPTNO = DEPTID;

/* When SALARY_MASK is merged into the above statement,
 * 'WHEN SALARY IS NULL THEN NULL' is added as the 
 * first WHEN clause, as follows:
 */

SELECT CASE WHEN SALARY IS NULL THEN NULL
            WHEN SALARY < 10000 THEN CAST(SALARY*2 AS DEC(9,2))
            ELSE COALESCE(CAST(SALARY/2 AS DEC(9,2)), BONUS)
       END SALARY
       FROM DEPT 
         LEFT JOIN EMPLOYEE ON DEPTNO = DEPTID;