PL/SQLの勉強8 データを1件だけ取得する

2022-10-20

PL/SQLでプログラムを組んでいると
データを1件だけ取得して変数に持ちたいな〜
なんて思うことがあります。

そんな時はどうやるのか…

今回はそれをやっていきましょう。

まずはサンプルのデータを用意

そんなのいらないよ!
と言う方は、次に行ってくださいw

こんな感じのデータを用意しますよ。

IDNAME
1太郎
2花子
3光宙

以下のDDL・DMLを全部コピーして
Oracle Live SQLに貼り付け・実行すれば
自分で試すためのデータは用意できますよ♪

create table COMMON_MST
(
  ID   number
 ,NAME varchar2(4000)
 ,constraint PK_COMMON_MST primary key (ID)
)
;

insert into COMMON_MST values (1, '太郎');
insert into COMMON_MST values (2, '花子');
insert into COMMON_MST values (3, '光宙');

commit;

試しにちゃんとデータが入っているか
確認してみましょう。

select
*
from COMMON_MST
;

大丈夫そうですね!
これでデータの準備はOKです。

データを1件だけ取得

まずは結論をば。。。
こんな感じに書きますよ!

declare
  v_name  varchar2(4000);
begin
  
  select
    NAME
  into
    v_name
  from COMMON_MST
  where ID = 1
  ;
  
  dbms_output.put_line('取得した名前 : ' || v_name);
  
end;

実行結果はこんな感じになるはずです。

「太郎」が取得できていますね!

詳しく見ていきましょう。

普通のSELECT文ではないですね。
7行目に「into」があります!

人がテーブルからデータを取得するときは
「どんなデータが入っているの?」
って見るだけですが

プログラムがデータを取得するときは
「そのデータを変数に持って、その後で何かに使う!」
となるはずです。

何かに使うためにデータを取得したんでしょ?
それを後で使うために、変数に保持しておかないと!

…という感じ♪

ちなみに…
変数に持たないでSELECTするだけ!
なんてことは出来ません。
エラーになります。

エラーメッセージを見ると
「SELECTするときはINTOが必要だよ!」
って言われてますね。

もっとプログラムの堅牢化を目指した形

例えば以下のプログラムを書いてしまうと、エラーになります。

declare
  v_name  varchar2(1);
begin
  
  select
    NAME
  into
    v_name
  from COMMON_MST
  where ID = 1
  ;
  
  dbms_output.put_line('取得した名前 : ' || v_name);
  
end;

「character string buffer too small」
って書いてありますね。

2行目の変数を定義するところで
「varchar2(1)」と書いている。。。

つまり、変数は1byteまでしか入れられないのに
「太郎」という文字を入れようとして
そんなに大きいデータは入らないよ〜!と言われているんです。

何byteか考えながら変数を定義しないといけないの?
めんどくせー!!

と思う方、センスあります!
簡単な方法があるんです!

declare
  v_name  COMMON_MST.NAME%type;
begin
  
  select
    NAME
  into
    v_name
  from COMMON_MST
  where ID = 1
  ;
  
  dbms_output.put_line('取得した名前 : ' || v_name);
  
end;

結果は上と同じで「太郎」が取得できます。

注目すべきは2行目!
「COMMON_MST.NAME%type;」と書いてますね。

COMMON_MSTというテーブルの
NAMEというカラムの
type、つまり定義を使うよ!

と言っています。

これを使えば
テーブル定義とかあまり考えなくても
プログラム書けちゃいますね♪

一気に複数カラムのデータを取得

あくまでも「このやり方は」
1行のデータしか取得できません。

けど1行であれば
複数カラムの取得は可能です!

こんな感じに書けますよ。

declare
  v_id    COMMON_MST.ID%type;
  v_name  COMMON_MST.NAME%type;
begin
  
  select
    ID
   ,NAME
  into
    v_id
   ,v_name
  from COMMON_MST
  where ID = 1
  ;
  
  dbms_output.put_line('取得したID:' || v_id || ', 名前 : ' || v_name);
  
