web-dev-qa-db-fra.com

comment créer une table si elle n'existe pas avec Derby Db

Je suis nouveau à Apache derby et je ne peux pas sembler faire du travail

    CREATE TABLE IF NOT EXISTS table1 ...

comme cela peut être réalisé dans MySql etc. Je reçois un 'Syntax error: Encountered "NOT" at line 1, column 17.' lorsque j'essaie d'exécuter cette instruction SQL dans mon programme Java.

J'ai vérifié la page de documentation pour Derby Db Create Statements , mais je n'ai pas trouvé une telle alternative.

25
midhunhk

Créez la table, récupérez la variable SQLException et vérifiez le code d'état SQL.

La liste complète des codes d'erreur peut être trouvée ici mais je n'ai pas pu trouver Table <value> already exists; c'est probablement X0Y68. Le code dont vous avez besoin est X0Y32.

Il suffit d'exécuter le code une fois et d'imprimer le code d'erreur. N'oubliez pas d'ajouter un test pour vous assurer que le code fonctionne. De cette façon, vous pouvez détecter les changements dans le code d'erreur (cela ne devrait pas arriver ...).

Dans mes projets, j'ajoute généralement une classe d'assistance avec des méthodes statiques pour pouvoir écrire:

} catch( SQLException e ) {
    if( DerbyHelper.tableAlreadyExists( e ) ) {
        return; // That's OK
    }
    throw e;
}

Une autre option consiste à exécuter un SELECT sur la table et à vérifier le code d'état (qui devrait être 42X05). Mais c’est une deuxième commande que vous devez envoyer et qui n’offre aucune information supplémentaire.

Pire encore, il peut échouer pour d'autres raisons que "La table n'existe pas", donc "l'erreur de création et d'ignorance" est préférable.

25
Aaron Digulla

Derby ne supporte pas cette instruction SQL.
Dans mon programme, j'analyse toutes les tables de la base de données dans un ensemble et vérifie si la table y existe. Comme ça:

  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());
    }
  }
12
oers

pour vérifier si la table est existante: 

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");
}

pour afficher le nom de toutes les tables: 

    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");
    }
4
Adham Gamal

Suivant Aaron Digulla, avec une classe DerbyUtils pour vérifier si la table existe, voici la solution que j'ai proposée:

Classe d'appel

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;
    }
}

Voir également

2
blo0p3r

Je sais que cela a été marqué par une réponse, mais au cas où quelqu'un voudrait un autre moyen de vérifier je voulais quand même poster. Ici, je vérifie les métadonnées de la table avec une méthode qui retourne un booléen, true s'il existe, false si ce n'est pas le cas. J'espère que cela aidera les autres s'ils cherchent. 

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
David Bentley

la requête que vous exécutez n'est pas prise en charge par Derby db. Au lieu de cela, si vous connaissez le nom de la table, vous pouvez déterminer si la table existe ou pas assez facilement.

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;
}

Catch consiste à spécifier le nom de la table en majuscule, sinon vous ne pourrez pas trouver le nom de la table dans les métadonnées.  

2
Ankit Chaudhary

Une autre solution avec 2 conditions:

  • Prêt à supprimer la table _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __ ______________________________________________________________ {{}}}

  • Utilisez Spring et vous êtes donc prêt à utiliser spring-test comme dépendance Maven. Votre vie peut devenir beaucoup plus simple avec son annotation @Sql.

Donc, premièrement, en ajoutant ceci comme dépendance à votre pom:

           <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>4.2.5.RELEASE</version>
                <scope>test</scope>
            </dependency>

Deuxièmement, en supposant que vous avez un sql qui tombe, crée une table dans un fichier rectangle.sql:

DROP TABLE rectangles;

CREATE TABLE rectangles (
    id      INTEGER NOT NULL PRIMARY KEY,
    width   INTEGER NOT NULL,
    height  INTEGER NOT NULL
);

Et vous avez une classe de test BlahTest qui devrait exécuter ce sql avant de faire le test, ajoutez simplement l'annotation suivante @Sql à votre classe:

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 { 
...
}

Le @SqlConfig de la valeur d'attribut config spécifiée a la magie qui lui permet d'ignorer les erreurs d'instruction drop au cas où la table n'existe pas. Je pense que cela a été écrit pour cibler spécifiquement ces types de bases de données qui ne supportent pas IF EXISTS pour la suppression/la création de table (ce derby devrait vraiment, même si cela ne fait pas partie du standard SQL pour le moment)

1
Deepak
try {
            connection.createStatement().execute("create table channels(channel varchar(20),topic varchar(20))");
        } catch (Exception e) {
            // TODO Auto-generated catch block
        //  e.printStackTrace();
        }

Entourez l'instruction de création par try-catch.et assurez-vous de commenter e.printstacktace (); S'il existe déjà, il n'affiche pas d'erreur, sinon il crée une table .. !!

0
user3318622

Voici une solution que vous pourrez écrire en SQL.

  1. Créez une classe comme suit:

    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...");              
            }
        }       
    }
    

    }

    Remarque : vous n'avez pas besoin d'utiliser Spring, vous pouvez l'écrire directement dans JDBC, mais vous devez ensuite savoir comment le faire correctement. (Gauche comme un exercice pour le lecteur). De plus, vous pouvez réécrire ceci pour analyser le nom de la table à partir du paramètre ddl. Une autre chose à faire serait de gérer correctement les erreurs.

  2. Assurez-vous que la classe est compilée et placée dans le chemin de classe du VM dans lequel la base de données s'exécutera.

  3. Ecrivez votre script 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;
    
  4. ???

  5. profit
0
Fenris Ulth