rink_rewさんの助け合いフォーラム投稿一覧
「I/O」については、おっしゃられているとおり「インプット/アウトプット」のことです。つまり、データの読み込み/書き込みを指しています。
この問題の解説や参考に以下の記述があります。
データ・ブロックには通常複数の行データが格納されているため、1行にアクセスしたい場合でも、データ・ブロックに含まれるすべての行データがロードの対象となります。
「I/Oの最小単位」ですので、Oracle Databaseがレコードの読み込みや書き込みを行う際には、データブロック単位で処理をしている、例えば、クライアントから「一行のレコードのみを結果として返すようなSELECT文」が投げられた場合でも、Oracle Databaseは「そのレコードが格納されているデータブロック」を丸ごと読みこみ(つまり複数のレコードを読み込んでいる)、その中の一行だけをクライアントに返すような動きをしています。
※正確にはキャッシュや書き込み遅延の話などがあり、ツッコミどころがあるかもしれませんが、大まかにいえばこういうことです。
すみません、疑問に思われている点に対する回答になっていないかもしれません。
ping-tさん提供の検証用データに基づいて、順をおって動きを見てみるとこんな感じでしょうか。
SELECT e.employee_name FROM employees e WHERE EXISTS (SELECT * FROM employees m WHERE e.manager_id = m.employee_id);
- employees e の1行を取得
EMPLOYEE_ID EMPLOYEE_NAME MANAGER_ID
----------- ------------------------------ ----------
1001 山田二郎
- 副問合せの条件は「e.manager_id = m.employee_id」なので、副問合せで参照している employees m 表から、m.employee_id と e.manager_id が等しい行を取得する。
- 上の 1. で employees e から取得した山田二郎の manager_id は null。
- 副問合せで参照している employees m 表の m.employee_id と一致する行がない。
-> 副問合せから行が返されないので、主問合せの EXISTS 条件は FALSE。この行の e.employee_name は返されない。(出力されない)
- employees e の他の1行を取得
EMPLOYEE_ID EMPLOYEE_NAME MANAGER_ID
----------- ------------------------------ ----------
1008 中山大輔 1001
- 副問合せの条件は「e.manager_id = m.employee_id」なので、副問合せで参照している employees m 表から、m.employee_id と e.manager_id が等しい行を取得する。
- 上の 3. で employees e から取得した中山大輔の manager_id は 1001。
- 副問合せで参照している employees m 表の m.employee_id と一致する行(山田二郎)がある。
-> 副問合せから行が返されるので、主問合せの EXISTS 条件は TRUE。この行の e.employee_name は返される。(出力される)
=> 結果として、employees 表 の manager_id 列に、同表内に存在する employee_id の値を持つ行(上司のいる従業員)が返される。
SELECT m.employee_name FROM employees m WHERE EXISTS (SELECT * FROM employees e WHERE e.manager_id = m.employee_id);
- employees m の1行を取得
EMPLOYEE_ID EMPLOYEE_NAME MANAGER_ID
----------- ------------------------------ ----------
1001 山田二郎
- 副問合せの条件は「e.manager_id = m.employee_id」なので、副問合せで参照している employees e 表から、m.employee_id と e.manager_id が等しい行を取得する。
- 上の 1. で employees m から取得した山田二郎の employee_id は 1001。
- 副問合せで参照している employees e 表の e.manager_id と一致する行(中山大輔、米村真司、等)がある
-> 副問合せから行が返されるので、主問合せの EXISTS 条件は TRUE。この行の m.employee_name は返される。(出力される)
- employees e の他の1行を取得
EMPLOYEE_ID EMPLOYEE_NAME MANAGER_ID
----------- ------------------------------ ----------
1008 中山大輔 1001
- 副問合せの条件は「e.manager_id = m.employee_id」なので、副問合せで参照している employees m 表から、m.employee_id と e.manager_id が等しい行を取得する。
- 上の 3. で employees e から取得した中山大輔の employee_id は 1008。
- 副問合せで参照している employees e 表の e.manager_id と一致する行がない。
-> 副問合せから行が返されないので、主問合せの EXISTS 条件は FALSE。この行の m.employee_name は返されない。(出力されない)
=> 結果として、employees 表の manager_id 列に存在する値を、employee_id 列の値として持つ行(部下を持つ従業員(上司))が返される。
セッションというのは各ユーザーがオラクルにアクセスするたびにそれぞれのセッションが作成されるイメージを持っています。←あっているでしょうか?
はい。その認識で良いと思います。
sqlplusなどを使用して対話的にアクセスしている状況ならば「各ユーザ」と呼べますし、開発した複数のアプリケーションからのアクセスであれば「各アプリケーション」とも呼べると思います。
もし、セッションが各ユーザがオラクルにアクセスするたびに作成されるのであれば、上記セッションは終了しておらず他のセッションからTEMP表を参照するとデータが1件表示されるのではないか?
ご認識の通り、セッションは終了していないと考えられます。終了しているのは「トランザクション」のみです。テーブル定義時に「ON COMMIT PRESERVE ROWS」を指定しているので、トランザクション終了後もデータを参照できています。(解説の実行例の通り)
この設問でのポイントは、「一時表のデータはあくまでもセッション内でのみ参照可能である」という点だと思います。他のセッションからは「表の構造」は参照できますが(解説の画像でいうところのDESC)、「データ」は参照できません(解説の画像でいうところのSELECT文の結果)。
一つのコマンドプロンプト(Linuxやmacであればターミナル等)を立ち上げて設問で提示されているSQLを実行後、同じコマンドプロンプト上から(同じセッション内からの意)はCOMMIT後も挿入したデータが参照できます。
もう一つ別のコマンドプロンプトを立ち上げて「temp」表に対してSELECT文を実行しても、データは参照できません。これは、前のコマンドプロンプトにおける最後の「COMMIT;」の前でも後でも同様です。
このことから「他のセッションからTEMP表を参照すると、データは0件である」が正答であると導き出せると思います。
問題文の冒頭に「EMPLOYEE_ID列にはPRIMARY KEY制約だけが定義されています」とあるので、画像の「NOT NULL」は、明示的に付与したNOT NULL制約というわけではなく、PRIMARY KEY制約を付与した際に暗黙的に作成されたものだと判断できると思います。
運営さんに修正してもらうとしたら、明示的か暗黙的かを明記してもらうぐらいでしょうか。
実際の試験において、どの程度明確な問題文が提示されるかはわかりませんが...。
ユーザーAが発行したFOR UPDATE WAIT 10はユーザーAの前の処理に対して働いていると考えますがあっているでしょうか?
そうですね。
①のSELECT文で「FOR UPDATE」を用いてロックを取得しようとしていますが、競合するトランザクションがすでにある場合には待たされます。「WAIT 10」は競合するトランザクションがすでにあった場合に「10秒までは待つ」という意味で、10秒経過するとエラーが返ります。
この設問では、①の前に何かトランザクションがあるか否かといった情報は特に提示されていないので、ロックを取得できると考えられます。
また、解説③にはユーザーAがかけた排他ロックが解除されるまで待機するとありますが、これはユーザーBのSQL文でUPDATE prod SET name = 'Chopin' WHERE prodid = 2 の後に FOR UPDATE WAIT がありませんがデフォルトでそのような挙動になるのでしょうか?
FOR UPDATE句はSELECT文で使用できる句です。UPDATE文ではそもそもロックを取得するので、FOR UPDATE句はありません。(「SELECT ... FOR UPDATE」文としてひと塊りで覚えてしまった方がわかりやすいかもしれません)
参考: DML操作での自動ロック
https://docs.oracle.com/cd/F19136_01/sqlrf/Automatic-Locks-in-DML-Operations.html#GUID-3D57596F-8B73-4C80-8F4D-79A12F781EFD
私は同じ状況になったことはないのですが、試しに今PCからログインしてみましたところ、特に問題なくログインできました。
ログインできないとのことですが、何かエラーなど出ている場合には、Oracle側に問い合わせをしてみた方が早いかもしれませんね。
https://www.oracle.com/jp/education/certification/migration-to-certview.html#Contact
ここの、「オラクル認定資格事務局(oraclecert_jp@oracle.com)」でしょうか。
例として挙げておられるデータで実際に試してみました。
INTERSECTは積をとり、重複行は含まれないのでこのような結果となるようです。
SQL> select * from test_prod;
PROD_ID PROD_NAME
---------- -----------
1001 Alpha
1001 Blavo
1001 Charlie
1002 Delta
SQL> select * from test_sales;
PROD_ID CUST_ID
---------- ----------
1001 2001
1001 2002
1001 2003
1002 2004
SQL> select prod_id from test_prod intersect select prod_id from test_sales;
PROD_ID
----------
1001
1002
SQL> select distinct prod_id from test_prod p join test_sales s using(prod_id);
PROD_ID
----------
1001
1002
SQL>
こういうことでしょうか。
SQL> select * from emp;
EMP_ID EMP_NAME SAL
---------- ---------- ----------
1001 aaa 100000
1002 bbb 200000
SQL> create view emp_view_check as select * from emp where sal = 200000 with check option;
ビューが作成されました。
SQL> select * from emp_view_check;
EMP_ID EMP_NAME SAL
---------- ---------- ----------
1002 bbb 200000
SQL> delete from emp_view_check where emp_id = 1001;
0行が削除されました。
SQL> delete from emp_view_check where emp_id = 1002;
1行が削除されました。
SQL> select * from emp;
EMP_ID EMP_NAME SAL
---------- ---------- ----------
1001 aaa 100000
SQL>
作成したビューを通して元表のデータを削除する場合、そのビューに含まれるレコードは作成時の条件を満たす(with check optionのチェックを通っている)ものだけなので、もしdelete文の対象とするレコードがビューの作成条件を満たしていないのならば、そのビューからはそもそも見えていないデータだと思います。
このようなdelete文においては、上記の実行例によれば、delete文自体はエラーにはならないが、実際には何も削除されないようです。
解説に
①数値→文字への暗黙的な型変換が出来る
②文字→数値への暗黙的な型変換は出来ない
解説のどの部分でしょうか?最後に記述されている以下の文章でしょうか。
また、2つ目のSQL文では、第3引数には数値データ(salary)が指定されており、その後、2つ目の戻り値として文字データ('-')が指定されています。'-'は暗黙的データ変換で数値データへ変換できないため、このSQL文もエラーとなります。
もしこの文章のことであれば、「文字→数値への暗黙的な型変換は出来ない」とは書かれておらず、「'-'は暗黙的データ変換で数値データへ変換できない」なので、'-' が数値データへの変換ができないという意味かなと思いました。
※例えば、'abc'のような文字列の場合、数値に変換しようがない。'-'も同様に数値に変換しようがない。'100'のような文字列であれば、Oracleは数値の 100 に暗黙的に変換できる。
Engineer1993 さんが仰っている通り、私も「文字→数値の暗黙的な型変換もできる」という理解ですが、あくまでもその変換が意味を持つ場合という認識です。
参考までに、マニュアルの暗黙的なデータ変換に関する部分に以下の記述がありました。
https://docs.oracle.com/cd/E16338_01/server.112/b56299/sql_elements002.htm#i46862
暗黙的なデータ変換
あるデータ型から別のデータ型への変換が意味を持つ場合、Oracle Databaseは値を自動的に変換します。
的外れな意見となっていましたらごめんなさい。
「NOMOUNT状態の時に読み込まれる」を「NOMOUNT状態の時に『MOUNT状態に遷移するために次に』読み込まれる」と捉えるか、「NOMOUNT状態の時に『既に』読み込まれている」と捉えるかという感じでしょうか。前者だと正解は「制御ファイル」、後者だと「初期化パラメータ・ファイル」ですが、ちょっと問題の表現が曖昧なような気もします。
設問の選択肢は「データベースがNOMOUNT状態の時に読み込まれる」ですが、「NOMOUNT状態の時」という時点においては、既に「初期化パラメータ・ファイル」は読み込み済みと判断して良いと思います。しかし、次に「制御ファイル」を読み込むとは限りませんし(startup nomountで起動しただけかもしれない)、startup openを実行した前提のような表現になってしまっているような気もします。
「NOMOUNTに遷移する時に読み込まれる」や「マウントする際に読み込まれる」のような表現なら勘違いしなくて済みそうですが、本試験で前述のような表現が出てくると迷ってしまいそうですね...。
問題の以下の解説にも記載されているように、結合列に表接頭辞を使用することはできないので、正答とされているクエリで正しいと思います。
USING句を指定した結合では、結合列に表接頭辞を使用することはできません。SELECT句やORDER BY句に指定されたDEPARTMENT_ID列に表接頭辞が指定されているためエラーとなります。
Ping-tさんのこちらの問題集には検証環境準備用のスクリプトが提供されているので、そちらを利用して正答のクエリを実際に実行してみましたがエラーは発生しませんでした。
参考:
https://docs.oracle.com/cd/F19136_01/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6