DOMAIN_CHECK_TYPE

目的

DOMAIN_CHECK_TYPEを使用すると、ドメイン制約をチェックせずに、値式をドメイン列のデータ型に変換できます。制約をチェックする場合は、DOMAIN_CHECKを使用する必要があります。

DOMAIN_CHECK_TYPEは、DOMAIN_CHECKと同じ引数を取り、引数のデータ型が対応するドメイン列のデータ型と一致する場合はTRUEを返します。データ型が一致しない場合、FALSEが返されます。

  • 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_CHECK_TYPEFALSEを返します。DOMAIN_CHECK_TYPEを使用して、特定のドメインの列に挿入できない値をフィルタで除外できます。

MULTI-COLUMNドメイン

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

フレキシブル・ドメイン

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

例1

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

CREATE DOMAIN three_chars AS CHAR(3 CHAR) STRICT;

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

SELECT DOMAIN_CHECK_TYPE (three_chars, 'ab') two_chars,
       DOMAIN_CHECK_TYPE (three_chars, 'abc') three_chars,
       DOMAIN_CHECK_TYPE (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_TYPE (dgreater, 1) one_expr;

ORA-11515: incorrect number of columns in domain association list
2番目の問合せでは次のようになります:
  • 値が数値であるため、first_lowerfirst_higherは両方ともTRUEです。ドメイン制約はチェックされません。

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

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

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

例3

次の例では、ドメイン制約のないドメインDAY_OF_WEEKを作成します。すべての入力値をCHARに変換できるため、DOMAIN_CHECK_TYPEへのすべてのコールは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_TYPE(day_of_week, day_of_week_abbr) domain_column, 
       DOMAIN_CHECK_TYPE(day_of_week, calendar_date) nondomain_column, 
       DOMAIN_CHECK_TYPE(day_of_week, CAST('MON' AS day_of_week)) domain_value, 
       DOMAIN_CHECK_TYPE(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

次の例では、値が大文字の曜日名の略語(MON、TUEなど)になるように、制約付きのドメインDAY_OF_WEEKを作成します。

この制約の検証はコミットまで遅延されるため、無効な値を挿入できます。

DOMAIN_CHECK_TYPEを使用すると、すべての値が型チェックに合格するため、すべての値に対してTRUEが返されます:

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_TYPE(day_of_week, day_of_week_abbr) domain_column, 
       DOMAIN_CHECK_TYPE(day_of_week, calendar_date) nondomain_column, 
       DOMAIN_CHECK_TYPE(day_of_week, CAST('MON' AS day_of_week)) domain_value, 
       DOMAIN_CHECK_TYPE(day_of_week, 'mon') nondomain_value
  FROM calendar_dates;

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

例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_TYPEを4回コールします:

SELECT order_id,
       product_id,
       amount,
       currency_code,
       DOMAIN_CHECK_TYPE(currency, order_id, product_id) order_product,
       DOMAIN_CHECK_TYPE(currency, amount, currency_code) amount_currency,
       DOMAIN_CHECK_TYPE(currency, currency_code, amount) currency_amount,
       DOMAIN_CHECK_TYPE(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 TRUE          TRUE            FALSE           TRUE
         2          2    1234.56 GBP TRUE          TRUE            FALSE           TRUE
         3          3    -999999 JPY TRUE          TRUE            FALSE           TRUE
         4          4    3141592 XXX TRUE          TRUE            FALSE           TRUE
         5          5    2718281 123 TRUE          TRUE            TRUE            TRUE

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

  • ORDER_IDおよびPRODUCT_IDの値はドメイン内の対応する列型(NUMBERおよびCHAR)に変換できるため、すべての行に対してORDER_PRODUCTTRUEです。

  • 表の列がドメイン列と一致するため、すべての行に対してAMOUNT_CURRENCYTRUEです。

  • 最初の引数CURRENCY_CODEの値はすべての文字であるため、最初の4行に対してCURRENCY_AMOUNTFALSEです。これらをドメインの最初の列の型(NUMBER)に変換できないため、型エラーになります。5行目はTRUEです。これは、金額(2718281)をCHARに変換できるためです。

  • ORDER_IDおよびCURRENCY_CODEの型は対応するドメイン列型(NUMBERおよびCHAR)と一致するため、すべての行に対してORDER_CURRENCYTRUEです。

例6

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

SELECT DOMAIN_CHECK_TYPE(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.