How to add to INSERT INTO PRIMARY KEY AND FOREIGN KEY - java

So i have two tables: locations and employees i want locations_id to be the same in employees.locations_id, I am trying to make it all in one statement
the erros is this You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO employees(employees_id, locations_id) VALUES('e1598','')' at line 1
String sql = " INSERT INTO locations( locations_id , username, password, id, type_of_id, first_name, last_name, phone, email, date_of_birth, address, sex ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"
**Error here --->** + "INSERT INTO employees(employees_id,locations_id) VALUES (?,SELECT locations_id FROM locations INNER JOIN employees ON locations.locations_id =employees.locations_id)";
try {
MicroModelGUI micro = new MicroModelGUI();
PreparedStatement consulta = micro.connection.prepareStatement(sql);
consulta.setString(1, tflid.getText());
consulta.setString(2, tfuser.getText());
consulta.setString(3, tfpass.getText());
consulta.setString(4, tfid.getText());
consulta.setString(5, tftoid.getText());
consulta.setString(6, tffirst.getText());
consulta.setString(7,tflast.getText());
consulta.setString(8,tfphone.getText());
consulta.setString(9,tfemail.getText());
consulta.setString(10,tffdn.getText());
consulta.setString(11,tfaddress.getText());
consulta.setString(12,tfsex.getText());
consulta.setString(13,tfeid.getText());
int resultado = consulta.executeUpdate();

You should be using an INSERT INTO ... SELECT here:
INSERT INTO employees (employees_id, locations_id)
SELECT ?, l.locations_id
FROM locations l
INNER JOIN employees e ON l.locations_id = e.locations_id;
To the ? placeholder you would bind a value from your Java code. Note that while your version of SQL might support putting a scalar subquery into a VALUES clause, it is likely that your exact version would cause an error, as it would return more than one row.

Related

Using two INSERT statements for two different tables in a single SQL statement

I have two tables one is users and other is students. I wish to execute a single SQL statement that inserts into both these tables different values. The id is PK for users and I have referenced the same id in the student table with (id INTEGER NOT NULL PRIMARY KEY REFERENCES users(id))
I tried this:
INSERT INTO users (id, password, firstName, lastName, emailAddress, enrollDate, lastAccess, enabled, type) VALUES (100222222, 'password', 'Robert', 'McReady', 'bob.mcready#dcmail.ca', '2016-03-07', '2015-09-03', true, 's')
AND
INSERT INTO students (id, programCode, programDescription, year) VALUES (100222222, 'a', 'b', 3)
This statement throws syntax error (syntax error at or near "AND"), and I don't understand why. I am connecting this SQL prepared statement through Java so my code is like this:
String sqlInsert = "INSERT INTO users (id, password, firstName, lastName, emailAddress, enrollDate, lastAccess" + ", enabled, type) VALUES (100222222, 'password', 'Robert', 'McReady', 'bob.mcready#dcmail.ca', " + "'2016-03-07', '2015-09-03', 's', true)";
Is there a way so I can code this sqlInsert statement to insert into two different tables with different values in a single sql statement in Java?
If the goal is to avoid repeating the value for the ID column, this could be done using a data modifying CTE:
with data (id, password, firstname, lastname, emailaddress, enrolldate, lastaccess, enabled, type) as (
VALUES (100222222, 'password', 'Robert', 'McReady', 'bob.mcready#dcmail.ca', '2016-03-07', '2015-09-03', true, 's')
), new_user as (
INSERT INTO users (id, password, firstname, lastname, emailaddress, enrolldate, lastaccess, enabled, type)
select id, password, firstname, lastname, emailaddress, enrolldate, lastaccess, enabled, type
from data
)
INSERT INTO students (id, programcode, programdescription, year)
select id, 'a', 'b', 3
from data;
Postgres also allows to run two statements with a single Statement.executeUpdate() call as long as they are delimited with a ; (not with an "AND")
String sqlInsert = "insert into users (...) values (...);" +
"insert into students (...) values (...);";
However the above is not the correct approach. You should not put the actual values directly into your SQL strings.
It's better (safer and more efficient) to use a PreparedStatement. As the ID will be stored in a Java variable, there is no need to repeat it.
This has the additional advantage that you can pass the values for the DATE columns as proper LocalDate instances rather than strings. If you insert both in a single transaction you make sure that either both rows or nothing is inserted.
Something like the following (without proper error handling and cleanup!)
String usersInsert = "INSERT INTO users
(id, password, firstname, lastname, emailaddress, enrolldate, lastaccess, enabled, type)
VALUES (?,?,?,?,?,?,?,?,?)";
String studentInsert = "INSERT INTO INSERT INTO students (id, programcode, programdescription, year) values (?,?,?,?)";
// Start a transaction
connection.setAutocommit(false);
int id = 100222222;
PreparedStatement stmtUsers = connection.prepareStatement(usersInsert);
stmtUsers.setInt(1, id);
stmtUsers.setString(2, "password");
stmtUsers.setString(3, "Robert");
...
stmtUsers.setObject(6, LocalDate.of(2016,3,7), Types.DATE);
stmtUsers.setObject(7, LocalDate.of(2015,9,3), Types.DATE);
...
stmtUsers.executeUpdate();
PreparedStatement stmtStudent = connection.prepareStatement(studentInsert);
stmtStudent.setInt(1, id);
stmtStudent.setString(2, "a");
...
stmtStudent.executeUpdate();
// end the transaction
connection.commit();
stmtStudent.close();
stmtUsers.close();
It is not possible to combine two insert statements with an AND. They need to be seperated.
In your code, depending on the language/framework, you can make one transaction for both statements, so they will be comitted at the same time to your DB.

ANDROID STUDIO / SQLiteLog: (1) near "LIMIT": syntax error

I am trying to delete the duplicates that I am getting in my database using DELETE function of my SQL with LIMIT 1 but it is showing me the "LIMIT" syntax error .
myDatabase.execSQL("CREATE TABLE IF NOT EXISTS users (name VARCHAR , age INT(3))");
myDatabase.execSQL("INSERT INTO users (name, age) VALUES ('Vaishant', 21)");
myDatabase.execSQL("INSERT INTO users (name, age) VALUES ('Tommy',4)");
myDatabase.execSQL("DELETE FROM users WHERE name = 'Vaishant' LIMIT 1");
Can someone tell me why I am getting this error and how to correct it ?
SQLite does not support LIMIT in a DELETE statement.
Use a subquery that returns the rowid of a row that contains the name that you search for:
String sql = "DELETE FROM users WHERE rowid = (SELECT rowid FROM users WHERE name = 'Vaishant' LIMIT 1)";
myDatabase.execSQL(sql);
If you want to delete the duplicate names and keep only 1, then you can do this:
DELETE FROM users
WHERE NOT EXISTS (SELECT 1 FROM users u WHERE u.name = users.name AND u.rowid < users.rowid)
or:
DELETE FROM users
WHERE rowid NOT IN (SELECT MIN(rowid) FROM users GROUP BY name)
In your delete statement you are using limit with Delete query. You should use it as below:
First add id column as primary key in your table
myDatabase.execSQL("CREATE TABLE IF NOT EXISTS users (ID INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR , age INT(3))");
change the query of delete as below
myDatabase.execSQL("DELETE FROM users
WHERE id IN
(SELECT id FROM
(SELECT id,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY name) AS row_num FROM users )t
WHERE row_num > 1)");

Proper way to add data to a table in postgreSQL using JDBC?

This is my first post here, if my formatting is not correct/ hard to read, I will change it. Please let me know.
I have been playing with JDBC trying to add basic data to a database, using user input data. The user provides first and last name, email, and a user id is generated using the random function.
The database was created using postgreSQL. I'm trying to add to a table called accounts, which contains the following columns - user_id (integer), first_name (varchar(100)), last_name (varchar(100)), email (varchar(500)).
My program is able to connect to the database successfully, but it's not able to add data to the table.
in the following code, firstName, lastName, and eMail are all strings, while sID is an int.
state = conx.prepareStatement("INSERT INTO accounts VALUES ("+ sID +","+ firstName + "," + lastName + "," + eMail) + ")");
s.executeUpdate();
Normally, I'd hope the data would be added to the table so we can call it a day, but I'm getting an error.
org.postgresql.util.PSQLException: ERROR: column "v" does not exist
Position: 36
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2440)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2183)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:308)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:143)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:120)
at Main.main(Main.java:49)
org.postgresql.util.PSQLException: ERROR: column "v" does not exist
Position: 36
Use ? for parameters instead of concatenating their values. Also, you should name the columns in the INSERT statement. For example:
s = conx.prepareStatement(
"INSERT INTO accounts (id, first_name, last_name, email) " +
"VALUES (?, ?, ?, ?)"
);
s.setInt(1, sID);
s.setString(2, firstName);
s.setString(3, lastName);
s.setString(4, email);
int affectedRows = s.executeUpdate();

