DOMAIN_CHECK

目的

DOMAIN_CHECKは、まずexprの引数のデータ型を、対応するドメイン列のデータ型に変換します。次に、domain_nameの制約条件(nullまたはチェック制約ではない)をexprに適用します。

ドメインの制約が遅延または未検証の場合、DOMAIN_CHECKでも条件がexprに適用されます。ドメインの制約が無効になっている場合は、DOMAIN_CHECKの一部としてチェックされません。

  • domain_nameは識別子である必要があり、domain_owner.domain_nameを使用して指定できます。domain_ownerなしで指定すると、最初に現在のユーザーに解決され、次にパブリック・シノニムとして解決されます。名前を解決できない場合は、エラーが発生します。

  • domain_nameが存在しないドメインまたはEXECUTE権限を持たないドメインを参照している場合、DOMAIN_CHECKはエラーを生成します。

  • ドメイン列のデータ型がSTRICTの場合、値はドメイン列のデータ型に変換されます。たとえば、ドメイン列のデータ型がVARCHAR2(100) STRICTの場合、値はVARCHAR2(100)に変換されます。変換によって入力が最大長に自動的に切り捨てられることはありません。値が一部の行で'abc'と評価され、ドメインのデータ型がCHAR(2 CHAR)の場合、'ab'を返すかわりに変換は失敗します。

    ドメイン列のデータ型がSTRICTでない場合、値は、長さ、スケールおよび精度に関してドメイン列のデータ型の最も許容できる形に変換されます。たとえば、入力値がVARCHAR2(30)の場合、ドメイン長より短いため、VARCHAR2(100)に変換されます。入力値がVARCHAR2(200)の場合は、ドメイン長よりも大きいため、VARCHAR2(200)のままになります。

  • データ型の変換に失敗すると、エラーがマスクされ、DOMAIN_CHECKFALSEを返します。DOMAIN_CHECKを使用して、特定のドメインの列に挿入できない値をフィルタで除外できます。

    データ型の変換が成功し、domain_nameに有効な制約が関連付けられていない場合、DOMAIN_CHECKTRUEを返します。

  • データ型の変換が成功し、domain_nameに、指定された変換済の値に対してすべて満たされる有効な制約がある場合、DOMAIN_CHECKTRUEを返します。ドメイン制約のいずれかが満たされない場合は、FALSEを返します。

MULTI-COLUMNドメイン

複数列ドメインに対してDOMAIN_CHECKをコールする場合、exprの引数の数がドメイン内の列数と一致する必要があります。一致しない場合、DOMAIN_CHECKによってエラーが発生します。

ドメインDn列がある場合は、DOMAIN_CHECK(D, arg1, ..., argn)などのD+1引数を使用してDOMAIN_CHECKをコールする必要があります。

Dが存在しないか、Dにアクセスする権限がない場合は、エラーが発生します。すべてのチェックがtrueを返した場合、TRUEが返されます。これは、次のことを意味します:

  • arg1Dの列1のデータ型に正常に変換され、arg2Dの列2のデータ型に正常に変換され、argnDの列nのデータ型に正常に変換されます。

  • Dの有効な制約はすべて、Dの列1のデータ型に変換済のarg1で置換された列1、Dの列2のデータ型に変換済のarg2で置換された列2、Dの列nのデータ型に変換済のargnで置換された列nで満たされます。

次の例では、NUMBER型の2つの列c1およびc2を含むドメインdgreaterと、c1c2より大きいチェック制約を作成します:

CREATE DOMAIN dgreater AS (c1 AS NUMBER, c2 AS NUMBER ) CHECK (c1 > c2);

次に、DOMAIN_CHECK (dgreater, 1, 2)FALSEを返します。これは、c1c2より小さいためです(チェック条件が失敗します)。c1c2より大きい(チェック条件が合格する)ため、DOMAIN_CHECK (dgreater, 2, 1)TRUEを返します。

フレキシブル・ドメイン

フレキシブル・ドメインに対してDOMAIN_CHECKをコールする場合、exprの引数の数は、ドメイン列と判別式の数と一致する必要があります。一致しない場合、DOMAIN_CHECKによってエラーが発生します。

フレキシブル・ドメイン制約の確認は、対応するサブドメインの制約の確認と同じです。

DOMAIN_CHECKを使用するには、フレキシブル・ドメインに対するEXECUTE権限が必要です。

