2011年2月14日月曜日

【MySql】DatabaseMetaDataからテーブルの情報取得

DatabaseMetaDataからデータベースの情報を抜き出す方法

カラム名の取得

テーブルに対応するカラムのリストを定義順に取得するコード。

Oracleだと、スキーマ名やテーブル名は大文字じゃないとNGだけど、MySqlだと小文字じゃないとダメらしい。
ずっと大文字で指定してて、データ取得できずにかなりはまった・・・。
Map<Integer, String> columns = new TreeMap<Integer, String>();
try {
    DatabaseMetaData metaData = con.getMetaData();
    // testスキーマのtest_tableのカラム情報を取得
    ResultSet resultSet = metaData.getColumns(
            con.getCatalog(), schema, table, null);
    try {
        while (resultSet.next()) {
            columns.put(resultSet.getInt("ORDINAL_POSITION"),
                    resultSet.getString("COLUMN_NAME"));
        }
    } finally {
        resultSet.close();
    }
} catch (SQLException e) {
    throw new RuntimeException(
            String.format("エラー. テーブル名 = [%s]",
                    table), e);
}

主キーの取得

テーブルに対応する主キー情報を取得するコード。

MySqlは、主キーが定義されていないテーブルがあるとSQLExceptionを投げてくれる。
0件取得でいいのに・・・。
Map<Integer, String> primaryKeys = new TreeMap<Integer, String>();
try {
    DatabaseMetaData metaData = con.getMetaData();
    // testスキーマのtest_tableの主キー情報を取得
    ResultSet resultSet = metaData.getPrimaryKeys(
            con.getCatalog(), "test", "test_table");
    try {
        while (resultSet.next()) {
            primaryKeys.put(resultSet.getInt("KEY_SEQ"),
                    resultSet.getString("COLUMN_NAME"));
        }
    } finally {
        resultSet.close();
    }
} catch (SQLException e) {
    // NOP
}

2011年2月12日土曜日

scala

プログラミングScalaが翻訳されて発売されてたのか。
scala勉強してみたいし、買ってみよう。

2011年2月7日月曜日

【Oracle】PreparedStatementの入力パラメータに変数名を指定する

JDBCのAPIを使用した場合、PreparedStatementの入力パラメータは「?」で指定する必要があり、非常に分かりづらい。カラム数の多いinsert文とか見ると何番目が、どのカラムかを即理解するなんてまず不可能だと思うし。
この問題を解決する機能を、Oracleの拡張機能で用意してくれています。
この機能を使うと、入力パラメータを「?」で定義して位置で紐付けるのではなく、変数名で紐付ける事ができるようになります。

実際に使ってみると、こんな感じのコードになる。個人的には、JDBCのAPIにこの機能ほしいと思ってしまいます。

