2014年10月24日金曜日

UNIQUE制約でのNULLの扱い

0 コメント
PostgreSQLで、テーブルの複数列でUNIQUE制約をかけたとき、その中にNULLを許可する列があった場合の挙動について。

次のテーブルを作成します。
このテーブルに次のINSERT文でデータを入れてみます。
結果は次のようになります。
id=3は、UNIQUE制約違反でINSERTに失敗しています。
ここで引っかかったのはid=5がUNIQUE制約違反にならず、INSERTに成功しているところです。

私のイメージだと、NULLは何もないという感覚だったので、id=4とid=5のデータはUNIQUE制約に違反してid=5はINSERTに失敗すると思っていました。
調べてみると、PostgreSQLの一意制約の解説では、
一般に、制約の対象となる列について同じ値を持つ行が、テーブル内に1行を上回る場合は、一意性制約違反になります。 しかし、この比較では2つのNULL値は等価とはみなされません。 つまり、一意性制約があったとしても、制約対象の列の少なくとも1つにNULL値を持つ行を複数格納することができるということです。 この振舞いは標準SQLに準拠していますが、この規則に従わないSQLデータベースがあることを聞いたことがあります。 ですから、移植する予定のアプリケーションを開発する際には注意してください。
とあり、NULLは等価ではないとあり、上の例ではid=4とid=5はUNIQUE制約に違反せず、INSERTできるということになります。
文中の
この規則に従わないSQLデータベースがあることを聞いたことがあります。
は、MicrosoftのSQL Serverが該当するみたいです。
OracleやMySQLなどはPostgreSQLと同じ挙動をするんだとか。
移植の際などには気をつける必要があります。

対策としては、std列をNOT NULLとして、id=4,id=5には''を入れるようにすれば、意図した動きになります。

では、ADO.NETのDataTableはどうなんでしょう?
こんなサンプルを作って試してみました。 結果はこうなりました。 PostgreSQLとは異なり、NULLを同じ値として扱っているようです。
PostgreSQLにNULLを許可した列を含むUNIQUE制約を持つテーブルからADO.NETのDataTableにデータを取り込んだ場合、エラーになる可能性が考えられます。
UNIQUE制約をかける列は、NOT NULLにするべきでしょうね。

2014年5月15日木曜日

ubuntu14.04にoracle-xe 11gをインストール

1 コメント
ubuntu14.04 LTS ServerにOracle Database Express Edition 11g Release2をインストールしたときの手順のまとめ。

こちらのサイトを参考にさせていただきました。というか、パクリです。

まず、Oracle-XE-11.2.0のLinux x64版をダウンロードして、ubuntuにコピーしておく。

必要なパッケージをインストール。
sudo apt-get install alien libaio1 unixodbc unzip

oracle-xeのパッケージを解凍。
unzip oracle-xe-11.2.0-1.0.x86_64.rpm.zip

rpmパッケージをdebパッケージに変換。
cd Disk1/
sudo alien --to-deb --scripts oracle-xe-11.2.0-1.0.x86_64.rpm

パッケージをインストール。
/sbin/chkconfig をviで編集し
sudo vi /sbin/chkconfig
以下の内容を記述。
#!/bin/bash
# Oracle 11gR2 XE installer chkconfig hack for Debian by Dude
file=/etc/init.d/oracle-xe
if [[ ! `tail -n1 $file | grep INIT` ]]; then
   echo >> $file
   echo '### BEGIN INIT INFO' >> $file
   echo '# Provides:             OracleXE' >> $file
   echo '# Required-Start:       $remote_fs $syslog' >> $file
   echo '# Required-Stop:        $remote_fs $syslog' >> $file
   echo '# Default-Start:        2 3 4 5' >> $file
   echo '# Default-Stop:         0 1 6' >> $file
   echo '# Short-Description:    Oracle 11g Express Edition' >> $file
   echo '### END INIT INFO' >> $file
fi
update-rc.d oracle-xe defaults 80 01
configureのawkのパスが違うのでシンボリックリンクを作成。
sudo ln -s /usr/bin/awk /bin/awk
ファイルのパーミッションを変更。
sudo chmod 755 /sbin/chkconfig

パッケージのインストール。
sudo dpkg --install ./oracle-xe_11.2.0-2_amd64.deb

/etc/init.d/oracle-xeの /var/lock/subsys/ を /var/lock/ に変更。
sudo vi /etc/init.d/oracle-xe


※私の試した環境(仮想マシンに1Gのメモリを設定)では、このままconfigureを実行してうまくいきましたが、configureでエラーが出るような場合は、以下のパラメータを変更してみてください。
/u01/app/oracle/product/11.2.0/xe/config/scripts/init.ora
/u01/app/oracle/product/11.2.0/xe/config/scripts/initXETemp.ora
の2つのファイルの、memory_targetをコメントにして、pga_aggregate_targetとsga_targetを設定します。
sudo vi /u01/app/oracle/product/11.2.0/xe/config/scripts/init.ora
sudo vi /u01/app/oracle/product/11.2.0/xe/config/scripts/initXETemp.ora
以下の内容を記述。
#memory_target=418381824
pga_aggregate_target=200540160
sga_target=601620480


configureを実行。
sudo /etc/init.d/oracle-xe configure

.profileを編集して、oracleの環境変数が設定されるようにする。
vi ~/.profile
以下の内容を追加する。
source /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh

編集した.profileの内容を反映する。
source ~/.profile

oracleに接続できるか確認する。
sqlplus system/[設定したパスワード]@XE

これでoracleに接続できたらOK!