フレキシブル・ドメインに対するEXECUTE権限が必要な操作(列をフレキシブル・ドメインに関連付ける場合や、最初の引数のフレキシブル・ドメイン名にDOMAIN_CHECKを行う場合など)には、サブドメインに対するEXECUTE権限が必要です。これは、フレキシブル・ドメインが作成中に複数列ドメインに変換されるためです。したがって、次のルールが適用されます:

  • 列をフレックス・ドメインに関連付けることは、対応する複数列ドメインに関連付けることと同じです。

  • フレキシブル・ドメイン制約の確認は、対応する複数列ドメインの制約の確認と同じです。

  • フレキシブル・ドメイン表示および順序プロパティの評価は、対応する複数列ドメインのプロパティの評価と同等です。

例1

次の例では、データ型CHAR(3 CHAR)の厳密なドメインを作成します:

 
CREATE DOMAIN three_chars AS CHAR(3 CHAR) STRICT;

DOMAIN_CHECKをコールすると、3文字以下の文字列に対してtrueが返されます。4文字以上の長さの文字列の場合は、falseを返します:

SELECT DOMAIN_CHECK (three_chars, 'ab') two_chars,
       DOMAIN_CHECK (three_chars, 'abc') three_chars,
       DOMAIN_CHECK (three_chars, 'abcd') four_chars;
       
TWO_CHARS   THREE_CHARS FOUR_CHARS
----------- ----------- -----------
TRUE        TRUE        FALSE 

例2

次の例では、NUMBER型の2つの列c1およびc2を含むドメインdgreaterと、c1c2より大きいチェック制約を作成します:

CREATE DOMAIN dgreater AS (
  c1 AS NUMBER, c2 AS NUMBER 
) 
  CHECK (c1 > c2);

最初の問合せは1つの式値を渡します。ドメインに2つの列があるため、エラーが発生します:


SELECT DOMAIN_CHECK (dgreater, 1) one_expr;

ORA-11515: incorrect number of columns in domain association list

2番目の問合せでは次のようになります:

  • first_lowerはドメイン制約に失敗するため、FALSEです

  • first_higherはドメイン制約に合格するため、TRUEです

  • 値は数値に変換できないため、lettersFALSEです


SELECT DOMAIN_CHECK (dgreater, 1, 2) first_lower, 
       DOMAIN_CHECK (dgreater, 2, 1) first_higher,
       DOMAIN_CHECK (dgreater, 'b', 'a') letters;

FIRST_LOWER FIRST_HIGHER LETTERS
----------- -----------  -----------
FALSE       TRUE         FALSE

例3

次の例では、ドメイン制約のないドメインDAY_OF_WEEKを作成します。すべての入力値をCHARに変換できるため、DOMAIN_CHECKへのすべてのコールはtrueを返します。これは厳密でないドメインであるため、長さのチェックはありません。

CREATE DOMAIN day_of_week AS CHAR(3 CHAR);

CREATE TABLE calendar_dates (
  calendar_date    DATE,
  day_of_week_abbr day_of_week
);

INSERT INTO calendar_dates 
VALUES(DATE'2023-05-01', 'MON'), 
      (DATE'2023-05-02', 'tue'), 
      (DATE'2023-05-05', 'fRI');
      
SELECT day_of_week_abbr, 
       DOMAIN_CHECK(day_of_week, day_of_week_abbr) domain_column, 
       DOMAIN_CHECK(day_of_week, calendar_date) nondomain_column, 
       DOMAIN_CHECK(day_of_week, CAST('MON' AS day_of_week)) domain_value, 
       DOMAIN_CHECK(day_of_week, 'mon') nondomain_value
  FROM calendar_dates;
  
DAY DOMAIN_COLUMN   NONDOMAIN_COLUMN   DOMAIN_VALUE   NONDOMAIN_VALUE
--- --------------- ------------------ -------------- -----------------
MON TRUE            TRUE               TRUE           TRUE
TUE TRUE            TRUE               TRUE           TRUE
FRI TRUE            TRUE               TRUE           TRUE
mon TRUE            TRUE               TRUE           TRUE
MON TRUE            TRUE               TRUE           TRUE 

例4

次の例では、値が大文字の曜日名の略語(MONTUEなど)になるように、制約付きのドメインDAY_OF_WEEKを作成します。この制約の検証はコミットまで遅延されるため、無効な値を挿入できます。

DOMAIN_CHECKを使用してドメイン列DAY_OF_WEEK_ABBRの値をテストすると、制約(MON)に準拠する値に対してTRUEが返され、準拠しない値(tuefRI)に対してFALSEが返されます:

CREATE DOMAIN day_of_week AS CHAR(3 CHAR)
  CONSTRAINT CHECK(day_of_week IN ('MON','TUE','WED','THU','FRI','SAT','SUN'))
  INITIALLY DEFERRED;