// 入力パラメータは、":" + 変数名として定義する。
// prepareStatementの戻りを、OraclePreparedStatementにキャストする。
// Oracleの拡張機能を使うのでキャストしてあげないといけない。
OraclePreparedStatement statement = (OraclePreparedStatement) connection.prepareStatement( 
        insert into test (c1, c2, c3) values (:c1, :c2, :c3)"); 
try { 
    // setStringを使用するのではなく、Oracle拡張機能のsetStringAtNameを使う。 
    // 第一引数には、位置ではなく変数名(SQL文で定義した変数名(:を除いた物))を設定する。 
    statement.setStringAtName("c1", "1"); 
    statement.setStringAtName("c2", "あ"); 
    // 数値型の場合には、setIntAtNameを使用する。
    statement.setIntAtName("c3", 12345); 
    statement.executeUpdate(); 
} finally { 
    statement.close(); 
}

※setメソッドは、java.sql.PreparedStatementに用意されているsetXXXに対応するsetXXXAtNameがあります。IDEを使えば保管できるので何を使えばいいかはまず迷うことはないと思います。

2011年2月4日金曜日

Oracle11gからPL/SQLでのSEQUENCE採番が便利に

Oracle11gからは、PL/SQLでSEQUENCEオブジェクトを使って採番する際に、dual表を使ってSELECT文を実行する必要がなくなった。

実際のコードは、こんな感じに、採番した値をダイレクトに変数に代入できるようになった。
なんか、なんの違和感もない直感的なコードになってる気がする。
  1  declare
  2    num pls_integer;
  3  begin
  4    num := test_seq.nextval;
  5    dbms_output.put_line(num);
  6* end;
SQL>
SQL> /
2

PL/SQL procedure successfully completed.

ちなみに、これがOracle10gまでのコード。
やっぱり、select文って必要ないよな。
  1  declare
  2    num pls_integer;
  3  begin
  4    select test_seq.nextval into num from dual;
  5    dbms_output.put_line(num);
  6* end;
SQL>
SQL> /
3

PL/SQL procedure successfully completed.

Oracle10gで、11gの新機能を使ってみようとすると当然エラーとなる。
  1  declare
  2    num pls_integer;
  3  begin
  4    num := test_seq.nextval;
  5    dbms_output.put_line(num);
  6* end;
SQL> /
  num := test_seq.nextval;
                  *
ERROR at line 4:
ORA-06550: line 4, column 19:
PLS-00357: Table,View Or Sequence reference 'TEST_SEQ.NEXTVAL' not allowed in
this context
ORA-06550: line 4, column 3:
PL/SQL: Statement ignored

2011年1月25日火曜日

【intellij】live templates

Intellijには、live templatesなるものがあって、コーディング作業をサポートしてくれるテンプレートが用意されている。

デフォルトでは、こんな感じのものが用意されている。














この機能を使って、Javaのコマンドライン引数を標準出力に出力するコードを書いてみる。 ほとんどコードを書くって作業をする必要がない。

空のクラスにmain関数を作成

main関数は、「psvm」というtemplateを使用する。 templateの一覧は、Windowsのデフォルトkeymapでは、「Ctrl+j」で表示される。











「psvm」を選択するとこんな感じにmain関数が出力される。











コマンドライン引数のループ

配列のループは、「iter」というtemplateを使用する。このtemplateは、JDK5以降のfor-each文が出力される。 「itar」を使用すると、従来のfor文が出力できる。














「iter」を選択した結果。変数名を変えたい場合は、template選択後に変更可能な変数にフォーカスが当たるのでそこで変更することができるようになっている。 (いちいち、名前を変えたい変数まで移動する必要がないようになっている。)














標準出力へ出力

標準出力へ変数の出力は、「soutv」というtemplateを使用する。












こんな感じに、「変数名 = 値」を出力するsysoutが出力される。














こんな感じに、live templatesを使用すると決まりきったコードをtemplateを使ってコーディングできるためかなり作業効率が上がる。 また、templateは自由に追加できるため、これ毎回書いてるな?と思うのがあったら追加していくといい感じになるとおもう。

2011年1月23日日曜日

【ruby】エンコード指定でファイル入出力

ファイルを入出力する際には、アプリの内部エンコーディングとは異なるエンコーディングのファイルを開きたい場合がある。
そんな時には、Fileを開く際に外部エンコーディングを指定してあげれば良い。

実行時に文字列のエンコーディングを変更する方法→http://se-bikou.blogspot.com/2010/02/ruby19.html

ファイル出力


windows-31jのフィルを出力する場合

#coding:utf-8
# windows-31jを指定してファイルを開く
File.open("test.txt", "w:windows-31j") { |file|
  file.puts "1,あいうえお"
  file.puts "2,あいうえお"
}

euc-jpを指定する場合

#coding:utf-8
# euc-jpを指定してファイルを開く 
File.open("test.txt", "w:euc-jp") { |file| 
  file.puts "1,あいうえお" 
  file.puts "2,あいうえお" 
}

ファイル入力


euc-jpのファイルを出力

# euc-jpのファイルを読み込む場合
# 入力ファイルのエンコーディングには、euc-jpを指定する。 
File.open("test.txt", "r:euc-jp") {|file| 
  file.each {|line| 
    puts "#{line}:#{line.encoding}" 
  } 
}

2011年1月10日月曜日

【ruby】オブジェクトのクラスをテスト

Rubyでインスタンスがどのクラスか?(どのクラスのサブクラス)かをチェクする方法。

変数が、どのクラスかをチェックする方法
instance_of?メソッドを使うことによってチェックできる。
array = Array.new

# array変数の実体クラスのArrayを指定した場合はtrue
puts array.class == Array          # => true
    
# 親クラスのObjectを指定さ場合は、false
puts array.instance_of? Object     # => false
    
# ミックスインモジュールのEnumerableを指定した場合はfalse
puts array.instance_of? Enumerable # => false

is_a?メソッドを使うと階層構造を含めてチェックできる。
puts array.is_a? Array        # => true
puts array.is_a? Object       # => true(親クラスをチェックできる)
puts array.is_a? Enumerable   # => true(ミックスインもチェックできる)

# Classクラスの===でも同じ比較が行える。直感的なのはis_a?かな。
puts Object === array