| Oracle | Oracleちょっとメモ | |
| 2001/01/13 - 2025/10/11 |
| パスワードに「%」文字を含めるには? |
ALTER USER USER1 IDENTIFIED BY "PASS%WORD";のように二重引用符で囲めばOKです。一重だとエラーになるので注意。 |
| SQL*Plusの「&」 |
| SQL*Plusでリモートデータベースに接続するとき「@サービス名」部分を省略したい |
export TWO_TASK=REMOTEDB1 sqlplus USER1/PASS1とすると、 sqlplus USER1/PASS1@REMOTEDB1と同じ意味になります。 |
| 他の開発ツールで実行できるCREATE文が、SQL*PlusだとORA-00933エラーになる |
| ストアドプロシージャにエラーがないのにORA-06508エラーになる |
この場合はおとなしくセッション1を終了し、再度接続して実行する必要があります。 |
| SELECT文にDISTINCTを付けただけでORA-01791エラーになる |
SELECT DISTINCT ORDER_NO||'-'||LINE_NO, ITEM_NAME FROM ORDERS WHERE BUYER_NAME = 'TARO' ORDER BY ORDER_NO, LINE_NOこれ、「ORA-01791: SELECT式が無効です。」というエラーになります。 DISTINCTを付けた場合、ORDER BYに指定できるのはSELECT句に含めたカラムだけになります。 したがって、エラーを解消するには、 SELECT DISTINCT ORDER_NO||'-'||LINE_NO, ORDER_NO, LINE_NO, ITEM_NAME FROM ORDERS WHERE BUYER_NAME = 'TARO' ORDER BY ORDER_NO, LINE_NOこのようにORDER_NO,LINE_NOをSELECT対象に入れるか、または SELECT DISTINCT ORDER_NO||'-'||LINE_NO, ITEM_NAME FROM ORDERS WHERE BUYER_NAME = 'TARO' ORDER BY ORDER_NO||'-'||LINE_NOこのようにORDER BYの方を変えるかのいずれかにする必要があります。 |
| DBMS_SQLパッケージでCREATE文を使うとORA-01031エラー |
| 「PLS-00313: この有効範囲内で***が宣言されていません。」ってなあに? |
どうしてもプロシージャ定義をコール個所より上に書けない場合は、 「先に宣言だけ書いておく」という方法で回避できます。詳しくは、マニュアルで。 |
| ALTER TABLE 〜 MOVE文の後にビューを参照するとORA-01502エラー |
そのため、MOVE後は必ず対象表の索引をALTER INDEX 〜 REBUILDで再作成する必要があります。 |
| 参照整合性制約の参照先の表をTRUNCATEするとORA-02266エラー |
DELETEではなくどうしてもTRUNCATEしたい場合は、一時的に制約をDISABLE CONSTRAINTで無効にするか、 DROP CONSTRAINTで削除してからTRUNCATEを実行する必要があります。 |
| オブジェクト権限の検索 |
| 「他スキーマのシノニム」へのシノニム |
CREATE SYNONYM KUDAMONO FOR FRUITS; GRANT SELECT ON FRUITS TO USER2;このとき、USER2が CREATE SYNONYM KUDAMONO FOR USER1.KUDAMONO; SELECT * FROM KUDAMONO;を実行したらデータが見れるでしょうか?答えは見れます。 Oracleでは、シノニム自身にはSELECT権限という概念はありません。 まさに「別名」というラベルが貼られているだけの状態です。 この例のようにシノニム参照が多重化している場合、 最終的な参照先オブジェクトである USER1.FRUITS への権限を持っていれば、 シノニムを利用したデータ操作が可能です。 |
| シノニムをGRANTするとどうなるの? |
Oracleでは、シノニムをGRANTするということは、シノニムの参照先のオブジェクトをGRANTしている意味になります。 従ってすぐ上の例のように、他のOracleユーザーは、参照先のオブジェクトに対する権限を持っていれば、 シノニムを名指ししてそのオブジェクトを操作することも自動的にできるようになります。 |
| 整数を16進数に変換して文字列に格納する |
SELECT TO_CHAR(255,'FMXXXX') FROM DUAL;Xを大文字で書くと16進数のアルファベットが大文字に、小文字にすると16進数のアルファベットが小文字になります。 |
| 0.6は0.6、6は6と表記する |
小数点が邪魔なんだけどなあ、邪魔だなあ…ではどうするか、 面倒なのでRTRIMすればいいんじゃないでしょうか(おーい) SELECT RTRIM(TO_CHAR(6,'FM999990.999'), '.') FROM DUAL;なお、FMをつけずに、代わりに'.0'をRTRIMしても同じ結果が得られます。 |
| EBCDICコード順のORDER BY |
SELECT ORDER_NO, LINE_NO FROM ORDERS ORDER BY ORDER_NO, CONVERT(LINE_NO, 'JA16EBCDIC930'); |
| 表をある列でORDER BYし、先頭の1行だけを取り出す |
SELECT ID, NAME, AGE FROM EMPS WHERE AGE = (SELECT MIN(AGE) FROM EMPS)こんな感じですね(年齢が最も若い人のレコードを取得)。 ただし、複数の表を結合したり、「最も」ではなく「3番目」を取りたいといった場合難しくなってきます。 そのときは2つ目の方法として行番号を振るROW_NUMBER関数を使って SELECT ID, NAME, AGE FROM ( SELECT ID, NAME, AGE, ROW_NUMBER() OVER (ORDER BY AGE) RN FROM EMPS ) WHERE RN = 1このように書けます。 ちなみに、ORDER BYする必要がなく、複数行返る可能性は分かっているが、 それらのどの行を取り出しても問題ないのであればROWNUM擬似列を使うのが分かりやすいです。 SELECT ID, NAME, AGE FROM EMPS WHERE ROWNUM = 1;但し、ROWNUMはソートする前に連番を振ってしまうので、 どの行でもいいわけではなく、あくまでソートしてから1行目だけを取り出したい場合は、 ORDER BY有りのSQLを副問合せとして、ORDER BY無しのSQLで囲んで二重に書けばOKです。 SELECT ID, NAME, AGE FROM (SELECT ID, NAME, AGE FROM EMPS ORDER BY AGE) WHERE ROWNUM = 1; |
| 表をある列でグループ化し、グループごとに別のソートキー列で連番を振る |
SELECT ID, NAME, AGE,
ROW_NUMBER() OVER (PARTITION BY DEPT_NO ORDER BY AGE) RN FROM EMPS
これにWHERE句をつけると、「総務部で3番目に若い人は誰か」のような検索ができます(あまり現実的でないか)。
もっと実用的な例で言えば、店舗の営業日カレンダーマスタなんかに使えますね。
「ある月の第3営業日は何日か?」のような問合せは在庫管理システムなどでいかにもありそうです。
|
| 表を横向きに集計する |
ええと、 1つの注文番号で複数のお届け先がありうるとします。 ORDER_NO | OTODOKESAKI ----------------------------------- 00012345 | 横浜市西区南幸z-z-zz 00012345 | 新潟市中央区柳島町z-z-zz 00034567 | 横浜市西区南幸z-z-zz 00034567 | 新潟市中央区柳島町z-z-zz 00034567 | 大阪市淀川区西中島z-z-zz ...これを ORDER_NO | お届け先1 | お届け先2 | お届け先3 ------------------------------------------------------------------------------------ 00012345 | 横浜市西区南幸z-z-zz | 新潟市中央区柳島町z-z-zz | 00034567 | 横浜市西区南幸z-z-zz | 新潟市中央区柳島町z-z-zz | 大阪市淀川区西中島z-z-zzSQL1個でこのように集計したいという。 これは次のようにすれば可能です。
SELECT a.ORDER_NO,
MAX(CASE WHEN a.RN = 1 THEN a.OTODOKESAKI ELSE NULL END) AS OTO1,
MAX(CASE WHEN a.RN = 2 THEN a.OTODOKESAKI ELSE NULL END) AS OTO2,
MAX(CASE WHEN a.RN = 3 THEN a.OTODOKESAKI ELSE NULL END) AS OTO3,
MAX(CASE WHEN a.RN = 4 THEN '他' ELSE NULL END) AS OTO4
FROM
(SELECT ORDER_NO, OTODOKESAKI,
ROW_NUMBER() OVER (
PARTITION BY ORDER_NO ORDER BY DELIVERY_DATE ) AS RN
FROM DELIVERY_DB) a
GROUP BY a.ORDER_NO
|
| DECODE関数が返すデータ型 |
DECODE(COL1, '1', NULL, '2', 100, 200)を実行したとき、COL1の値が'3'だった場合、整数の200が返ると思うかな? 違います。文字列の'200'が返ってしまいます。 DECODE関数の戻り値のデータ型は、DECODE(s, r1, v1, r2, v2, r3, v3...) とやったとき、v2やv3のデータ型には一切関係なく、常にv1のデータ型が採用されます。 v1がNULLであれば、v2やv3のデータ型には一切関係なく、常にVARCHAR2型で返されます。 |
| ストアドプロシージャの更新日とソースコードを検索する |
SELECT b.NAME, b.TYPE, MAX(TO_CHAR(a.LAST_DDL_TIME, 'YYYY/MM/DD HH24:MI:SS')),
MAX(b.LINE), SUM(LENGTHB(b.TEXT))
FROM USER_OBJECTS a, USER_SOURCE b
WHERE a.OBJECT_NAME = b.NAME
AND a.OBJECT_TYPE = b.TYPE
GROUP BY b.NAME, b.TYPE
ORDER BY b.NAME, b.TYPE
|
| ソースコードに特定の文字列を含むストアドプロシージャ、ファンクション、パッケージを抽出する |
SELECT DISTINCT NAME, TYPE FROM USER_SOURCE
WHERE TYPE IN ('PROCEDURE', 'FUNCTION', 'PACKAGE') AND TEXT LIKE '%TARGET_STRING%';
|
| ストアドプロシージャをコンパイルしてもLAST_DDL_TIMEが更新されない |
| あるはずのデータが見れない! |
SELECT ITEM_CODE FROM TABLE_A a WHERE NOT EXISTS (SELECT 1 FROM TABLE_B WHERE ORDER_NUMBER = a.ORDER_NUMBER)TABLE_Bに存在しない注文番号をTABLE_Aから探し、その品目コードを表示するという、 超ありがちな例ですが、そのようなデータが存在するはずなのに、 1件も該当しません。なぜでしょうか。 ありがちな例として、TABLE_Aの注文番号がORDER_NUMBER、 TABLE_Bの注文番号がORDER_NOだったとしたら? 「それなら列名が違うからエラーになるだろう」と思ってSQLを再度よく見ると? 「(SELECT 1 FROM TABLE_B WHERE ORDER_NUMBER = a.ORDER_NUMBER)」 の左側のORDER_NUMBERは、当然TABLE_Bの列だろうと読めてしまいますが、 TABLE_BにはORDER_NUMBERという列はないのにエラーにならない? そうです、左も右もORDER_NUMBERはTABLE_Aの同じ列を指しているので、 このSQLでは該当行が現れることはありません。 |
| EXPLAIN PLANで実行計画を見ようとすると 「ORA-01039 insufficient privileges on underlying objects of the view (ORA-01039: ビューのもとになるオブジェクトに関する特権が不十分です)」 というエラーが出る。 |
| Oracle8iでPRAGMA AUTONOMOUS_TRANSACTIONで自立型トランザクションを行わせると、 ORA-00164 「移行可能な分散トランザクション内で自立型トランザクションの処理はできません」 というエラーが出る。 |
| シーケンスにいつも20くらいの飛び(欠番)が発生する! |
| 文字列の簡単な暗号化 |
DBMS_OBFUSCATION_TOOLKIT.DESENCRYPT(
input_string => lv_plain_pass,
key_string => lv_key,
encrypted_string => lv_enc_pass
);
暗号化には、「DBMS_OBFUSCATION_TOOLKIT.DESENCRYPT」や
「DBMS_OBFUSCATION_TOOLKIT.DES3ENCRYPT」を使い、
復号には「EN」が「DE」に変わった名前の関数を使います。引数の名前を明示しているのは、 オーバーロードしている関数があるためです。 つまり引数の名前を指定しないと PLS-00307 (複数のプロシージャが宣言されている) というエラーになります。 入力文字列(上記の例のlv_plain_pass)は、文字列の長さ(バイト数)が8の倍数でなければいけません。 つまり、少なくとも8バイトの長さが必要で、 それを超える場合には16、24…という長さに文字列を合わせてやる必要があります。 |
| 元表の持ち主にビューをGRANTしてもORA-01720が発生する |
そうです、AがBに「GRANT SELECT ON CHUMON」する際に「WITH GRANT OPTION」をつけない限り、 相手が元表の持ち主といえどもビューを公開することはできません。 |
| 普通に発行できるSQLをPL/SQLの中で使うとORA-00942でコンパイルエラーになる |
これは、実行に必要な権限の一部を、ロール経由で付与されていると発生します。 例えば、MY_ROLEロールをつくり、SELECT ANY TABLEシステム権限をMY_ROLEに付与し、 MY_ROLEを各ユーザに付与すれば、 各ユーザは他ユーザの表やビューを個別のGRANTなしにSELECTできるようになります。 しかし、同じSELECT文をストアドプロシージャの中で使おうとすると、 ORA-00942でコンパイルエラーになってしまうのです。 |
| Oracleは一意制約違反になる条件がおかしい? |
つまり例えば、表に3つの列からなる一意制約を付けたとします。 それらの値が(NULL,NULL,NULL)の行はいくつあっても一意制約違反になりませんが、 (値A、値B、NULL)という行が複数作られようとすると、一意制約違反になります。 直感的にはよく分からない仕様ですね。 RDBMSとはこういうものなのか、それともOracleだけが特殊なのか? 全てはなぞのままなのであった。(帰れ) |
| 「1.2.3」のような「本の章立て」みたいなデータを並び替える |
これを正しく並び替える方法は色々考えられますが、一例として次のようなソートキーを作る方法があります。 この例では「.1」または「{行頭}1」を「.01」と左0詰して2桁に揃えた後、 元々の「10」が「010」になっているのを後ろ2桁に削り直しています。これをORDER BYに食わせれば所望の事ができると思います。 なおこの例は「1.100.3」のような3桁以上の数字には非対応です。
SELECT REGEXP_REPLACE(REGEXP_REPLACE('1.3.4', '(\.|\A)(\d)', '.0\2'), '\d(\d\d)', '\1') FROM DUAL;
.01.03.04
SELECT REGEXP_REPLACE(REGEXP_REPLACE('1.23.4', '(\.|\A)(\d)', '.0\2'), '\d(\d\d)', '\1') FROM DUAL;
.01.23.04
|
| 副問合せを使って更新する |
UPDATE ITEMS a SET PRICE = (SELECT PRICE FROM NEW_ITEMS b WHERE b.PRICE = a.PRICE) WHERE EXISTS (SELECT 1 FROM NEW_ITEMS b WHERE b.PRICE = a.PRICE)副問合せを二重に使うなんて、処理がものすごく遅いんじゃないのと一見思ってしまいがちですが、 やってみると場合にもよりますが割と負荷にならないこともありますよ。不思議ですね(←あるまじき発言) |
| SELECT文の結果で複数列を更新する |
ストアドプロシージャを作らなくても、次のようにSQL一発で実行できます。これは超便利。
UPDATE ORDERS
SET (UPDATED_USER_ID, UPDATED_USER_NAME, UPDATED_USER_SEC_ID, UPDATED_USER_SEC_NAME) =
(SELECT USER_ID, USER_NAME, USER_SEC_ID, USER_SEC_NAME FROM EMP_DB WHERE USER_ID = 'U0001')
WHERE ORDER_ID = "A123"
|
| SYSDBAで接続しようとするとORA-01017が発生する |
1. そもそもOracleインスタンスが起動していない。 2. 環境変数ORACLE_HOMEやORACLE_SIDが正しく設定されていない。 3. 実行しているOSユーザーがdbaグループに所属していない。groupsコマンドを実行してdbaが出てこなければアウトです。 4. sqlnet.oraでOS認証が許可されていない。 sqlnet.oraは通常 $ORACLE_HOME\network\admin に置かれています。 Windowsの場合は SQLNET.AUTHENTICATION_SERVICES= (NTS)Linuxの場合は SQLNET.AUTHENTICATION_SERVICES= (BEQ)と記述します。(NONE)と書かれていたらそれはOS認証を許可しない設定です。 なお、NTSはWindows、BEQはLinux/UNIX専用の認証方式です。逆側を書いても認証が効くようにはなりません。 また、sqlnet.oraの設定を変えたらOracleインスタンスやリスナーは再起動した方がいいの? ネット情報では様々ですが、ざっくり言うと認証方式に関する設定を変えた場合は再起動が必要で、 その他の設定を変えた場合は不要です。よくわからん場合は再起動した方が無難です。 |
| アーカイブログモードで、残しておくべきアーカイブログファイルの表示 |
SET PAGESIZE 50
SET HEADING OFF
SELECT NAME || ' ' || SEQUENCE# || ' ' || NEXT_CHANGE#
FROM V$ARCHIVED_LOG
WHERE NEXT_CHANGE# >= (SELECT MIN(CHANGE#) FROM V$BACKUP
WHERE CHANGE# > 0);
|
| データファイルを使用しているDBオブジェクトの検出 |
SELECT A.SEGMENT_NAME, A.EXTENT_ID, A.FILE_ID FROM DBA_EXTENTS A WHERE A.OWNER = 'PO' AND A.TABLESPACE_NAME = 'POX' AND A.FILE_ID = 22 ORDER BY A.SEGMENT_NAME |
| Oracle Instant Clientって |
|
| もくじ | ||
| Oracle | (C) 2002-2025 MISUMI URANO |