6

TL; 博士:

ユーザー定義のレコード タイプを宣言して、フィールドの 1 つに入力しない場合、そのフィールドがそのフィールドを尊重するようにするにはどうすればよいDEFAULTですか?


詳細:

私のパッケージ仕様では、次のレコードおよびテーブル タイプを定義します。

/* set up a custom datatypes that will allow us to pass an array of values into CCD_UI procedures and functions */
TYPE RECORD_OPTION_ATTRIBUTES IS RECORD(
    option_name             VARCHAR2(200)   NOT NULL DEFAULT 'INVALID NAME"', /* default intentionally breaks HTML */
    option_value            VARCHAR2(200)   NOT NULL DEFAULT 'INVALID VALUE"', /* default intentionally breaks HTML */
    option_selected_ind     NUMBER(1)       NOT NULL DEFAULT '0',
    option_class            VARCHAR2(200)   DEFAULT NULL,
    option_attributes       VARCHAR2(200)   DEFAULT NULL
);

TYPE TABLE_OPTION_ATTRIBUTES IS TABLE OF RECORD_OPTION_ATTRIBUTES
    INDEX BY BINARY_INTEGER;

パッケージ本体には、これと非常によく似た機能があります。

PROCEDURE populate_user_defined_table()
AS

    v_criteria_pairs        TABLE_OPTION_ATTRIBUTES;

BEGIN

    SELECT some_column1 AS option_name, some_column2 AS option_value, some_column3 AS selected_ind,
        some_column4 AS option_class
    BULK COLLECT INTO v_criteria_pairs
    FROM Some_Table
    WHERE some_column='whatever';

END;

option_attributes鋭い目で見ると、フィールドに値を挿入していないことに気付くでしょう。使用可能な 5 つのフィールドのうち 4 つだけを入力しています。

このパッケージをコンパイルしようとすると、パッケージ本体から次のエラーが表示されます。

PL/SQL: ORA-00913: 値が多すぎます

option_attributes宣言からフィールドを削除するRECORD_OPTION_ATTRIBUTESと、パッケージはコンパイルされます。

の値を指定しない場合option_attributes、そのフィールドのデフォルトが になるように、レコード タイプを宣言するにはどうすればよいNULLですか?

4

4 に答える 4

1

select [bulk collect] into構文を使用する場合はできません。あなたが言ったコメントで:

1) ユーザー定義レコードではデフォルト値を定義できる、2) ユーザー定義レコードのすべてのフィールドにデータを入力する必要がある、という両方のステートメントが当てはまるとしたら、それはおかしな話です。

最初のステートメントは真です。2 番目は、クエリからレコード全体を割り当てる場合にのみ当てはまります。

ドキュメントには次のように書かれています

RECORD 型のレコード変数の場合、型を定義するときに別の初期値を指定しない限り、各フィールドの初期値は NULL です。

したがって、レコード変数を作成すると、デフォルトが設定されます。

declare
  v_rec RECORD_OPTION_ATTRIBUTES;
begin
  dbms_output.put_line(v_rec.option_name ||':'|| v_rec.option_value
    ||':'|| v_rec.option_selected_ind ||':'|| v_rec.option_class
    ||':'|| v_rec.option_attributes);
end;
/

INVALID NAME":INVALID VALUE":0::

PL/SQL procedure successfully completed.

その後、フィールド値を個別に設定してデフォルトを上書きできます。

レコード変数を選択すると、

select_listの各列について、レコード変数には、対応する型互換性のあるフィールドが必要です。select_listの列は、レコード フィールドと同じ順序で表示される必要があります。

レコードタイプよりも少ない値を選択リストに入れることはできないと明示的に言っているわけではありませんが、2番目の文はそれを暗示しています。たまたまレコードの最後に余分なフィールドを追加しましたが、それを最初に置くことを止めるものは何もありませんでした。これは明らかに違反していたでしょう。選択リストのどの列がレコードのどのフィールドにマップされるかを指定するメカニズムがないため、まったく同じ番号、同じ型、同じ順序で指定する必要があります。

