Как создать таблицу, если она не существует с использованием Derby Db
Я новичок в apache derby
и я не могу заставить работать
CREATE TABLE IF NOT EXISTS table1 ...
как это может быть достигнуто в MySql
и т.д. я получаю 'Syntax error: Encountered "NOT" at line 1, column 17.'
когда я пытаюсь запустить это SQL
утверждение в моем Java
программа.
Я проверил на странице документации для Derby Db Create Statements, но не смог найти такой альтернативы.
9 ответов
Создать таблицу, поймать SQLException
и проверьте код состояния SQL.
Полный список кодов ошибок можно найти здесь, но я не смог найти Table <value> already exists
; это, вероятно X0Y68
, Код, который вам нужен X0Y32
,
Просто запустите код один раз и напечатайте код ошибки. Не забудьте добавить тест, чтобы убедиться, что код работает; таким образом, вы можете ловить изменения в коде ошибки (не должно происходить...).
В моих проектах я обычно добавляю вспомогательный класс со статическими методами, чтобы я мог написать:
} catch( SQLException e ) {
if( DerbyHelper.tableAlreadyExists( e ) ) {
return; // That's OK
}
throw e;
}
Другой вариант - запустить SELECT
против таблицы и проверьте код состояния (который должен быть 42X05
). Но это вторая команда, которую вам нужно отправить, и она не предлагает никакой дополнительной информации.
Что еще хуже, он может потерпеть неудачу по другим причинам, чем "Таблица не существует", поэтому "создать и игнорировать ошибку" лучше IMO.
Derby не поддерживает этот sql-оператор.
В моей программе я анализирую все таблицы из базы данных в набор и проверяю, существует ли таблица там. Как это:
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");
}
Выполняемый вами запрос не поддерживается 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;
}
Уловка заключается в том, чтобы указать имя таблицы в верхнем регистре, иначе вы не сможете найти имя таблицы в метаданных.
Следуя примеру Аарона Дигуллы с 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;
}
}
Другое решение с 2 условиями:
Желание отбрасывать таблицу перед каждым созданием, при этом то же самое присутствует в файле.sql
Используете Spring и, следовательно, хотите использовать spring-test как зависимость Maven, ваша жизнь может стать намного проще с ее аннотацией @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
);
И у вас есть тестовый класс BlahTest, который должен запустить этот sql перед тем, как выполнить какой-либо тест, просто добавьте следующую аннотацию @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 {
...
}
@SqlConfig указанного значения атрибута конфигурации обладает магией, которая заставляет его пропускать ошибки оператора отбрасывания в случае, если таблица не существует. Я считаю, что он был написан специально для этих типов баз данных, которые не поддерживают IF EXISTS для удаления / создания таблиц (что на самом деле должно делать дерби, даже если в данный момент он не является частью стандарта SQL)
Этот ответ слишком поздно, но может быть кому-то полезен.
Следующий код Java (стандартный JDBC) можно использовать для проверки, существует ли таблица или нет, и если она существует, то ее можно создать;
String query = "SELECT TRUE FROM SYS.SYSTABLES WHERE TABLENAME = ? AND TABLETYPE = 'T'"; // Leave TABLETYPE out if you don't care about it
PreparedStatement ps = connection.prepareStatement(query);
ps.setString(1, "TABLE_NAME"); // Must be in capitals
ResultSet rs = ps.executeQuery();
if ( rs.next() && rs.getBoolean(1) )
{
// Table exists
}
else
{
// Table does NOT exist ... create it
}
Вот решение, которое вы можете написать в 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. Другое дело - правильно обрабатывать ошибки.
Убедитесь, что класс скомпилирован и помещен в путь к классу виртуальной машины, в которой будет работать база данных.
Напишите свой 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;
???
- прибыль
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.and и обязательно прокомментируйте e.printstacktace(); если он уже существует, он не показывает ошибку, в противном случае он создает таблицу..!!