Retrieving MySQL stored procs OUT parameters in hibernate

I have a question regarding what is the best approach to using stored procs in mysql with hibernate. I am running mysql version 5.7.14 with hibernate 4.0.0.Final as my ORM tool. Now in mysql database, I have a stored proc defined below:
DROP PROCEDURE IF EXISTS LK_spInsertBaseUser;
DELIMITER $$
CREATE PROCEDURE `LK_spInsertBaseUser`(f_name VARCHAR(255),
l_name VARCHAR(255),
n_name VARCHAR(255),
pwd VARCHAR(255),
OUT user_id INT)
BEGIN
## Declaring exit handler
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
#state = RETURNED_SQLSTATE,
#errno = MYSQL_ERRNO,
#message = MESSAGE_TEXT;
SET #full_error = CONCAT('ERROR ', #errno, ' (', #state, '): ', #message);
SELECT #full_error;
ROLLBACK;
END;
START TRANSACTION;
IF NOT EXISTS(SELECT first_name
FROM base_user
WHERE first_name = f_name AND last_name = l_name AND nick_name = n_name)
THEN
INSERT INTO base_user (first_name, last_name, nick_name, password)
VALUES (f_name, l_name, n_name, pwd);
SET user_id = LAST_INSERT_ID();
SELECT #user_id AS userId;
ELSE
SET #exiting_user = CONCAT('Base user already exists');
SELECT #exiting_user;
ROLLBACK;
END IF;
END $$
DELIMITER ;
As we can see from my proc above, if the insert works, the id of the new record is stored in the OUT parameter user_id and we do a select as well. However, if there is a error I print out the error. Now, here is the heart of the question. I ran into a few hiccups when trying to execute the stored proc via hibernate. I finally came up with a solution but I am not convinced it is the right solution. Let me go through the various attempts i went through.
Attempt 1:
I decided to use #NamedNativeQueries annotation for my BaseUser Entity (note: base_user sql table maps to BaseUser pojo entity). Below is the code snippet:
#SqlResultSetMapping(name="insertUserResult", columns = { #ColumnResult(name = "userId")})
#NamedNativeQueries({
#NamedNativeQuery(
name = "spInsertBaseUser",
query = "CALL LK_spInsertBaseUser(:firstName, :lastName, :nickName, :password, #user_id)",
resultSetMapping = "insertUserResult"
)
})
Now, in the Dao class I created a method to invoke the named query via the session object like so:
Query query = getSession().getNamedQuery("spInsertBaseUser")
.setParameter("firstName", user.getFirstName())
.setParameter("lastName", user.getLastName())
.setParameter("nickName", user.getNickName())
.setParameter("password", user.getEncodedPassword());
Object data = query.list();
System.out.println(data);
Now this works partially. It inserts the data into the database however the data object is null. It seems the out parameter isn't set or even retrieved. I then decided to use a different approached and use the CallableStatement object. Below is the code:
Attempt 2:
getSession().doWork((Connection connection) -> {
CallableStatement statement = connection.prepareCall("{call LK_spInsertBaseUser(?, ? , ?, ?, ?)}");
statement.setString(1, user.getFirstName());
statement.setString(2, user.getLastName());
statement.setString(3, user.getNickName());
statement.setString(4, user.getEncodedPassword());
statement.registerOutParameter(5, Types.INTEGER);
statement.executeUpdate();
System.out.println(statement.getInt(5));
});
This works and it is fairly quick however, I have read that the instantiation of the prepareCall is expensive so I guess the real question is, is this solution the acceptable standard or should I continue to figure out the NamedNativeQuery approach in the quest for better performance?

