rink_rewさんの助け合いフォーラム投稿一覧
この問題の場合は、外部キーにユニーク制約が設定されているため、NULLを格納することも可能です。
解説のこの文章は、参照先のテーブルのカラムには「主キー制約」または「ユニーク制約」が設定されている必要がある、という外部キー制約作成時の条件が前提になっていると思います。(参考: 問題ID35376)
- 外部キー作成時には、参照先のテーブルのカラムに「主キー制約」または「ユニークキー制約」が必要
↓ - この問題では、参照先のテーブルのカラムに「ユニーク制約」が設定されている
↓ - 従って、「customer」テーブルの「addressid」カラムに対して、NULLを格納することも可能
ただ、この問題の解説の文章だけ読むと、もう少し補足があっても良いかなと感じますね。
・セグメントは連続した複数のエクステントで構成される
エクステントは連続した領域に確保されるとは限りません。
この説明文の言いたいことは、「セグメントを構成するエクステントは、連続した領域に確保されるとは限らない」、ということですよね。
※「参考」の以下記述の部分
表領域に複数のデータファイルが割り当てられている場合は、セグメントを構成する個々のエクステントが異なるデータファイル上に格納される場合もあります。つまり、1つのセグメントが複数のデータファイルにまたがる場合もあります。
ですが、この問題の解説の文章だと、若干モヤっとしますね。少し表現を変えてもらえると良さそうですが...。
recovery.conf は PostgreSQL 12で廃止され、postgresql.conf に統合されたようです。
https://www.postgresql.jp/document/14/html/recovery-config.html
本問題の解説にも以下の記載がありました。
PostgreSQL 11 以前のバージョンでは、リカバリに関する設定を「recovery.conf」というファイルを作成して記述していましたが、これらの設定は PostgreSQL 12 から「postgresql.conf」ファイルに統合されました。
OSS-DB Silver Ver.3.0 は PostgreSQL 12 以上を基準としているので、postgresql.conf を用いるという説明は妥当かなと思います。
https://oss-db.jp/outline/silver
この問題の解説に記載のとおり、GENERATED ALWAYS AS IDENTITYが指定されているid列に明示的に値を指定したUPDATEやINSERTはエラーになるので、name=Suzukiのレコードのid列は変更されませんし(3番目のSQL)、id列に3を指定したレコードも追加されない(4番目のSQL)、結果、1番目のSQLと2番目のSQLで挿入された2レコードだけがそのまま残る、ということではないですか?
質問の意図が理解できていなかったらすみません。
下記のDESCの後に表示されている「1」は何をあらわしているのでしょうか。
これは、ORDER BY 句における項目の指定方法で、列名や列別名以外に、SELECT句で指定した項目の順番を数値で指定することができるというものです。
DESCの後の数字というか、DESCはその前の数字にかかっています。
SELECT employee_name, salary, grade FROM employees, grade
WHERE salary = (SELECT MAX(salary) FROM employees)
AND salary BETWEEN low AND high
ORDER BY 3, 2 DESC, 1
この例だと、まず最初に「3」(grade)で昇順にソート、次に「2」(salary)で降順にソート、最後に「1」(employee_name)で昇順にソート、という動きになります。
※ORDER BY句のデフォルトが昇順で、ASCは省略可能、降順にしたい場合はDESCを指定する。
ORDER BY句に着目した別の問題(26443)に、以下の説明がありました。
ORDER BY句の項目には「列名」の他、以下を指定できます。どれも重要です。
・列別名(*WHERE句では指定不可)
・算術式
・SELECT句に指定されている項目の順番(数値)
ASCとDESCは昇順/降順を指定するキーワードです。ASCで昇順(小さい順)、DESCで降順(大きい順)にソートします。省略するとASCが指定されたものとみなされます。
ORDER BY句では複数の項目を指定できますが、ASC/DESCも項目ごとに指定できます。
何件表示されるかとの問いに対し、
問題文で「何件表示されるか」とは書かれてないですね。
問題文は「以下のSQLを実行した場合、取得されるデータとして正しいものは?」と書かれていて、countの結果5件のデータが取得されているので、選択肢として「5件」で良いのではないでしょうか。
もし、「以下のSQLを実行した場合、出力される値は?」のような問題文であれば、選択肢は「5」のように「件」がついていない方が適切だと思いますが。
少し古い情報にはなりますが、私が受験した際にはテストセンターで受付済ませて試験を受ける部屋に入室する前に、厚紙をラミネートしたようなペラペラのホワイトボード代わりのシートと黒のマーカーが配布されました。
他の設問ですが26677の参考のNULLIF関数の説明部分に以下の記載がありました。
なお、第1引数にはリテラルのNULL値以外の値を指定しなければなりません。
上記のように第1引数にリテラルのNULL値は指定できませんが、第1引数で指定した列の値などが結果としてNULL値となる場合は問題ありません。
第1引数が結果としてNULL値となる場合は、第2引数がいかなる値であっても、NULL値が返されます。(第2引数がNULL値であれば等しいのでNULL値、第2引数がNULL値以外であれば等しくないので第1引数のNULL値が返される為)
実際にsalary列にnullが含まれるデータで、選択肢のSQLを実行した場合エラーにはなりません。
NULLIF関数の結果としてnullが返され、DECODE関数の条件と一致して、結果、「-」として表示されます。
SQL> select employee_id, employee_name, salary from employees where salary is NULL;
EMPLOYEE_ID EMPLOYEE_NAME SALARY
----------- -------------------- ----------
1017 渡辺和也
1018 塚本孝
1019 野口圭子
SQL> select employee_id, employee_name, NULLIF(salary, 500000) from employees where salary is NULL;
EMPLOYEE_ID EMPLOYEE_NAME NULLIF(SALARY,500000)
----------- -------------------- ---------------------
1017 渡辺和也
1018 塚本孝
1019 野口圭子
SQL> SELECT employee_id, employee_name, DECODE(NULLIF(salary, 500000), NULL, '-', salary) sal FROM employees;
EMPLOYEE_ID EMPLOYEE_NAME SAL
----------- -------------------- -------------------------
1001 山田二郎 -
1002 佐藤昭夫 -
1003 山口洋子 -
1004 田中浩介 -
1005 加藤昭彦 -
1006 佐々木明子 800000
1007 菊池浩二 800000
1008 中山大輔 400000
1009 星野健一 400000
1010 斎藤京子 400000
1011 吉田亜希 400000
1012 阿部伊吹 400000
1013 米村真司 350000
1014 伊藤佳奈 300000
1015 橋本淳 300000
1016 井上悦子 200000
1017 渡辺和也 -
1018 塚本孝 -
1019 野口圭子 -
1020 内田雄介 200000
1021 高田明 200000
1022 坂本真 200000
22行が選択されました。
このSQL文自体には特段問題はなく、言語環境の問題だと思います。
私はUTF8環境ですが、解説と同じ出力結果でした。
※検証用データの提供ページに「DBのキャラクタセットは「Unicode(AL32UTF8)」を想定」と記載されていたのでそれに従っていました。
問題文の冒頭で「実行環境は日本語とする」と言及しているのは、通貨記号「¥」が含まれているからですかね。
SQL> !echo $NLS_LANG
Japanese_Japan.AL32UTF8
SQL> select parameter, value from NLS_DATABASE_PARAMETERS where parameter = 'NLS_CHARACTERSET';
PARAMETER VALUE
-------------------- --------------------
NLS_CHARACTERSET AL32UTF8
SQL> SELECT TO_NUMBER('¥500,000.0', 'L999G999D0') FROM dual;
TO_NUMBER('¥500,000.0','L999G999D0')
------------------------------------
500000
試しに英語に変えてみると、ORA-01722のエラー(「数値が無効です」のエラー)が発生しました。
通過記号「¥」が一致しなくなるためだと思います。
SQL> !echo $NLS_LANG
American_America.WE8MSWIN1252
SQL> SELECT TO_NUMBER('¥500,000.0', 'L999G999D0') FROM dual;
SELECT TO_NUMBER('¥500,000.0', 'L999G999D0') FROM dual
*
ERROR at line 1:
ORA-01722: invalid number
余談ですが、「$」などとすればエラーは発生しません。
SQL> !echo $NLS_LANG
American_America.WE8MSWIN1252
SQL> SELECT TO_NUMBER('$500,000.0', 'L999G999D0') FROM dual;
TO_NUMBER('$500,000.0','L999G999D0')
------------------------------------
500000
すでに実際に試されているとおり、自己結合の場合にUSING句を使用してもエラーにはなりませんよね。
・USING句に結合条件を指定する
USING句は同じ名前の列のみを結合することができます。自己結合の実行例のように結合列に表接頭辞(表別名)を使用できないので、誤りです。
おそらくこの解説文で言いたいのは、USING句を用いる場合で「結合条件としての結合列に表接頭辞(表別名)を使用できない」ということだと思いますが、自己結合のクエリでUSING句に結合条件を指定する(表接頭辞を含まない列名を指定する)こと自体は不可能ではないので、この問題の選択肢として「USING句に結合条件を指定する」が「正しくない」とは言えないですよね。問題の修正をお願いしたいところです。
SQL> SELECT emp.employee_name, mgr.employee_name FROM employees emp JOIN employees mgr USING(emp.manager_id);
SELECT emp.employee_name, mgr.employee_name FROM employees emp JOIN employees mgr USING(emp.manager_id)
*
行1でエラーが発生しました。:
ORA-01748: ここでは修飾された列名は使用できません。
これは、上司の人はmanager_idを持たず、上司のいる従業員のmanager_id列に上司のemployee_idが入るという認識で合ってますでしょうか。
そうですね。その理解で良いと思います。
前提として「manager_id列に値が入っているレコードは、上司がいることを意味する」と判断しておく必要はありますが、実際の表データは見なくても問題は解けるかなと思います。
以下の2つの選択肢は構文エラーになるので除外。
・SELECT emp.employee_name, mgr.employee_name FROM employees emp NATURAL JOIN employees mgr;
・SELECT employee_name, mgr.employee_name FROM employees JOIN employees mgr ON manager_id = mgr.employee_id;
以下の選択肢は、同じ名前が表示されるだけなので、期待する結果(従業員名とその上司の氏名)にはならないと判断できる。
・SELECT emp.employee_name, mgr.employee_name FROM employees emp JOIN employees mgr USING (employee_id);
そして残りの2つについては、manager_id列に値を持つemployee_nameと、そのmanger_idに該当するemployee_nameが表示されるので、本設問で期待されている「従業員名とその上司の氏名」(と思われるもの)が表示されるので正答である、と判断はできないことはないかなと思いました。
・SELECT emp.employee_name, mgr.employee_name FROM employees emp, employees mgr WHERE emp.manager_id = mgr.employee_id;
・SELECT emp.employee_name, mgr.employee_name FROM employees emp JOIN employees mgr ON emp.manager_id = mgr.employee_id;
もし、運営さんに修正してもらうとしたら、「manager_id列に値が入ってるレコードは、その従業員に上司がいることを意味する」のような補足を問題文に追記してもらうぐらいでしょうか。
実際のSilver SQL 2019の試験問題で、どのような出題がされるかはなんとも言えないところですが...。
②は理由が分かりませんでした
(¥を記載したため?,文字として¥を記載するのはエラーにならないと思ったのですが…)
そうですね。第一引数の文字列として¥が含まれていること自体は問題ないので、エラーにもなりませんが、出力結果は期待したものにはなりません。
実際に実行してみると、出力結果は以下のとおり「500000」が出力されます。
TO_NUMBERはNUMBERに変換するので、出力結果として桁区切りのカンマや通貨記号は含まれません。
※第二引数で指定したフォーマットは、第一引数の文字列を数値に変換するにあたり、どう解釈すれば良いかの指定。
SQL> SELECT TO_NUMBER('¥500,000.0', 'L999G999D0') FROM dual;
TO_NUMBER('¥500,000.0','L999G999D0')
------------------------------------
500000
下記問題が×である理由の説明が記載されていないため、ご教授いただきたいです
Ping-tさんの問題集はたいてい不正解の選択肢についても説明が載ってるような気がするのですが、確かにこの問題にはないですね...なんででしょう...。
コミットだけでは飛ばされないと思います。共有プールがクリアされたりすれば、欠番が発生することになると思いますが。
SQL> create sequence seq01 cache 20;
順序が作成されました。
SQL> select seq01.nextval from dual;
NEXTVAL
----------
1
SQL> select sequence_name, last_number from dba_sequences where sequence_name = 'SEQ01';
SEQUENCE_NAME LAST_NUMBER
-------------------- -----------
SEQ01 21
SQL> select seq01.nextval from dual;
NEXTVAL
----------
2
SQL> commit;
コミットが完了しました。
SQL> select seq01.nextval from dual;
NEXTVAL
----------
3
SQL>
''(空文字/長さ0の文字値)はNULLとして扱われるので、
- =での比較はできない (結果がUNKNOWNとなる)
- NULLを検索したければ、IS NULL / IS NOT NULL を使用しなければならない。
ということですね。「WHERE yomi = ''」では、NULLを=で検索することになります。
確かにOracleのNULLの扱いはクセがあると言えるかもしれませんが、参考URLに記載のマニュアルに以下のとおり記載されてますので。
NULLを検査するには、比較条件IS NULLおよびIS NOT NULLのみを使用します。NULLを他の条件で使用して、その結果がNULLの値に依存する場合、結果はUNKNOWNになります。
SELECT文のWHERE句でUNKNOWNと評価される条件が使用された場合、その問合せに対して行は戻されません。
成立しますね。SELECT文のとおり、並び替えられた上で上位15%(この問題の例であれば4行)が返されます。
ping-tさん提供のサンプルデータで、salaryの85%をnullにして試した結果は以下のとおりです。
SQL> SELECT employee_id, employee_name, salary FROM employees ORDER BY salary DESC NULLS LAST;
EMPLOYEE_ID EMPLOYEE_NAME SALARY
----------- ------------------------------ ----------
1003 山口洋子 500000
1002 佐藤昭夫 500000
1001 山田二郎 500000
1007 菊池浩二
1008 中山大輔
1009 星野健一
(中略)
22行が選択されました。
SQL> SELECT employee_id, employee_name, salary FROM employees ORDER BY salary DESC NULLS LAST FETCH FIRST 15 PERCENT ROWS ONLY;
EMPLOYEE_ID EMPLOYEE_NAME SALARY
----------- ------------------------------ ----------
1003 山口洋子 500000
1002 佐藤昭夫 500000
1001 山田二郎 500000
1007 菊池浩二
RPADやLPADの第2引数は「表示される全体の長さ」で、第1引数の文字列の長さが第2引数で指定された長さよりも長い場合には、第2引数で指定された長さまでのみ表示され、残りは切り捨てられます。
SUBSTR(cust_postal_code, INSTR(cust_postal_code, '-'))
→ 「-0063」※長さ 5
LENGTH(cust_postal_code) - INSTR(cust_postal_code, '-')
→ 8 - 4 = 4
第一引数の文字列の長さ「5」、第2引数で指定された長さ「4」で、第一引数の方が長いため、RPADの結果は長さ4まで(「-0063」のうち「-006」まで)が表示されることになります。
参考URLのマニュアルだと、以下の部分ですね。
expr1がnより長い場合、このファンクションはnに収まるexpr1の一部を戻します。
あと、この問題の解説には書いてなかったのですが、他の問題(ID:26812)の解説に以下の記述がありました。
RPAD関数やLPAD関数の引数に指定された文字列が、長さで指定されたサイズよりも長い場合、次のように指定されたサイズ分の文字列が表示されます。
ping-tさん提供の検証用データがあります。スクリプト形式で提供されているので、問題集で実行されているSQLはすぐに試せますよ。
https://ping-t.notion.site/Ping-t-Silver-SQL-6f833fb434994343bcc338233e058bb2
本件も、実際に実行してみれば一発でわかります。
SQL> CREATE SEQUENCE seq_id MAXVALUE 100;
順序が作成されました。
SQL> CREATE TABLE list (id NUMBER(3) DEFAULT seq_id.NEXTVAL PRIMARY KEY, name VARCHAR2(10));
表が作成されました。
SQL> GRANT SELECT, INSERT ON list TO userA;
権限付与が成功しました。
SQL> conn userA
パスワードを入力してください:
接続されました。
SQL> SELECT * FROM pingt.list;
レコードが選択されませんでした。
SQL> INSERT INTO pingt.list (name) VALUES ('Sato');
INSERT INTO pingt.list (name) VALUES ('Sato')
*
行1でエラーが発生しました。:
ORA-01031: 権限が不足しています
SQL> conn pingt
パスワードを入力してください:
接続されました。
SQL> GRANT SELECT ON pingt.SEQ_ID to userA;
権限付与が成功しました。
SQL> conn userA
パスワードを入力してください:
接続されました。
SQL> INSERT INTO pingt.list (name) VALUES ('Sato');
1行が作成されました。
SQL> SELECT * FROM pingt.list;
ID NAME
---------- ----------
1 Sato
SQL>
同じ結果になります。実務的には、時なら1/24、分なら1/1440の表記を使うことが多いような気がします。パッと見て分かりやすいので。
SQL> select to_date('12-01-01') from dual;
TO_DATE('12-01-01
-----------------
12-01-01 00:00:00
SQL> select to_date('12-01-01') +12/24 from dual;
TO_DATE('12-01-01
-----------------
12-01-01 12:00:00
SQL> select to_date('12-01-01') +1/2 from dual;
TO_DATE('12-01-01
-----------------
12-01-01 12:00:00
過去にも同じ質問があったようです。
https://mondai.ping-t.com/g/posts/603
INSERT時は範囲外の値をセットすると「範囲外の値は入力できない(エラー)」となりますが、UPDATE時は更新指示自体がエラーになるのではなく「処理を実行した結果0件でした」となるのだよ、という違いですね。_
ちなみに、ping-tさん提供のテストデータで実際に実行してみた結果は以下のとおりです。
SQL> select * from v_emp;
DEPARTMENT_ID EMPLOYEE_ID EMPLOYEE_NAME SALARY
------------- ----------- ------------------------------ ----------
1 1001 山田二郎 500000
1 1008 中山大輔 400000
1 1013 米村真司 350000
SQL> UPDATE v_emp SET salary = 500000 WHERE department_id = 3;
0行が更新されました。
SQL> select * from v_emp;
DEPARTMENT_ID EMPLOYEE_ID EMPLOYEE_NAME SALARY
------------- ----------- ------------------------------ ----------
1 1001 山田二郎 500000
1 1008 中山大輔 400000
1 1013 米村真司 350000
SQL>
私は新体系の試験にはあまり詳しくないのですが、以下のサイトで試験範囲の比較情報が出ておりました。
[FAQ] 新Silver DBAとSilver SQLのどちらを受験すべきか?
https://cosol.jp/techdb/2022/06/faq_new_oracle_master_silver_dba_silver_sql_2/
何割程度被るかということはわかりませんが、こちらをみる限りでは、Silver SQLの知識をもっていればSilver DBAの「SQL範囲」はカバーできそうですので、もしSilver SQLの学習から日が経ってしまい内容を忘れてしまったという場合には、Silver SQLの復習をすれば良さそうです。
また、同じブログにて以下のような記事もあがっていました。
[FAQ] 新Bronze DBAと新Silver DBAのどちらから受験すべきか?
https://cosol.jp/techdb/2022/06/faq_new_oracle_master_bronze_dba_silver_dba/
Bronze DBA合格している方であれば、Silver DBAの学習にもスムーズに入っていけそうなことが書かれていますので、もし、実務でOracle Databaseまたはその他データベースに日々触れているという状況でない場合には、せっかくなのでBronze DBAの知識を忘れてしまう前に、一気にSilver DBAまでやり切ってしまうのもアリかもしれませんね。
どちらの手順も、結果としてやっていることは同じだと思います。
Ping-tの説明では、最初に ALTER SYSTEM 文で初期化パラメータ「CONTROL_FILE」を編集していますが、解説にも記載のとおり「CONTROL_FILE」は静的パラメータなので、SCOPE=SPFILEを指定して、spfileだけを変更しています。
つまり、この時点で稼働中のインスタンスには何の影響もありません。変更内容が反映されるのは、次回の起動時です。
重要なのは、制御ファイルをコピーするタイミングで、これについてはping-tの手順でも公式ドキュメントの手順でも、インスタンスが停止した状態で、OSコマンドで制御ファイルのコピーを行っています。あとは、起動すれば初期化パラメータ「CONTROL_FILE」の変更内容も反映されます。
Ping-tさん提供の検証用データで試してみましたが、結果は以下の通りエラーとはなりませんでした。
SQL> SELECT employee_id, employee_name, salary FROM employees WHERE department_id IN (SELECT department_id FROM departments WHERE department_name = '開発') OR salary >ANY (SELECT MIN(AVG(salary)) FROM employees GROUP BY department_id);
EMPLOYEE_ID EMPLOYEE_NAME SALARY
----------- ------------------------------ ----------
1001 山田二郎 500000
1002 佐藤昭夫 500000
1003 山口洋子 500000
1004 田中浩介 500000
1005 加藤昭彦 500000
1006 佐々木明子 800000
1007 菊池浩二 800000
1008 中山大輔 400000
1009 星野健一 400000
1010 斎藤京子 400000
1011 吉田亜希 400000
EMPLOYEE_ID EMPLOYEE_NAME SALARY
----------- ------------------------------ ----------
1012 阿部伊吹 400000
1015 橋本淳 300000
13行が選択されました。
SQL>
参考までに、以下は整形したSQL文ですが、特に余計な括弧はなさそうです
SELECT
employee_id,
employee_name,
salary
FROM
employees
WHERE
department_id IN (
SELECT
department_id
FROM
departments
WHERE
department_name = '開発'
)
OR salary > ANY (
SELECT
MIN(AVG(salary))
FROM
employees
GROUP BY
department_id
);