2006/01
java.sql.DatabaseMetaDataを使うとDBのメタ情報(テーブル定義情報等)を
取得することが出来ます。テーブル名や列名、属性、長さ等です。
これらを元にSQL文を生成したいと思います。
package tool.db;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
/**
* JDBCでDBに接続してメタ情報を取得し、SQL文を生成してファイルに出力する。
* SQL文はSELECT(無条件 & 主キーを条件)、INSERT、UPDATE(主キーを条件)、
* DELETE(主キーを条件)
* @author yamarou
*/
public class SQLGeneretor {
public static void main(String[] args) throws Exception {
System.out.println("処理開始");
PrintWriter out = new PrintWriter(new FileWriter("c:/TEMP/sql.txt"));
String driverName = "COM.ibm.db2.jdbc.app.DB2Driver";
String url = "jdbc:db2:YAMAROUDB";
String user = "db2admin";
String password = "db2admin";
String schem = "SCHEM01";
ArrayList list = loadDBInfo(driverName, url, user, password, schem);
for (int i = 0; i < list.size(); i++) {
TableVO table = (TableVO) list.get(i);
String tableID4Java = table.getName();
tableID4Java =
tableID4Java.substring(0, 1)
+ tableID4Java.substring(1).toLowerCase();
String sql = "SELECT ";
String columnNames = "";
for (Iterator iter = table.getColumns().iterator();
iter.hasNext();
) {
String column = (String) iter.next();
sql += column + ",";
columnNames += column + ",";
}
sql = sql.substring(0, sql.length() - 1);
sql += " FROM " + schem + "." + table.getName();
columnNames = columnNames.substring(0, columnNames.length() - 1);
sql += " WHERE ";
String where = "";
for (Iterator iter = table.getPrimaryKeys().iterator();
iter.hasNext();
) {
String column = (String) iter.next();
sql += column + "=? AND ";
where += column + "=? AND ";
}
sql = sql.substring(0, sql.length() - 5);
out.println(sql);
try {
where = where.substring(0, where.length() - 5);
} catch (StringIndexOutOfBoundsException e) {
}
sql = "INSERT INTO " + schem + "." + table.getName() + "(";
for (Iterator iter = table.getColumns().iterator();
iter.hasNext();
) {
String column = (String) iter.next();
sql += column + ",";
}
sql = sql.substring(0, sql.length() - 1);
sql += ") VALUES(";
String values = "";
for (Iterator iter = table.getColumns().iterator();
iter.hasNext();
) {
String column = (String) iter.next();
sql += "?,";
if (column.equals("RCRD_CRTS")) {
values += "CURRENT TIMESTAMP,";
} else if (column.equals("ROW_UPDTS_DBS")) {
values += "CURRENT TIMESTAMP,";
} else {
values += "?,";
}
}
sql = sql.substring(0, sql.length() - 1) + ")";
out.println(sql);
values = values.substring(0, values.length() - 1);
sql = "DELETE FROM " + schem + "." + table.getName() + " WHERE ";
for (Iterator iter = table.getPrimaryKeys().iterator();
iter.hasNext();
) {
String column = (String) iter.next();
sql += column + "=? AND ";
}
sql = sql.substring(0, sql.length() - 5);
out.println(sql);
sql = "UPDATE " + schem + "." + table.getName() + " SET ";
String columnNamesAndParameters = "";
for (Iterator iter = table.getColumns().iterator();
iter.hasNext();
) {
String column = (String) iter.next();
sql += column + "=?,";
if (column.equals("ROW_UPDTS_DBS")) {
columnNamesAndParameters += column + "=CURRENT TIMESTAMP,";
} else if (
column.equals("RCRD_CRTS")
|| column.equals("CREAT_USRID_RCRD")
|| column.equals("DEL_FLAG")) {
} else {
columnNamesAndParameters += column + "=?,";
}
}
columnNamesAndParameters =
columnNamesAndParameters.substring(
0,
columnNamesAndParameters.length() - 1);
sql = sql.substring(0, sql.length() - 1) + " WHERE ";
for (Iterator iter = table.getPrimaryKeys().iterator();
iter.hasNext();
) {
String column = (String) iter.next();
sql += column + "=? AND ";
}
sql = sql.substring(0, sql.length() - 5);
out.println(sql);
}
out.close();
System.out.println("処理終了");
}
/**
* DB情報を取得してリストに格納して返す。
* @param driverName ドライバー名
* @param url URL
* @param user DBユーザ名
* @param password DBパスワード
* @param schem DBスキーマ名
* @return DB情報
* @throws ClassNotFoundException ドライバークラスが見つからない
* @throws SQLException DBエラー
*/
public static ArrayList loadDBInfo(
String driverName,
String url,
String user,
String password,
String schem)
throws ClassNotFoundException, SQLException {
Class.forName(driverName);
Connection con = DriverManager.getConnection(url, user, password);
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getColumns(null, schem, "%", "%");
HashMap map = new HashMap();
while (rs.next()) {
//printResultSet(rs);
String tableName = rs.getString("TABLE_NAME");
String columnName = rs.getString("COLUMN_NAME");
String typeName = rs.getString("TYPE_NAME");
TableVO table = (TableVO) map.get(tableName);
if (table == null) {
table = new TableVO();
table.setName(tableName);
loadPrimaryKeyList(
dbmd,
table.getName(),
table.getPrimaryKeys(),
schem);
map.put(tableName, table);
}
table.getColumns().add(columnName);
}
rs.close();
con.close();
ArrayList list = new ArrayList();
Collection c = map.values();
for (Iterator iter = c.iterator(); iter.hasNext();) {
TableVO e = (TableVO) iter.next();
list.add(e);
}
Collections.sort(list);
return list;
}
/**
* dbmdからschemスキーマのtableNameテーブルの主キー情報を取得して
* listに格納して返す。
* @param dbmd DB定義情報
* @param tableName テーブル名
* @param list 主キー情報を格納するリスト
* @param schem スキーマ名
* @throws SQLException DB例外
*/
private static void loadPrimaryKeyList(
DatabaseMetaData dbmd,
String tableName,
ArrayList list,
String schem)
throws SQLException {
//ユニークインデックスで主キーを定義している場合は↓のコードを実行
ResultSet rs = dbmd.getIndexInfo(null, schem, tableName, true, true);
//プライマリーキーで主キーを定義している場合は↓のコードのコメントを外す
//ResultSet rs = dbmd.getPrimaryKeys(null, schem, tableName);
while (rs.next()) {
String s = rs.getString("COLUMN_NAME");
if (s != null) {
list.add(s);
}
}
rs.close();
}
/**
* ResultSetを標準出力する
* @param rs 標準出力するResultSet
* @throws SQLException DBエラー
*/
private static void printResultSet(ResultSet rs) throws SQLException {
while (rs.next()) {
ResultSetMetaData rm = rs.getMetaData();
for (int i = 1; i <= rm.getColumnCount(); i++) {
System.out.println(
i + ":" + rm.getColumnName(i) + ":" + rs.getString(i));
}
}
}
}
package tool.db;
import java.util.ArrayList;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* Table情報を格納する
* @author yamarou
*/
public class TableVO implements Comparable {
/** テーブル名 */
private String name;
/** 列名リスト */
private ArrayList columns = new ArrayList();
/** 主キー名リスト */
private ArrayList primaryKeys = new ArrayList();
/**
* オブジェクトの文字列表現を返します。
*/
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
/**
* 列名リストを返す
* @return 列名リスト
*/
public ArrayList getColumns() {
return columns;
}
/**
* テーブル名を返す
* @return テーブル名
*/
public String getName() {
return name;
}
/**
* 主キー名リストを返す
* @return 主キー列名リスト
*/
public ArrayList getPrimaryKeys() {
return primaryKeys;
}
/**
* テーブル名を設定する
* @param string テーブル名
*/
public void setName(String string) {
name = string;
}
/**
* オブジェクトを比較する。
*/
public int compareTo(Object o) {
TableVO table = (TableVO) o;
return this.name.compareTo(table.getName());
}
}
■実行
java tool.db.SQLGeneretor
■実行結果
c:/TEMP/sql.txtにテキストファイルが出来上がります。
[sql.txt]
SELECT 〜
INSERT 〜
DELETE 〜
UPDATE 〜
・
・
・
続く
INSERT 〜
DELETE 〜
UPDATE 〜
・
・
・
続く
この仕組みを使えばORマッピングクラスや、
JUnitのテストコード等、DB関連のコードを
自動生成したりといったことが出来ると思います。
なかなか使えそうですね♪