【Java】java.sql.ResultSetから値を読み出すときメモ
JDBCは業務アプリや軽いデータ取得ツールを作るには、低レイヤすぎて面倒くさい。 特に値を読み出すところが面倒すぎてO/Rマッパに逃げた挙句、今日まともに使い方を理解したJavaおじさん5年目がメモ。
JDBCとは
Javaの標準APIに組み込まれている、データベースに接続してSQL投げてクエリするための各種セット。
サクっと(?)試せる記事があったので使い勝手はこちら参照。 https://qiita.com/wb773/items/27dc0e77a4c8b035d6fc
登場した頃の鳴り物的なものはこのあたりかも。 https://www.atmarkit.co.jp/ait/articles/0106/26/news001.html
データ取得
ResultSetの型がガバガバ
いい加減にしろっていうぐらいJava型に対応したget~メソッドが多い
// SQLではint型で取得 ResultSet resultSet = statement.executeQuery("SELECT 1"); // 下記全部それっぽい値が取れてしまう System.out.println(resultSet.getByte(1)); System.out.println(resultSet.getShort(1)); System.out.println(resultSet.getInt(1)); System.out.println(resultSet.getFloat(1)); System.out.println(resultSet.getBigDecimal(1)); System.out.println(resultSet.getObject(1));
困ったことにString型も、数字っぽかったらエラーなしで数値型に変換する始末。お前はPHPか。
ちょっと古いドキュメントだが、一番型的に正解で精緻な値が取れる組み合わせは、ResultSetMetaData.getType()からとれるjava.sql.Types 列挙体と下記ドキュメントを突き合せれば良い。 https://docs.oracle.com/cd/E16338_01/java.112/b56281/datacc.htm
NULL値の取り方
オブジェクト型であれば、get~メソッドでnullが帰ってくるが、プリミティブの数値型は 0 で帰ってくる。
ResultSet resultSet = statement.executeQuery("SELECT NULL"); // 0でとれる System.out.println(resultSet.getByte(1)); System.out.println(resultSet.getShort(1)); System.out.println(resultSet.getInt(1)); System.out.println(resultSet.getFloat(1)); // nullでとれる System.out.println(resultSet.getString(1)); System.out.println(resultSet.getBigDecimal(1)); System.out.println(resultSet.getObject(1));
ただし、プリミティブでも 直前のget~の取得結果がSQL上でnullだったかをResultSet.wasNullメソッドで検知できる。
ResultSet resultSet = statement.executeQuery("SELECT NULL"); System.out.println(resultSet.getByte(1)); System.out.println(resultSet.wasNull()); // true
したがって、1行のデータを丸々取りたかったら、だいたいこんな感じになる。
public static ArrayList<String> readOneRecord(ResultSet rs, ResultSetMetaData metaData, int colcount, List<ColumnProp> props, SimpleDateFormat sfdTimestamp) throws SQLException { ArrayList<String> list = new ArrayList<String>(colcount); for (int i=0; i<colcount; i++) { // @see https://docs.oracle.com/cd/E16338_01/java.112/b56281/datacc.htm switch (metaData.getColumnType(i+1)) { //getstring case java.sql.Types.CHAR: case java.sql.Types.LONGNVARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.VARCHAR: case java.sql.Types.NCHAR: case java.sql.Types.NVARCHAR: String vString = rs.getString(i+1); list.add(vString != null ? vString : props.get(i).nullas); break; //getBigDecimal case java.sql.Types.DECIMAL: case java.sql.Types.NUMERIC: BigDecimal vBigDecimal = rs.getBigDecimal(i+1); list.add(vBigDecimal != null ? vBigDecimal.toString() : props.get(i).nullas); break; //gettimestamp case java.sql.Types.TIMESTAMP: java.sql.Timestamp vTimestamp = rs.getTimestamp(i+1); list.add(vTimestamp != null ? sfdTimestamp.format(vTimestamp) : props.get(i).nullas); break; //getdate case java.sql.Types.DATE: java.sql.Date vDate = rs.getDate(i+1); list.add(vDate != null ? sfdTimestamp.format(vDate) : props.get(i).nullas); break; //getint case java.sql.Types.TINYINT: byte vByte = rs.getByte(i+1); list.add(rs.wasNull() ? Byte.toString(vByte) : props.get(i).nullas); break; case java.sql.Types.SMALLINT: short vShort = rs.getShort(i+1); list.add(rs.wasNull() ? Short.toString(vShort) : props.get(i).nullas); break; case java.sql.Types.INTEGER: int vInt = rs.getInt(i+1); list.add(rs.wasNull() ? Integer.toString(vInt) : props.get(i).nullas); break; case java.sql.Types.BIGINT: long vLong = rs.getLong(i+1); list.add(rs.wasNull() ? Long.toString(vLong) : props.get(i).nullas); break; //getbool case java.sql.Types.BOOLEAN: boolean vBoolean = rs.getBoolean(i+1); list.add(rs.wasNull() ? Boolean.toString(vBoolean) : props.get(i).nullas); break; //getfloat case java.sql.Types.FLOAT: case java.sql.Types.DOUBLE: case java.sql.Types.REAL: double vDouble = rs.getDouble(i+1); list.add(rs.wasNull() ? Double.toString(vDouble) : props.get(i).nullas); break; //getnull case java.sql.Types.NULL: list.add(props.get(i).nullas); break; //rowid case java.sql.Types.ROWID: RowId vRowId = rs.getRowId(i+1); list.add(vRowId != null ? vRowId.toString() : props.get(i).nullas); break; //gettime case java.sql.Types.TIME: Time vTime = rs.getTime(i+1); list.add(vTime != null ? sfdTimestamp.format(vTime) : props.get(i).nullas); break; default: list.add(props.get(i).nullas); break; // not supported // case java.sql.Types.ARRAY: // case java.sql.Types.BIT: // case java.sql.Types.BINARY: // case java.sql.Types.BLOB: // case java.sql.Types.CLOB: // case java.sql.Types.DATALINK: // case java.sql.Types.DISTINCT: // case java.sql.Types.JAVA_OBJECT: // case java.sql.Types.NCLOB: // case java.sql.Types.OTHER: // case java.sql.Types.REF: // case java.sql.Types.LONGVARBINARY: // case java.sql.Types.SQLXML: // case java.sql.Types.STRUCT: // case java.sql.Types.VARBINARY: } } return list; }