So I am creating a JDBC program using a connection. This is my first time becoming familiar with this kind of programming so please excuse me if my question comes across as "dumb". But I have been stuck on this issue for a while. I am created 4 new tables. It compiles fine but when I run it, I get a "ERROR: relation "joke" already exists". When I remove the createTableJoke prepared statement, I get the same error ("ERROR: relation "gift" already exists") for my gift table. This continues for all my statements. What am I doing wrong and what is the logic behind why PostgreSQL does this? I have included my code below:
private static void createTables() throws SQLException {
PreparedStatement createTableJoke = null;
PreparedStatement createTableGift = null;
PreparedStatement createTableHat = null;
PreparedStatement createTableCracker = null;
Connection conn = null;
try {
conn = getDBConnection();
createTableJoke = conn.prepareStatement("CREATE TABLE Joke ( jid INTEGER PRIMARY KEY, joke CHAR(200) NOT NULL, royalty FLOAT NOT NULL);");
createTableJoke.executeUpdate();
createTableGift = conn.prepareStatement("CREATE TABLE Gift ( gid INTEGER PRIMARY KEY, description CHAR(100) NOT NULL, price FLOAT NOT NULL);");
createTableGift.executeUpdate();
createTableHat = conn.prepareStatement("CREATE TABLE Hat ( hid INTEGER PRIMARY KEY, description CHAR(100) NOT NULL, price FLOAT NOT NULL);");
createTableHat.executeUpdate();
createTableCracker = conn.prepareStatement("CREATE TABLE Cracker (cid INTEGER PRIMARY KEY, name CHAR(20) NOT NULL, jid INTEGER REFERENCES Joke(jid), gid INTEGER REFERENCES Gift(gid), hid INTEGER REFERENCES Hat(hid), saleprice NUMERIC CHECK (saleprice > 0), quantity INTEGER NOT NULL);");
createTableCracker.executeUpdate();
} catch (SQLException e){
System.out.println(e.getMessage());
}
finally {
if ((createTableJoke != null) && (createTableGift != null) && (createTableHat != null) && (createTableCracker != null)){
createTableJoke.close();
createTableGift.close();
createTableHat.close();
createTableCracker.close();
}
if (conn != null) {
conn.close();
}
}
}
There are two cases:
You don't care about keeping the existing table if there is one. In this case, issue "DROP TABLE IF EXISTS Joke" before creating it. This will ensure the table is deleted, it will not fail when the table is not there.
You care about the existing content of your tables. In this case, issue a "CREATE TABLE IF NOT EXISTS Joke" ... instead of your plain CREATE TABLE. This will ensure the table is there, and if it already exists, it will not be created. Also note, if you change the structure in your create statement and the table exists, the change in structure does not apply.
This kind of errors means, that all this table were already created. Use pgAdmin (on Microsoft Windows operating systems it usually goes along with PostgreSQL installation) or psql client to connect to the database and check table existence.
Related
I'm working with Java JDBC with Apache Derby data base.
I have a table called `company`` with the values :
id, comp_name, password, email.
This method should create a new row of company with name, password, and email received from the user but the ID should be given automatically from the database and increment itself each time a new company is added to the database.
I just can't figure out how to make this work, I obviously get a error
"column 'ID' cannot accept a NULL value."
because the update occours before the ID is setted.
Code:
public void createCompany(Company company) {
Connection con = null;
try {
con = ConnectionPool.getInstance().getConnection();
String sql = "INSERT INTO company (comp_name, password, email) VALUES (?,?,?)";
PreparedStatement pstmt = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, company.getCompName());
pstmt.setString(2, company.getPassword());
pstmt.setString(3, company.getEmail());
pstmt.executeUpdate();
ResultSet rs = pstmt.getGeneratedKeys();
rs.next();
company.setId(rs.getLong(1));
pstmt.getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionPool.getInstance().returnCon(con);
}
During creation of that table you have to write following DDL
CREATE TABLE MAPS
(
comp_id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
comp_name VARCHAR(24) NOT NULL,
password VARCHAR(26)
)
Ref : https://db.apache.org/derby/docs/10.0/manuals/develop/develop132.html
You're doing almost everything right, you just need to let the database assign an unique ID to each inserted row:
CREATE TABLE my_table (
id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
...
);
A problem could be that you made a mistake by creating your table.
You could create your table like this:
CREATE TABLE company
(
ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
comp_name VARCHAR(50),
email VARCHAR(50),
password VARCHAR (50)
)
IF you want other values to be not NULL you could add NOT NULL to their lines:
password VARCHAR (50) NOT NULL
Delte your old table and execute the the SQl above on your DB. After that you can use your code without changes.
I have a DB schema that creates several tables and fills them with data. I want to check whether db contains corresponding tables or not during app start. I could check for db file existence, but H2 creates db if it doesn't exist. So the only way, I think, is to check for tables existence.
Here is the code of how I initialize DB:
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:database/svc", "sa", "");
Statement st = conn.createStatement();
st.execute("CREATE TABLE IF NOT EXISTS table1 (id INT PRIMARY KEY AUTO_INCREMENT NOT NULL, name VARCHAR(100), record INT, record_date DATE, UNIQUE(name))");
st.execute("CREATE TABLE IF NOT EXISTS table2 (id INT PRIMARY KEY AUTO_INCREMENT NOT NULL, name VARCHAR(100), record INT, record_date DATE, UNIQUE(name))");
st.execute("CREATE TABLE IF NOT EXISTS daily_record_stat (id INT PRIMARY KEY AUTO_INCREMENT NOT NULL, date DATE, table1_id INT, table1_record INT, table2_id INT," +
" table2_record INT, total_record INT);");
st.execute("ALTER TABLE daily_record_stat ADD FOREIGN KEY (table1_id) REFERENCES table1(id);");
st.execute("ALTER TABLE daily_record_stat ADD FOREIGN KEY (table2_id) REFERENCES table2(id);");
st.execute("INSERT INTO table1 VALUES(1, 'non_existed_stub', 0, NULL)");
st.execute("INSERT INTO table2 VALUES(1, 'non_existed_stub', 0, NULL)");
conn.close();
As you see, I check for table existence before creation using IF NOT EXISTS statement. But then I run at the problem with ALTER and INSERT - these commands don's allow IF usage.
I tried to do the following:
Connection conn = DriverManager.getConnection("jdbc:h2:database/svc", "sa", "");
ResultSet meta = conn.getMetaData().getTables(null, null, "table1", null);
if(meta.next()) {
//do something
}
But meta.next() is false.
So how to check whether table schema is initialized? Or maybe this should be done some other way?
Not sure if that's what you mean by saying to check programmatically, buy you can try to use DatabaseMetaData.getTables(). This call will return ResultSet which you'll have to check programmatically. You can see what fields are returned in this ResultSet in corresponding section here. And meta data itself can be obtained by conn.getMetaData().
Following code should return all tables which names start with 'TABLE':
ResultSet meta = conn.getMetaData().getTables(null, null, "TABLE%", new String[]{"TABLE"});
while (meta.next()) {
System.out.println(meta.getString(3));
}
Note that you have to specify table name pattern in upper case. Also it's good to pass table types that you need, although it is optional.
This is a check I used to (re)create the H2 database:
// IMPORTANT A sorted list of table names.
private static final String[] REQUIRED_TABLES = { "USER", ... };
public static final String CREATE_USER = "create table USER (...)";
private boolean schemaExists() throws SQLException {
final List<String> requiredTables = Arrays.asList(REQUIRED_TABLES);
final List<String> tableNames = new ArrayList<String>();
final Connection conn = dataSource.getConnection();
try {
final Statement st = conn.createStatement();
final ResultSet rs = st.executeQuery("show tables");
while (rs.next()) {
tableNames.add(rs.getString("TABLE_NAME"));
}
rs.close();
st.close();
}
finally {
if (conn != null) { conn.close(); }
}
Collections.sort(tableNames);
return tableNames.equals(requiredTables);
}
private void initializeDatabase() throws SQLException {
final Connection conn = dataSource.getConnection();
try {
if (schemaExists()) {
return;
}
final Statement st = conn.createStatement();
st.executeUpdate(CREATE_USER);
conn.commit();
}
finally {
if (conn != null) { conn.close(); }
}
}
And you just call:
initializeDatabase();
Notice the list of required tables has to be sorted because I use List.equals() to compare two lists. It would probably be better to also programmatically sort the required tables list too.
It's not fool-proof (not checking if any table exists and if it should be altered) but it works for me.
Take a look at the SHOW command for other uses.
I have a method which insert a record to mysql database as bellow,
public boolean addOrganization(OrganizationDTO organizationDTO) {
Connection con = null;
try {
String insertOrganizationSQL = "INSERT INTO organizations (org_id, org_name) VALUES(?, ?)";
con = JDBCConnectionPool.getInstance().checkOut();
PreparedStatement insertOrgPS = (PreparedStatement) con.prepareStatement(insertOrganizationSQL);
insertOrgPS.setString(1, organizationDTO.getOrg_id());
insertOrgPS.execute();
return true;
} catch (Exception e) {
JDBCConnectionPool.getInstance().checkIn(con);
logger.error(e.getLocalizedMessage());
e.printStackTrace();
return false;
} finally {
JDBCConnectionPool.getInstance().checkIn(con);
}
}
database table,
CREATE TABLE `organizations` (
`org_id` varchar(5) NOT NULL,
`org_name` varchar(100) DEFAULT NULL,
`sys_dat_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`user` varchar(100) NOT NULL,
PRIMARY KEY (`org_id`)
)
what I need is, when I insert a new record if, that is a duplicate exit the method without trying to insert and inform the user that it is a duplicate record. Is it possible to do without writing another method to search the record before inserting?
I would add a UNIQUE constraint to your table. For example, if org_name needs to be unique:
ALTER TABLE organizations ADD UNIQUE (org_name);
Then observe what's returned when you try to insert a duplicate record through Java. Add code to check for this, and if it occurs, display the message to your user.
Here is the reference documentation for ALTER TABLE.
Thats right, Alter table will surely help.
In your case, let say, both org_id and org_name is there, I would add unique in both, just avoid any confusion later.
I have problem with creating tables by JDBC controller on Oracle database.
When I create table by "creata table...." is ok. Table create and I see that table by SQL Developer. I have method to check if table with that name exist - and it works good.
So when I create table (I try to do commit, too - do not help), table appear in SQL developer but when i check by my method if that table exist i get 'false' (do not exist), when I restart database and run again, my method return 'true'.
I think is a problem with session but I don't now how to get over with that.
enter code here public void prepStatExecuteCreateTable(String name){
String createTable= "Create table "+ name +" (ID NUMBER(*, 0) NOT NULL PRIMARY KEY, CZAS NUMBER(*, 0) NOT NULL, OTWARCIE NUMBER(6, 2) NOT NULL , MAX_KURS NUMBER(6, 2) NOT NULL , MIN_KURS NUMBER(6, 2) NOT NULL , ZAMKNIECIE NUMBER(6, 2) NOT NULL , VOLUMEN NUMBER(*, 0) NOT NULL , FOREIGN KEY(czas) references CZAS(ID))";
PreparedStatement ps=null;
try{
ps = returnConnection().prepareStatement(createTable);
}catch(SQLException e){
System.out.println("Error with preperadStatement(create table): "+ e.getMessage());
}
try{
ps.execute();
returnConnection().commit();
ps.close();
closeConnection();
}
catch(SQLException e){
System.out.println("Error with execute: "+ e.getMessage());
}
}
public boolean ifExistTable(String tablename) throws SQLException{
String sql = "Select TABLE_NAME from user_tables where table_name='"+tablename.toUpperCase()+"' ";
System.out.println(sql);
ResultSet rs =null;
Statement ps = null;
try{
ps = returnConnection().createStatement();
}catch(SQLException e){
System.out.println("Error with preperadSatement(checking): "+ e.getMessage());
}
try{
rs=ps.executeQuery(sql);
while (rs.next()){
System.out.println (rs.getString(1)); // Print col 1
if(rs.getString(1).equals(tablename)){
return true;
}
}
}
catch(SQLException e){
System.out.println("Error with executing checking " +e.getMessage()+ " " + e.getStackTrace());
}
ps.close();
return false;
}
this is how I use in the Main method: (condDB is a object that has above methods)
enter code here String table_name="BBB";
System.out.println(conDB.ifExistTable(table_name));
conDB.prepStatExecuteCreateTable(table_name);
so if I run first, I get message "false" (table do not exist)
and is created (check by SQL developer, table with name 'BBB' appear)
when I run secondly I get message "false" and error message from second method:
Error with execute: ORA-00955: name is already used by an existing object
1) Your ifExistTable function really ought to be using bind variables rather than building the SQL statement using string concatenation if only to avoid SQL injection attacks.
2) Your ifExistTable function is running a query that uses the upper-case value of the tablename that is passed in. But then when you're fetching the data from rs, you're making a case-sensitive comparison with rs.getString(1).equals(tablename). At a minimum, that ought to be equalsIgnoreCase. But there should be no need to do the comparison at all in Java since your SQL statement is already doing it. If the ResultSet has a row, the table exists (or you can write the query as a COUNT(*) and check to see whether the row that is returned has a value of '1').
Perhaps when you created your stored procedure inside the package, you didn't close it with '/'
...
END;
/
so the connection is stucked and the resource is not liberated to be used by other query (which is actually another logical connection). commit will not work as you are performing a DDL sentence which could care less about commiting hehehe
I have two tables in my MySQL database, which were created like this:
CREATE TABLE table1 (
id int auto_increment,
name varchar(10),
primary key(id)
) engine=innodb
and
CREATE TABLE table2 (
id_fk int,
stuff varchar(30),
CONSTRAINT fk_id FOREIGN KEY(id_fk) REFERENCES table1(id) ON DELETE CASCADE
) engine=innodb
(These are not the original tables. The point is that table2 has a foreign key referencing the primary key in table 1)
Now in my code, I would like to add entries to both of the tables within one transaction. So I set autoCommit to false:
Connection c = null;
PreparedStatement insertTable1 = null;
PreparedStatement insertTable2 = null;
try {
// dataSource was retreived via JNDI
c = dataSource.getConnection();
c.setAutoCommit(false);
// will return the created primary key
insertTable1 = c.prepareStatement("INSERT INTO table1(name) VALUES(?)",Statement.RETURN_GENERATED_KEYS);
insertTable2 = c.prepareStatement("INSERT INTO table2 VALUES(?,?)");
insertTable1.setString(1,"hage");
int hageId = insertTable1.executeUpdate();
insertTable2.setInt(1,hageId);
insertTable2.setString(2,"bla bla bla");
insertTable2.executeUpdate();
// commit
c.commit();
} catch(SQLException e) {
c.rollback();
} finally {
// close stuff
}
When I execute the code above, I get an Exception:
MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails
It seems like the primary key is not available in the transaction before I commit.
Am I missing something here? I really think the generated primary key should be available in the transaction.
The program runs on a Glassfish 3.0.1 using mysql-connector 5.1.14 and MySQL 5.5.8
Any help is really appreciated!
Regards,
hage
You missed something for the returned updated id , you have to do like this :
Long hageId = null;
try {
result = insertTable1.executeUpdate();
} catch (Throwable e) {
...
}
ResultSet rs = null;
try {
rs = insertTable1.getGeneratedKeys();
if (rs.next()) {
hageId = rs.getLong(1);
}
...
Instead of using executeUpdate() use execute() and then return the primary key.
http://www.coderanch.com/t/301594/JDBC/java/Difference-between-execute-executeQuery-executeUpdate
But I don't work with db...so I could do a mistake