MySQLで、PrimaryKey以外を条件としてINSERT or UPDATE のような事を実現する
MySQLの REPLACE 文は、プライマリーキー(正確にはPrimaryKey、またはUniqKey)を条件にして一致するものがある場合は DELETE&INSERT、一致するものがなければ INSERT のみを行うという事ができるます。
似たような事を行うものとして、Oracleの MERGE 文がありますが、こちらはプライマリーキーでなくとも任意の条件を指定して INSERT、または UPDATE を行うことができます。
さて、MySQL でも PrimaryKey以外を条件に INSERT or UPDATE を行いたい事があったので、やり方を考えてみました(※PrimaryKey は AutoIncrement になっているという前提)。
CREATE TABLE user (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(30),
birthday DATE,
PRIMARY KEY(id)
上のような(id,name,birthday)カラムをもつ user テーブルがあったとき、、
name カラムを条件として、(name,birthday) = ('山田太郎','1980-05-15') のレコードを INSERT or UPDATE するSQLを以下に示します。
REPLACE user
SELECT id,name,'1980-05-15'
FROM dual LEFT JOIN user
ON user.name = '山田太郎'
該当レコードが存在する場合、id の値が入るので普通に REPLACE 文が実行されます。該当レコードが存在しない場合、id が NULL となるためマッピングされるレコードなし→INSERT文が実行される→id は AutoIncrement される、となりINSERTが成功します。
(※'山田太郎'が複数いるケースは考えないです・・
以上で、MySQL の REPLACE 文で PrimaryKey 以外を条件にして更新ができました。
WindowsのApacheでPHPを動かそうとしたときに、Cannot load mysql extension. といわれた
Windows 上に、Apache + PHP + MySQL の環境を構築していて、ハマった問題と解決策のメモ。
■事象
PHPからMySQLに繋ごうとすると、Cannot load mysql extension.というエラーが発生。Apache のログにも以下が出力されていた。
PHP Warning: PHP Startup: Unable to load dynamic library 'C:/Program Files/php-5.2.6/ext/php_mysql.dll'
※PHPのインストール&設定は、Webなどに掲載されているとおりに正しく実施している
■原因&対策
Windows上でPHPから、MySQLに繋ぐには、適切なバージョンのlibmysql.dll がパスの通ったところになければならない。
普通にWindows用のPHPをインストールすると、インストールディレクトリにlibmysql.dll があるので(インストールディレクトリにパスを通していれば)問題にはならないが、この「適切なバージョンの」というところがポイント。
僕の環境では古いMySQLがインストールされていて、かつ、そのMySQLがパスの前の方に指定してあったため、別の「libmySQL.dll」が読み込まれて、上記エラーが発生していました。パスの順序を修正して解決。
いやあ、悩んだ・・・orz
MySQLでNULLを含むカラムにINDEXを張っても大丈夫
「NULLを含むカラムにINDEXを張っても使用されないので、できればNULLを意味するデフォルト値を設定しよう」という記述を何回かみたことがあって、てっきりそうだと思い込んでいました。が、MySQLのマニュアルには、
と書いてありました。たぶん「NULLが含まれていると駄目な場合もある」のだと思いますが、上記のようなケース(IS NULLの比較)では問題ないようです。
column_name IS NULL を使用した検索では、column_name にインデックスが
張られている場合にインデックスが使用されます。
http://dev.mysql.com/doc/refman/4.1/ja/mysql-indexes.html
自分で調べてみるものです。
Eclipseプロジェクト内に、Validate対象外のディレクトリを作る方法
Eclipseプロジェクト内に、Tomcatのランタイムを格納すると便利だと思ってやってみたのですが、TomcatのサンプルのWebアプリが検証にひっかかってしまって、Eclipse上に大量のエラーがでてしまいました。
Tomcatのサンプルを捨ててしまうという解決策も考えたのですが、そもそも「Eclipseで特定のディレクトリ以下を検証の対象外とする方法はないのか?」という点が気になったので調べてみました。
結論からいうと、Eclipseの機能としてはない、が少しトリッキーな方法で実現できました。
まず、Eclipseの検証機能ですが、これはプロジェクト単位で有効/無効を切り替えることはできますが、ディレクトリ単位では無理なようです。一方で、Eclipseの機能として「.(ドット)」で始まるディレクトリは管理対象(検証対象)としない、という機能があります。これを利用しました。
つまり、Eclipseプロジェクト内に「.Tomcat」というディレクトリを作りました。そして、その下にTomcat一式を置くと、、、
検証エラーを発生させることなく、Tomcat一式をEclipseプロジェクト内に置くことができました。
ちなみに、「.(ドット)」から始まるディレクトリは管理対象(=検証対象)にはならないのですが、ライブラリ選択や、サーバ選択では普通にでてきました。万事解決。
Java1.6+Antを動かそうとすると、java.lang.NoClassDefFoundError: org/apache/tools/ant/launch/Launcher
Linux(Fedora)に、Java1.6とAntをインストールして、いざAntを動かそうとすると表題のエラーが発生。
Javaは、jdk-6u7-linux-i586-rpm.bin をダウンロードしてインストール、Antは yum install antでインストールしたもの。
原因調査のために、まず、javaコマンドから実行
java -cp /usr/share/java/ant-launcher.jar org.apache.tools.ant.launch.Launcher --help
これは問題なく動いた。ということは、/usr/bin/ant の問題か。次に /usr/bin/ant の中身を見てみると "-execdebug" というオプションがあることを発見。これをつけて実行してみると、
こんなメッセージがでてきた。実際に /usr/share/ をみてみると、java-1.4.2/、java-1.5.0/ はあるのに、java-1.6.0/ はない。じゃあ、作ればいいのかな、と思って作って実行してみると、、、
error: JAVAVER_LIBDIR /usr/share/java-1.6.0 does not exist
さっきのエラーは消えて別の同じようなエラーが発生。こっちも同様にディレクトリを作成してい再実行してみる。すると、、、
error: JAVAVER_JNIDIR /usr/lib/java-1.6.0 does not exist
動きました。こんな解決方法で良かったのかどうかは分かりませんが、まあ、当面の作業には問題ないので良しとしよう。。。
成功!
XMLHttpRequestオブジェクトでリダイレクトをハンドリングする方法
以前に、同じタイトルのエントリを書いたのですが、それよりもスマートなやり方がわかったので、書いておきます。
やりたいことについては前のエントリで書いたとおり。
- XMLHttpRequestで送ったリクエストが、サーバで認証エラー(セッションタイムアウトなど)となる
- このときサーバは認証エラー(=401)を返すのではなく、ログインページへのリダイレクトを返す
- クライアント(XMLHttpRequest)は、リダイレクト応答をうけとり、自動的にリダイレクト先を追跡する
- 結果、クライアントはログインページのHTMLを取得する(このときステータスコード=200)
- しかし、そもそもクライアントはJSON形式のデータを期待しているためスクリプトエラーとなる
前のエントリでは、XMLHttpRequestでレスポンスヘッダが使えることに着目して、"Content-Type"ヘッダが"text/html"だったらページを強制的に遷移させる方法でした。しかし、この方法は「"Content-Type"ヘッダが"text/html"である正常なレスポンス」があったら使えません。そこで以下の方法を思いつきました。4. および 6. のところが今回紹介する方法になります。
- XMLHttpRequestで送ったリクエストが、サーバで認証エラー(セッションタイムアウトなど)となる
- このときサーバは認証エラー(=401)を返すのではなく、ログインページへのリダイレクトを返す
- クライアント(XMLHttpRequest)は、リダイレクト応答をうけとり、自動的にリダイレクト先を追跡する
- ログインページでは、レスポンスヘッダに "AjaxRedirect: /Login.jsp" を追加する
- 結果、クライアントはログインページのHTMLを取得する(このときステータスコード=200)
- クラインアンは、レスポンスヘッダをチェックし、"AjaxRedirect" ヘッダが設定されているので、その値のURLを追跡する
以上で、XMLHttpRequestを使ったリダイレクトの完成。サンプルコードも載せておきます。
<% response.setHeader("AjaxRedirect", request.getContextPath() + "/Login.jsp"); %>
httpRequest.onreadystatechange = function() { if (httpRequest.readyState == 4 && httpRequest.status == 200) { var redctUrl = httpRequest.getResponseHeader("AjaxRedirect"); if (redctUrl != null) // リダイレクトURLが設定されていれば追跡 window.location.href = redctUrl;