end;

名前だけじゃなくてIDも追加してみました。

結果はこんな感じです。

ちゃんと取れてますね!

「v_id」という変数も
どんなデータ型なのか考えないでも書けちゃいます♪

変数をいくつも書くのが面倒な人は…

こんな書き方も出来ますよ!

declare
  v_common_mst  COMMON_MST%rowtype;
begin
  
  select
  *
  into
    v_common_mst
  from COMMON_MST
  where ID = 1
  ;
  
  dbms_output.put_line('取得したID:' || v_common_mst.ID || ', 名前 : ' || v_common_mst.NAME);
  
end;

注目するのは2行目。
今までは「<テーブル名>.<カラム名>%type」だったのが
今回は「<テーブル名>%rowtype」ってなってますね!

SELECTではカラム名を書かないで「*」としています。

データを使う(出力)する時には
「v_common_mst.ID」とか「v_common_mst.NAME」
ってしています。

ID・NAMEはテーブルのカラムに該当します。

こういうやり方はありますが
僕は実際には使ったことないです。

後で見た時 or 他の誰かがこれを見た時、
「このテーブルにはどんなカラムがあるの?」
が一目では分からないからです。

いちいちテーブル定義を見に行くのが面倒!!

この地味な一手間が積み重なると
読みにくいプログラムが出来上がるのです。。。

なので、100歩譲ってこんな感じに書くとしたら…
こうでしょうか。

declare
  v_common_mst  COMMON_MST%rowtype;
begin
  
  select
    ID
   ,NAME
  into
    v_common_mst
  from COMMON_MST
  where ID = 1
  ;
  
  dbms_output.put_line('取得したID:' || v_common_mst.ID || ', 名前 : ' || v_common_mst.NAME);
  
end;

6行目が「*」から
ID・NAMEって変わってるだけですが
「どんなテーブル定義なの?」
という苦痛は解消されます。

ただし注意が必要です!

この書き方、SELECT句のカラムは
テーブル定義通りに・同じ順番で書く必要があります。
じゃないとエラーになります。

エラーに注意してね!

「1件だけ取得する方法」
としてやっていますが、
ちょっと間違えるとエラーとなってしまいます。

なので注意してね!
というお話もしておこうと思います。

複数の行を取得しようとするとエラーになるよ

複数のデータを取得しようとした場合…
こうなります。

declare
  v_id    COMMON_MST.ID%type;
  v_name  COMMON_MST.NAME%type;
begin
  
  select
    ID
   ,NAME
  into
    v_id
   ,v_name
  from COMMON_MST
  where ID > 1
  ;
  
  dbms_output.put_line('取得したID:' || v_id || ', 名前 : ' || v_name);
  
end;

WHERE句が「1より大きい」ってなってます。
この場合、結果は2行返ってきます。

エラーになってしまいましたね!

こうならないために、プログラムを書くときは
必ず1件しか取得できないことを担保するべきです。

どうやって担保するか…?

簡単です。
テーブル定義でprimary key(主キー)って
なっていることを確認
すればいいんです!

0件でもエラーになるよ

SELECTした結果が0件でもエラーになります。

IDが4のデータは無いので
データは取得できません。

こちらも注意が必要ですね!

結局、僕はどう書くのか?

僕だったらこう書きます。
これ1択です!

declare
  v_id    COMMON_MST.ID%type;
  v_name  COMMON_MST.NAME%type;
begin
  
  select
    ID
   ,NAME
  into
    v_id
   ,v_name
  from COMMON_MST
  where ID = 1
  ;
  
  dbms_output.put_line('取得したID:' || v_id || ', 名前 : ' || v_name);
  
end;

以上ですw

1行だけデータを取得する場合について
やっていきました。

ちょっと注意する点はありますが
実際に仕事する際にも使える手法です。

「とあるテーブルに固定値が入っている
ので、それを取得したい!」

って時によく使います。

次回は、複数データを取得する場合…
についてやっていきます!

PL/SQL

Posted by kiri