クエリからの値を使用してレコードが入力され、常にデフォルトが上書きされます。フィールド値を指定することはできません。(クエリが列の値を null と評価したとしても、それはデフォルトをオーバーライドします。クエリがそうであった場合SELECT null AS option_name, ...、フィールドが null ではないため、ORA-06502 数値または値のエラーが発生します)。select intoしたがって、 を使用する場合でも、 を使用する場合でも、使用しない場合でも、デフォルトは適用されませんbulk collect

残念ながら、余分なフィールドを使用して新しいレコードとテーブルのタイプを追加します (元のタイプを期待するプロシージャに渡すことができないため、おそらく実用的ではありません。変換関数を追加することもできますが、それは単にさらに悪いこと)、または@MartinSchapendonkが示唆したように、ヒットして既存のコードを変更してください。

コレクション/レコードのみを処理するものは、新しいフィールドを参照しないため、何も変更する必要はないかもしれません。また、レコードを直接構築するものを変更する必要はありません。カーソル ループ内であっても (レコード変数にフェッチされない)、デフォルトの null 値が取得されるためです。select intoselect bulk collect into、またはを使用して、コレクション/レコードが SQL クエリからどのように入力されるかを (!) 変更する必要があるだけですfetch into

于 2016-11-02T13:53:11.210 に答える
1
TYPE RECORD_OPTION_ATTRIBUTES IS RECORD(
    option_name             VARCHAR2(200)   NOT NULL DEFAULT 'INVALID NAME"', /* default intentionally breaks HTML */
    option_value            VARCHAR2(200)   NOT NULL DEFAULT 'INVALID VALUE"', /* default intentionally breaks HTML */
    option_selected_ind     NUMBER(1)       NOT NULL DEFAULT '0',
    option_class            VARCHAR2(200)   DEFAULT NULL,
    option_attributes       VARCHAR2(200)   DEFAULT NULL
);

TYPE TABLE_OPTION_ATTRIBUTES IS TABLE OF RECORD_OPTION_ATTRIBUTES
    INDEX BY BINARY_INTEGER;



PROCEDURE populate_user_defined_table()
AS
  CURSOS cur IS -- cursor selecting values without last column
  SELECT some_column1 AS option_name, some_column2 AS option_value,some_column3 AS selected_ind, some_column4 AS option_class
   FROM Some_Table
  WHERE some_column='whatever';

 TYPE t_tmp_arr IS TABLE OF cur%rowtype index by pls_integer;

 v_tmp_arr               t_tmp_arr;
 v_criteria_pairs        TABLE_OPTION_ATTRIBUTES;

BEGIN
  open cur;
  fetch cur bulk collect into v_tmp_arr;
  close cur;
  for i in 1..v_tmp_arr.count loop
    -- it's better to wrap it into a function which accepts one type of record and returns another one        
    v_criteria_pairs(i).option_name := v_tmp_arr(i).option_name;
    v_criteria_pairs(i).option_value := v_tmp_arr(i).option_value;
    v_criteria_pairs(i).option_selected_ind := v_tmp_arr(i).option_selected_ind;
    v_criteria_pairs(i).option_class := v_tmp_arr(i).option_class;
  end loop;
END;
于 2016-11-07T11:17:27.347 に答える
1

Oracle docによると、「レコード内のすべてのフィールドをデフォルト値に設定するには、同じタイプの初期化されていないレコードをそれに割り当てます」、およびこれはその例です。

DECLARE
   TYPE RecordTyp IS RECORD (field1 NUMBER, 
                         field2 VARCHAR2(32) DEFAULT 'something');
   rec1 RecordTyp;
   rec2 RecordTyp;
BEGIN
-- At first, rec1 has the values you assign.
   rec1.field1 := 100; rec1.field2 := 'something else';