CREATE TABLE calendar_dates (
  calendar_date    DATE,
  day_of_week_abbr day_of_week
);

INSERT INTO calendar_dates 
VALUES(DATE'2023-05-01', 'MON'), 
      (DATE'2023-05-02', 'tue'), 
      (DATE'2023-05-05', 'fRI');

SELECT day_of_week_abbr, 
       DOMAIN_CHECK(day_of_week, day_of_week_abbr) domain_column, 
       DOMAIN_CHECK(day_of_week, calendar_date) nondomain_column, 
       DOMAIN_CHECK(day_of_week, CAST('MON' AS day_of_week)) domain_value, 
       DOMAIN_CHECK(day_of_week, 'mon') nondomain_value
  FROM calendar_dates;

DAY DOMAIN_COLUMN NONDOMAIN_COLUMN DOMAIN_VALUE NONDOMAIN_VALUE
--- ------------- ---------------- ------------ -----------
MON TRUE          FALSE            TRUE         FALSE
tue FALSE         FALSE            TRUE         FALSE
fRI FALSE         FALSE            TRUE         FALSE

例5

次の例では、2つの遅延制約を持つ複数列のドメイン通貨を作成します:

CREATE DOMAIN currency AS (
  amount        AS NUMBER(10, 2)
  currency_code AS CHAR(3 CHAR)
)
CONSTRAINT supported_currencies_c 
  CHECK ( currency_code IN ( 'USD', 'GBP', 'EUR', 'JPY' ) )
  DEFERRABLE INITIALLY DEFERRED
CONSTRAINT non_negative_amounts_c 
  CHECK ( amount >= 0 )
  DEFERRABLE INITIALLY DEFERRED;

ORDER_ITEMSの列AMOUNTおよびCURRENCY_CODEは、ドメインcurrencyに関連付けられています:

CREATE TABLE order_items (
  order_id      INTEGER,
  product_id    INTEGER,
  amount        NUMBER(10, 2),
  currency_code CHAR(3 CHAR),
  DOMAIN currency(amount, currency_code)
);
INSERT INTO order_items
VALUES (1, 1,    9.99, 'USD'),
       (2, 2, 1234.56, 'GBP'),
       (3, 3, -999999, 'JPY'),
       (4, 4, 3141592, 'XXX') ,
       (5, 5, 2718281, '123');

この問合せでは、DOMAIN_CHECKを4回コールします:

SELECT order_id,
       product_id,
       amount,
       currency_code,
       DOMAIN_CHECK(currency, order_id, product_id) order_product,
       DOMAIN_CHECK(currency, amount, currency_code) amount_currency,
       DOMAIN_CHECK(currency, currency_code, amount) currency_amount,
       DOMAIN_CHECK(currency, order_id, currency_code) order_currency
  FROM order_items;
   
  ORDER_ID PRODUCT_ID     AMOUNT CUR ORDER_PRODUCT AMOUNT_CURRENCY CURRENCY_AMOUNT ORDER_CURRENCY
---------- ---------- ---------- --- ------------- --------------- --------------- -----------
         1          1       9.99 USD FALSE         TRUE            FALSE           TRUE
         2          2    1234.56 GBP FALSE         TRUE            FALSE           TRUE
         3          3    -999999 JPY FALSE         FALSE           FALSE           TRUE
         4          4    3141592 XXX FALSE         FALSE           FALSE           FALSE
         5          5    2718281 123 FALSE         FALSE           FALSE           FALSE 

前述の例では次のようになります:

  • PRODUCT_IDの値がsupported_currencies_c制約に準拠していないため、ORDER_PRODUCTは、すべての行に対してFALSEです。

  • AMOUNT_CURRENCYは、制約(AMOUNT = -999999およびCURRENCY_CODE = "XXX"および"123")に違反する値を含む行に対してFALSEです。有効な値の場合はTRUEです。

  • CURRENCY_AMOUNTは、すべての行に対してFALSEです。これは、最初の4行で最初の引数の値CURRENCY_CODEがすべて文字であるためです。これらをドメインの最初の列の型(NUMBER)に変換できないため、型エラーになります。5番目の行では、金額(2718281)はsupported_currencies_c制約に準拠していません。

  • ORDER_CURRENCYは、制約(CURRENCY_CODE = "XXX"および"123")に違反する値を含む行に対してFALSEです。有効な値の場合はTRUEです。

例6

次の文は、存在しないドメインNOT_A_DOMAINに対して文字列"raises an error"を検証しようとします。これにより、例外が発生します:

SELECT DOMAIN_CHECK(not_a_domain, 'raises an error');
ORA-11504: The domain specified does not exist or the user does not have privileges on the domain for the operation.