底辺SEの備忘録

スキル無しの底辺です。参考になりません。

OracleのPK削除時の挙動について

概要

OracleのPK削除時の挙動について確認しました。

確認内容

CREATE TABLE文でPK付のテーブルを作成します。

SQL> CREATE TABLE TEST.TEST0722
  2  (
  3  COL1 NUMBER,
  4  COL2 NUMBER,
  5  CONSTRAINT TEST0722_PK PRIMARY KEY( COL1 )
  6  );

表が作成されました。

データディクショナリビューを確認して制約、インデックスが作成されていることを確認します。

SQL> COL CONSTRAINT_NAME FOR A30
SQL> COL TABLE_NAME FOR A30
SQL> COL COLUMN_NAME FOR A30
SQL> SELECT
  2  CON.CONSTRAINT_NAME,CON.TABLE_NAME,CON.COLUMN_NAME
  3  FROM DBA_CONSTRAINTS C,DBA_CONS_COLUMNS CON
  4  WHERE C.OWNER='TEST'
  5  AND C.CONSTRAINT_NAME=CON.CONSTRAINT_NAME
  6  AND C.CONSTRAINT_TYPE='P'
  7  AND C.TABLE_NAME='TEST0722';

CONSTRAINT_NAME                TABLE_NAME                     COLUMN_NAME
------------------------------ ------------------------------ ------------------------------
TEST0722_PK                    TEST0722                       COL1

SQL> COL INDEX_NAME FOR A30
SQL> SELECT INDEX_NAME FROM DBA_INDEXES
  2  WHERE OWNER='TEST' AND TABLE_NAME='TEST0722';

INDEX_NAME
------------------------------
TEST0722_PK

先にインデックスを削除しようとするとエラーとなりました。

SQL> drop index TEST.TEST0722_PK;
drop index TEST.TEST0722_PK
                *
行1でエラーが発生しました。:
ORA-02429: 一意キーまたは主キーの保持に使用される索引は削除できません。

制約を削除します。

SQL> ALTER TABLE TEST.TEST0722 DROP CONSTRAINT TEST0722_PK;

表が変更されました。

制約と索引が存在しないことを確認します。

SQL> SELECT
  2  CON.CONSTRAINT_NAME,CON.TABLE_NAME,CON.COLUMN_NAME
  3  FROM DBA_CONSTRAINTS C,DBA_CONS_COLUMNS CON
  4  WHERE C.OWNER='TEST'
  5  AND C.CONSTRAINT_NAME=CON.CONSTRAINT_NAME
  6  AND C.CONSTRAINT_TYPE='P'
  7  AND C.TABLE_NAME='TEST0722';

レコードが選択されませんでした。

SQL> COL INDEX_NAME FOR A30
SQL> SELECT INDEX_NAME FROM DBA_INDEXES
  2  WHERE OWNER='TEST' AND TABLE_NAME='TEST0722';

レコードが選択されませんでした。

重複レコードもNULLレコードも挿入可能です。

SQL> INSERT INTO TEST.TEST0722 VALUES(1,2);

1行が作成されました。

SQL> INSERT INTO TEST.TEST0722 VALUES(1,2);

1行が作成されました。

SQL> INSERT INTO TEST.TEST0722 VALUES(NULL,2);

1行が作成されました。

制約を削除する際にKEEP INDEXオプションを指定して削除します。
準備としてもう一度PKを追加します。

SQL> ALTER TABLE TEST.TEST0722 ADD CONSTRAINT TEST0722_PK PRIMARY KEY(COL1);

表が変更されました。

SQL> SELECT
  2  CON.CONSTRAINT_NAME,CON.TABLE_NAME,CON.COLUMN_NAME
  3  FROM DBA_CONSTRAINTS C,DBA_CONS_COLUMNS CON
  4  WHERE C.OWNER='TEST'
  5  AND C.CONSTRAINT_NAME=CON.CONSTRAINT_NAME
  6  AND C.CONSTRAINT_TYPE='P'
  7  AND C.TABLE_NAME='TEST0722';

CONSTRAINT_NAME                TABLE_NAME                     COLUMN_NAME
------------------------------ ------------------------------ ------------------------------
TEST0722_PK                    TEST0722                       COL1