SQL INSERT with loop with multiple rows

I'm trying to insert skeleton data into a database using jdbc.
So far my code is:
Statement st=con.createStatement();
String sql = "INSERT INTO student (studentid, titleid, forename, familyname, dateofbirth) "
+ "VALUES (1, 1, 'forename1', 'surname1', '1996-06-03');";
I need to create 100 entries for this and I'm not too sure how to go about doing it.
All I want is the student id, titleid, forename and familyname to increment by 1 until it reaches 100 entries with those rows filled in, date of birth doesn't need to be altered. I'm asking how to do a loop for this
General answer - You should use PrepareStatement instead of Statement and execute as batch.
Common way to insert multiple entry or execute
String sql = "INSERT INTO student (studentid, titleid, forename, familyname, dateofbirth) "
+ "VALUES (?, ?, ?, ?, ?);";
ps = connection.prepareStatement(SQL_INSERT);
for (int i = 0; i < entities.size(); i++) {
ps.setString(1, entity.get...());
...
ps.addBatch();
}
ps.executeBatch();
Important Note:
Why you should use PrepareStatement Over Statement
SQL Injection Example
There are two ways to do this. You can put your insert query inside a loop or you can put your loop inside an insert query. I have found that the better method depends on the database engine (but I've never used postresql) and the number of records you want to insert. You could bump up against the maximun query length or number of parameters or something.
The following code sample is ColdFusion, but it is intended to show the general idea of having a loop inside a query. You would have to write equivalent code in java.
<cfquery>
insert into yourtable
(field1
, field2
, etc)
select null
, null
, null
from SomeSmalllTable
where 1 = 2
<cfloop>
union
select <cfqueryparam value="#ValueForField1#">
, <cfqueryparam value="#ValueForField#">
, etc
</cfloop>
</cfquery>

Categories

Resources