rink_rewさんの助け合いフォーラム投稿一覧
解説に記載されている以下内容の通りかなと思います。
WHERE句に条件が複数指定されている場合は、論理演算子の優先順位に従って条件が評価されます。
AND演算子とOR演算子ではAND演算子のほうが先に評価されますが、()括弧がある場合は、括弧内の演算子を優先して評価します。
設問では「(department_id = 3 OR salary > 400000)」の部分が先に評価され、次にANDですので、「DEPARTMENT_ID列が3かSALARY列が400000より大きく、かつCOMMISSION列が1200000以下である」列(E)、または、「HIREDATE列が2008年4月1日より大きい(新しい)」列(B,C)が検索されます。
実際に実行すると、確かに「C」のレコードは表示されます。
SQL> select department_id, salary, commission, hiredate from employees where (department_id = 3 or salary > 400000) and commission <= 1200000 or hiredate > '2008-04-01';
DEPARTMENT_ID SALARY COMMISSION HIREDATE
------------- ---------- ---------- --------
3 400000 1200000 02-12-01
5 400000 800000 10-04-01
1 350000 800000 11-04-01
2 300000 800000 10-04-01
3 300000 800000 09-12-01
4 200000 800000 10-04-01 <--- C
~~~ 以下略 ~~~
記載いただいた以下の内容がChatGPTの回答でしょうか。
提供された行が条件にマッチしない理由は、条件 (department_id = 3 OR salary > 400000) AND commission <= 1200000 OR hiredate > '2008-04-01' に対して、以下の評価結果です
department_id = 4 は条件 (department_id = 3 OR salary > 400000) にマッチしません。
salary > 400000 もマッチしません。
commission <= 1200000 もマッチしません。
hiredate > '2008-04-01' もマッチしません。
以上の理由から、提供された行は条件式全体を満たさないため、マッチしません。条件内で指定されている条件に対して、department_id が 4 であることや他の列の値が具体的な値を持っていることは影響しません。
どのようなプロンプトを投げたかわからないので何とも言えませんが、「C」の選択肢は「hiredate > '2008-04-01'」の条件にマッチすると思います。
私も試しにChatGTPに質問してみました。最後の説明文がわかりやすいかなと感じました。
まず、SQLのWHERE句の条件式の評価の順序を理解する必要があります。AND、OR、NOTなどの論理演算子の優先順位は以下のようになっています:
1. NOT
2. AND
3. OR
上記のSQL文において、WHERE句の条件式は以下のように括弧を使って明確に示されています:
1. (department_id = 3 OR salary > 400000)
2. AND commission <= 1200000
3. OR hiredate > '2008-04-01'
この条件式の評価の順序を考慮すると、次のようなステップで評価されます:
1. 最初に括弧内の条件が評価される。すなわち、department_idが3のレコード、またはsalaryが400000を超えるレコードが該当します。
2. 次に、上記の結果の中からcommissionが1200000以下のレコードが選ばれます。
3. 最後に、hiredateが'2008-04-01'よりも新しいレコードが上記の条件に関係なく選ばれます。
そのため、結果として返されるレコードは以下の3つの条件のいずれかを満たすものになります:
1. department_idが3で、salaryが任意、commissionが1200000以下のレコード。
2. salaryが400000を超え、commissionが1200000以下のレコード。
3. hiredateが'2008-04-01'よりも新しいレコード。
注意点として、OR条件はAND条件よりも優先順位が低いため、上記のSQL文を実行すると、hiredateの条件は他の条件とは独立して評価される点に注意してください。
環境構築については、Oracle Master Bronze DBA 2019(1Z0-085)のWeb問題集のトップページに、「環境構築手順のご紹介」というリンクがあるので、その内容に従うと良いかもしれません。
あと、VirtualBox上のLinuxにOracle Database 19cを導入する手順について、とても良くまとまったブログ記事がありましたので、参考までに載せておきます。※記事はLinuxにインストールしてますが、インストールイメージのダウンロードからVMの作成、インストーラーのGUI画面も載っていて、ステップバイステップで書かれているので参考になると思います。
VM作成からのOracle 19cインストール手順 前編(Linuxシングル)
https://cosol.jp/techdb/2021/06/oracle19c_setup_1of2/
VM作成からのOracle 19cインストール手順 後編(Linuxシングル)
https://cosol.jp/techdb/2021/06/oracle19c_setup_2of2/
ちなみに、上記のブログでも言及されていますが、学習目的であれば無償版の「Oracle Database Express Edition」を使用する必要はないようです。(OTNライセンス)
私がOracle Masterを取得したのはもう何年も前の話にはなりますが、
- Oracle Master 教科書(黒本と呼ばれるやつ?)の内容は読み込んでおさえておく。
- Ping-tのWeb問題集は何周もする。解説や参考も面倒くさがらずに読む。
- 黒本やWeb問題集の内容については、可能な限り実機でも動きを確認しておく。
あたりが、自分の学習方法でした。
あと、欲を言えば、黒本やWeb問題集でよく理解できなかった部分などは、Oracleのマニュアルも参照してみるのが良いと思います。
※公式マニュアルは、慣れないうちは読みにくいかもしれませんが、もし将来的に実際の業務でOracle Databaseを使用するようになったら、マニュアルとは嫌でも付き合っていくことになると思うので、その準備も兼ねて慣れておくといいかもしれません。
学習頑張ってください。合格されることを願っております。
「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