SQL> SELECT INDEX_NAME,UNIQUENESS FROM DBA_INDEXES
  2  WHERE OWNER='TEST' AND TABLE_NAME='TEST0722';

INDEX_NAME                     UNIQUENES
------------------------------ ---------
TEST0722_PK                    UNIQUE

索引は残すように制約を削除します。

SQL> ALTER TABLE TEST.TEST0722 DROP CONSTRAINT TEST0722_PK KEEP INDEX;

表が変更されました。

SQL> SELECT
  2  CON.CONSTRAINT_NAME,CON.TABLE_NAME,CON.COLUMN_NAME
  3  FROM DBA_CONSTRAINTS C,DBA_CONS_COLUMNS CON
  4  WHERE C.OWNER='TEST'
  5  AND C.CONSTRAINT_NAME=CON.CONSTRAINT_NAME
  6  AND C.CONSTRAINT_TYPE='P'
  7  AND C.TABLE_NAME='TEST0722';

レコードが選択されませんでした。

SQL> SELECT INDEX_NAME,UNIQUENESS FROM DBA_INDEXES
  2  WHERE OWNER='TEST' AND TABLE_NAME='TEST0722';

INDEX_NAME                     UNIQUENES
------------------------------ ---------
TEST0722_PK                    UNIQUE

SQL>

一意索引のみが残っているので重複レコードはエラーとなりますが、NULLレコードは挿入できます。

SQL> INSERT INTO TEST.TEST0722 VALUES(1,2);

1行が作成されました。

SQL> INSERT INTO TEST.TEST0722 VALUES(1,2);
INSERT INTO TEST.TEST0722 VALUES(1,2)
*
行1でエラーが発生しました。:
ORA-00001: 一意制約(TEST.TEST0722_PK)に反しています


SQL> INSERT INTO TEST.TEST0722 VALUES(NULL,2);

1行が作成されました。

iノードについて

iノードとは

Linuxファイルシステムでは、「ファイルの中身(データ)」と 「ファイルの属性や管理情報」 は別々に保存される。 「ファイルの属性や管理情報」を格納する記憶領域をiノードと呼ぶ。 全てのファイルにはiノード番号が振られ対応するiノードと紐づけられる。

iノード番号の確認方法

ls -iで確認可能

[oracle@localhost ~]$ ls -i test.txt
67648997 test.txt
[oracle@localhost ~]$

statでも確認可能

[oracle@localhost ~]$ stat test.txt
  File: 'test.txt'
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: f900h/63744d    Inode: 67648997    Links: 1
Access: (0644/-rw-r--r--)  Uid: (54321/  oracle)   Gid: (54321/oinstall)
Access: 2022-07-20 22:52:03.048300620 +0900
Modify: 2022-07-20 22:52:03.048300620 +0900
Change: 2022-07-20 22:52:03.048300620 +0900
 Birth: -
[oracle@localhost ~]$

cpとmvでのiノード番号の変化

cpではiノード番号は変わる

[oracle@localhost ~]$ ls -i test.txt
67648997 test.txt
[oracle@localhost ~]$ cp -p test.txt test_01.txt
[oracle@localhost ~]$ ls -li test*
67648997 -rw-r--r-- 1 oracle oinstall 212 Jul 20 22:32 test.txt
67183839 -rw-r--r-- 1 oracle oinstall 212 Jul 20 22:32 test_01.txt

mvではiノード番号は変わらない

[oracle@localhost ~]$ ls -li test.txt
67183839 -rw-r--r-- 1 oracle oinstall 0 Jul 20 22:50 test.txt
[oracle@localhost ~]$ mv test.txt test_01.txt
[oracle@localhost ~]$ ls -li test*
67183839 -rw-r--r-- 1 oracle oinstall 0 Jul 20 22:50 test_01.txt
[oracle@localhost ~]$

67648997 test.txt

select文の中でSQL文も組み立てる

方法

連結演算子||を使用する。 シングルコーテーションは、シングルコーテーションでエスケープする。

あんまりないと思いますが、1行ずつdelete文を組み立てたいとき

SQL> select * from test.test_0615;

COL1     COL2
-------- --------
aaaa     bbbb
cccc     bbbb
dddd     cccc