-- Assigning an empty record to rec1
-- resets fields to their default values.
-- Field1 is NULL and field2 is 'something'
-- due to the DEFAULT clause
   rec1 := rec2;
   DBMS_OUTPUT.PUT_LINE
     ('Field1 = ' || NVL(TO_CHAR(rec1.field1),'<NULL>') || ',
      field2 = ' || rec1.field2);
END;
/
于 2016-10-31T13:22:08.020 に答える
0

以下は、PL/SQL レコードではないが同じ動作を持つオブジェクト タイプの別のオプションです。さらに、コンストラクターでデフォルト値を使用して初期化するためのオプションが追加されています (式と PL/SQL 関数を使用します)。

コンストラクターで新しい型を定義します。

CREATE OR REPLACE TYPE RECORD_OPTION_ATTRIBUTES AS OBJECT(
  option_name             VARCHAR2(200),
  option_value            VARCHAR2(200),
  option_selected_ind     NUMBER(1),
  option_class            VARCHAR2(200),
  option_attributes       VARCHAR2(200),
  constructor function RECORD_OPTION_ATTRIBUTES(
    in_option_name             VARCHAR2    DEFAULT 'INVALID NAME"', /* default intentionally breaks HTML */
    in_option_value            VARCHAR2    DEFAULT 'INVALID VALUE"', /* default intentionally breaks HTML */
    in_option_selected_ind     NUMBER      DEFAULT '0',
    in_option_class            VARCHAR2    DEFAULT NULL,
    in_option_attributes       VARCHAR2    DEFAULT NULL
  )
  return self as result
);

コンストラクターではデフォルト値を使用し、複雑な初期化ロジックを使用できます。複数のコンストラクターを持つことができることに注意してください。

create or replace type body RECORD_OPTION_ATTRIBUTES 
as
  constructor function RECORD_OPTION_ATTRIBUTES(
    in_option_name             VARCHAR2    DEFAULT 'INVALID NAME"', /* default intentionally breaks HTML */
    in_option_value            VARCHAR2    DEFAULT 'INVALID VALUE"', /* default intentionally breaks HTML */
    in_option_selected_ind     NUMBER      DEFAULT '0',
    in_option_class            VARCHAR2    DEFAULT NULL,
    in_option_attributes       VARCHAR2    DEFAULT NULL
  )
  return self as result
  as
  begin
    self.option_name         := in_option_name;
    self.option_value        := in_option_value;
    self.option_selected_ind := in_option_selected_ind;
    self.option_class        := in_option_class;
    self.option_attributes   := in_option_attributes;  
    return;
  end;
end;
/  

テストSQLを実行しましょう:

select RECORD_OPTION_ATTRIBUTES(table_name, tablespace_name, ini_trans) 
  from all_tables
 where owner = 'SYS'
   and rownum <= 10;

チェック結果:

RECORD_OPTION_ATTRIBUTES(TABLE_NAME,TABLESPACE_NAME,INI_TRANS)(OPTION_NAME, OPTI
--------------------------------------------------------------------------------
RECORD_OPTION_ATTRIBUTES('WRR$_REPLAY_CALL_FILTER', 'SYSAUX', 1, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('AW$EXPRESS', 'SYSAUX', 4, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('AW$AWMD', 'SYSAUX', 4, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('AW$AWCREATE', 'SYSAUX', 4, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('AW$AWCREATE10G', 'SYSAUX', 4, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('AW$AWXML', 'SYSAUX', 4, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('AW$AWREPORT', 'SYSAUX', 4, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('DUAL', 'SYSTEM', 1, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('SYSTEM_PRIVILEGE_MAP', 'SYSTEM', 1, NULL, NULL)
RECORD_OPTION_ATTRIBUTES('TABLE_PRIVILEGE_MAP', 'SYSTEM', 1, NULL, NULL)

10 rows selected.

ご覧のとおり、最後の 2 列にはデフォルト (この場合は null) 値があります。質問の元の SQL クエリと比較すると、選択した列を RECORD_OPTION_ATTRIBUTES() でラップするだけです。

于 2016-11-08T11:35:42.153 に答える