私はApache derby
と私は仕事をすることができないようです
CREATE TABLE IF NOT EXISTS table1 ...
MySql
などで達成できるように、私は'Syntax error: Encountered "NOT" at line 1, column 17.'
、SQL
プログラムでこのJava
ステートメントを実行しようとすると、.
ドキュメントページで Derby Db Create Statements を確認しましたが、そのような代替案を見つけることができませんでした。
テーブルを作成し、SQLException
をキャッチして、SQLステータスコードを確認します。
エラーコードの完全なリストは次のとおりです ここ が見つかりませんでした 必要なコードはTable <value> already exists
;おそらくX0Y68
。X0Y32
。
コードを1回実行し、エラーコードを出力します。コードが機能することを確認するためのテストを追加することを忘れないでください。このようにして、エラーコードの変更をキャッチできます(発生してはなりません...)。
私のプロジェクトでは、通常、静的メソッドを含むヘルパークラスを追加して、次のように記述できるようにします。
} catch( SQLException e ) {
if( DerbyHelper.tableAlreadyExists( e ) ) {
return; // That's OK
}
throw e;
}
別のオプションは、テーブルに対してSELECT
を実行し、ステータスコード(42X05
)。しかし、これは送信する必要がある2番目のコマンドであり、追加の情報を提供しません。
さらに悪いことに、「テーブルが存在しない」以外の理由で失敗する可能性があるため、「作成して無視するエラー」の方がIMOの方が優れています。
Derbyはそのsql-statementをサポートしていません。
私のプログラムでは、データベースのすべてのテーブルを解析してセットにして、そこにテーブルが存在するかどうかを確認します。このような:
private Set<String> getDBTables(Connection targetDBConn) throws SQLException
{
Set<String> set = new HashSet<String>();
DatabaseMetaData dbmeta = targetDBConn.getMetaData();
readDBTable(set, dbmeta, "TABLE", null);
readDBTable(set, dbmeta, "VIEW", null);
return set;
}
private void readDBTable(Set<String> set, DatabaseMetaData dbmeta, String searchCriteria, String schema)
throws SQLException
{
ResultSet rs = dbmeta.getTables(null, schema, null, new String[]
{ searchCriteria });
while (rs.next())
{
set.add(rs.getString("TABLE_NAME").toLowerCase());
}
}
テーブルが存在するかどうかを確認するには:
Connection con = DriverManager.getConnection(url);
ResultSet res = con.getMetaData().getTables(null, Schema_Name, table_name.toUpperCase(), null);//Default schema name is "APP"
if(res.next())
{
//do some thing;
}else{
JOptionPane.showMessageDialog(null, table_name +" not exist");
}
すべてのテーブル名を表示するには:
Connection con = DriverManager.getConnection(url);
ResultSet res = con.getMetaData().getTables(null, Schema_Name, "%", null);//Default schema name is "APP"
while(res.next())
{
JOptionPane.showMessageDialog(null, res.getString(3) + " is exist");//Show table name
}else{
JOptionPane.showMessageDialog(null, table_name +" not exist");
}
Aaron DigullaのリードをDerbyUtils
クラスでリードして、テーブルが存在するかどうかを確認します。これが私が思いついた解決策です。
呼び出しクラス
public void createTable(String name) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = daoFactory.getConnection();
String sql = String.format(SQL_CREATE_TABLE, name);
preparedStatement = connection.prepareStatement(sql, Statement.NO_GENERATED_KEYS);
preparedStatement.execute();
} catch (SQLException e) {
if(DerbyUtils.tableAlreadyExists(e)) { //check if the exception is because of pre-existing table.
logger.info("Talbe " + name + " already exists. No need to recreate");
} else {
logger.error(e.getMessage() + " : " + e.getStackTrace());
}
} finally {
close(connection, preparedStatement); //DAOUtils silently closes
}
}
DerbyUtils
public class DerbyUtils {
public DerbyUtils() {
//empty constructor -- helper class
}
public static boolean tableAlreadyExists(SQLException e) {
boolean exists;
if(e.getSQLState().equals("X0Y32")) {
exists = true;
} else {
exists = false;
}
return exists;
}
}
私はこれに回答が付いていることを知っていますが、誰かがチェックする別の方法が必要な場合に備えて、とにかく投稿したいと思いました。ここでは、ブール値を返すメソッドでテーブルのメタデータを確認します。存在する場合はtrue、存在しない場合はfalseです。彼らが探しているなら、それが他の人を助けることを願っています。
private static Connection conn = null;
private static Statement st = null;
private static ResultSet rs = null;
private static DatabaseMetaData dmd;
public Boolean firstTime()
{
try
{
dmd = conn.getMetaData();
rs = dmd.getTables(null, "APP", "LOGIN", null);
return !rs.next();
} catch (SQLException ex)
{
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}
実行中のクエリはDerby dbではサポートされていません。代わりに、テーブルの名前がわかっていれば、テーブルが存在するかどうかを簡単に見つけることができます。
public boolean isTableExist(String sTablename) throws SQLException{
if(connection!=null)
{
DatabaseMetaData dbmd = connection.getMetaData();
ResultSet rs = dbmd.getTables(null, null, sTablename.toUpperCase(),null);
if(rs.next())
{
System.out.println("Table "+rs.getString("TABLE_NAME")+"already exists !!");
}
else
{
System.out.println("Write your create table function here !!!");
}
return true;
}
return false;
}
キャッチはテーブル名を大文字で指定することです。それ以外の場合、メタデータでテーブル名を見つけることができません。
2つの条件を持つ別のソリューション:
作成する前にdrop tableを実行します。同じものが.sqlファイルに存在します。
Springを使用していて、Mavenの依存関係としてspring-testを使用することをいとわない場合は、@ Sqlアノテーション
したがって、最初にこれを依存関係としてpomに追加します。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
<scope>test</scope>
</dependency>
次に、ドロップするSQLがあると仮定して、テーブルaをファイルに作成しますrectangle.sql:
DROP TABLE rectangles;
CREATE TABLE rectangles (
id INTEGER NOT NULL PRIMARY KEY,
width INTEGER NOT NULL,
height INTEGER NOT NULL
);
そして、実行するテストを実行する前にこのSQLを実行する必要があるテストクラスBlahTestがあり、次の@ Sqlアノテーションをクラスに追加するだけです。
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.context.jdbc.SqlConfig.ErrorMode;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=XyzClientConfig.class)
@Sql(scripts="/sql/ddl/rectangle.sql", config=@SqlConfig (errorMode=ErrorMode.IGNORE_FAILED_DROPS))
public class BlahTest {
...
}
指定されたconfig属性値の@ SqlConfigには、スキップする魔法がありますテーブルが存在しない場合、dropステートメントエラー。私はそれがドロップ/テーブル作成のためにIF EXISTSをサポートしていないこれらのタイプのデータベースを特に対象とするように書かれていると信じています(ダービーは本当に、現時点ではSQL標準の一部ではありません)
try {
connection.createStatement().execute("create table channels(channel varchar(20),topic varchar(20))");
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
Createステートメントをtry-catch。で囲み、e.printstacktace();をコメント化してください。すでに存在する場合はエラーは表示されず、それ以外の場合はテーブルが作成されます。
SQLでスクリプトを作成できるソリューションを次に示します。
次のようなクラスを作成します。
package user.fenris.spring.extensions;
import Java.sql.Connection;
import Java.sql.DriverManager;
import Java.sql.SQLException;
import org.Apache.commons.logging.Log;
import org.Apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
public class SqlCreateIfNotExists {
private static Log log = LogFactory.getLog(SqlCreateIfNotExists.class);
public static void createTableIfNotExists(String tablename, String ddl) throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:default:connection");
if (conn != null) {
JdbcTemplate template = new JdbcTemplate(new SingleConnectionDataSource(conn, true));
int count = template.queryForInt("select count(*) from SYS.SYSTABLES where TABLENAME = ?", tablename);
log.debug("Count: " + count);
if (count == 0) {
log.debug("Executing sql statement: " + ddl);
template.execute(sql);
} else {
log.debug("Table exists. Skipping sql execution...");
}
}
}
}
注:Springを使用する必要はありません。直接JDBCで記述できますが、正しく実行する方法を知っている必要があります。 (読者のための演習として残しました)。また、これを書き換えて、ddlパラメータからテーブル名を解析できます。もう1つは、適切なエラー処理を行うことです。
クラスがコンパイルされ、データベースが実行されるVMのクラスパスに配置されていることを確認してください。
SQLスクリプトを記述します。
-- 2K for ddl statement should be enough. You want more? Seriously?
create procedure CreateTableIfNotExists(in tablename varchar(128), in ddl varchar(2048))
PARAMETER STYLE Java
MODIFIES SQL DATA
language Java
external name 'user.fenris.spring.extensions.SqlCreateIfNotExists.createTableIfNotExists';
call CreateTableIfNotExists('TABLE_NAME_MUST_BE_ALL_CAPS',
'create table TABLE_NAME_MUST_BE_ALL_CAPS
(entry_id int generated always as identity not null,
entry_timestamp timestamp,
username varchar(128) not null,
note varchar(1024) not null,
primary key (entry_id))');
-- you don't have to drop this, but you would have to create a similar
-- procedure to create the CreateTableIfNotExists procedure,
-- (i.e. CreateProcedureIfNotExists) but then it's turtles all the way down
drop procedure CreateIfNotExists;
???