SQL>  select 'delete from test.test_0615 where col1='''||col1||'''' from test.test_0615 where col2='bbbb';

'DELETEFROMTEST.TEST_0615WHERECOL1='''||COL1||''''
--------------------------------------------------------------------------------
delete from test.test_0615 where col1='aaaa'
delete from test.test_0615 where col1='cccc'

SQL>

OracleでSYSDBA権限を持つユーザを確認する方法

V$PWFILE_USERSで確認することが可能

表示例

SQL> select username,sysdba from V$PWFILE_USERS;

USERNAME                       SYSDBA
------------------------------ ----------
SYS                            TRUE
SYSDG                          FALSE
SYSBACKUP                      FALSE
SYSKM                          FALSE

SQL>

参考

V$PWFILE_USERSは、パスワード・ファイルに格納されているすべてのユーザーの一覧表示するとのこと docs.oracle.com

straceを使用してローカルネーミング接続でtnsnames.oraファイルを読み込んでいることを確認

概要

straceを使用してsqlplusを使用してローカルネーミング接続した際に
tnsnames.oraファイルを読み込んでいることを確認しました。

方法

以下のコマンドを実行

strace sqlplus <ユーザ名>/<パスワード>@<ネットサービス名>

出力結果の中に以下を確認

access("/home/oracle/.tnsnames.ora", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/tnsnames.ora", F_OK)       = -1 ENOENT (No such file or directory)
access("/u01/app/oracle/product/12.2.0/dbhome_1/network/admin/tnsnames.ora", F_OK) = 0
stat("/u01/app/oracle/product/12.2.0/dbhome_1/network/admin/tnsnames.ora", {st_mode=S_IFREG|0644, st_size=1086, ...}) = 0

特定の列名が存在する(しない)テーブルの一覧を表示するSQL(Oracle版)

概要

Oracleで特定の列名が存在するテーブル(しない)の一覧を表示するSQL

方法

以下で取得可能と思われる。。。
TESTスキーマ内の列名COL1が存在するテーブルを抽出

SELECT TABLE_NAME  FROM DBA_TABLES A WHERE OWNER='TEST'
AND EXISTS(SELECT 'X' FROM DBA_TAB_COLUMNS B WHERE
A.OWNER=B.OWNER AND A.TABLE_NAME=B.TABLE_NAME AND B.COLUMN_NAME='COL1'
)

TESTスキーマ内の列名COL1が存在しないテーブルの一覧の抽出

SELECT TABLE_NAME  FROM DBA_TABLES A WHERE OWNER='TEST'
AND NOT EXISTS(SELECT 'X' FROM DBA_TAB_COLUMNS B WHERE
A.OWNER=B.OWNER AND A.TABLE_NAME=B.TABLE_NAME AND B.COLUMN_NAME='COL1'
)

確認

テーブル定義

SQL> desc test1
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 COL1                                               NUMBER

SQL> desc test2
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 COL1                                               NUMBER
 COL2                                               NUMBER
 COL3                                               NUMBER

SQL> desc test3
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 COL2                                               NUMBER

SQL> desc test4
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 COL2                                               NUMBER
 COL3                                               NUMBER
 COL4                                               NUMBER

SQL> desc test5
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 COL1                                               VARCHAR2(10)
 COL2                                               VARCHAR2(10)

SQL> desc test6
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 COL2                                               VARCHAR2(10)
 COL3                                               VARCHAR2(10)

SQL>

実行結果

SQL> SELECT TABLE_NAME  FROM DBA_TABLES A WHERE OWNER='TEST'
  2  AND EXISTS(SELECT 'X' FROM DBA_TAB_COLUMNS B WHERE
  3  A.OWNER=B.OWNER AND A.TABLE_NAME=B.TABLE_NAME AND B.COLUMN_NAME='COL1'
  4  )
  5  ;

TABLE_NAME
--------------------------------------------------------------------------------
TEST1
TEST2
TEST5

SQL> SELECT TABLE_NAME  FROM DBA_TABLES A WHERE OWNER='TEST'
  2  AND NOT EXISTS(SELECT 'X' FROM DBA_TAB_COLUMNS B WHERE
  3  A.OWNER=B.OWNER AND A.TABLE_NAME=B.TABLE_NAME AND B.COLUMN_NAME='COL1'
  4  );

TABLE_NAME
--------------------------------------------------------------------------------
TEST3
TEST4
TEST6