Table Reservation:
I want to give the guest the amount he has to pay and I have a procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `CalculateTotal`(IN ID int ,OUT total float)
BEGIN
SELECT (DATEDIFF(reservation.endDate, reservation.startDate) * room.price)
INTO total
FROM (select * from guest Where guestID = ID) As R , Room, Reservation
WHERE Room.roomNumber = Reservation.roomNumber AND Reservation.guestID =
R.guestID;
END
System.out.println("Enter your ID guest:");
int gID = keyboard.nextInt();
rs = stmt.executeQuery("Select guestID from reservation where guestID = "+gID+";");
if(rs.next())
{
stmt.executeQuery("call calculateTotal(" + gID + ", #result);");
rs = stmt.executeQuery("Select firstName, lastName, roomNumber, class, price, startDate, endDate, #result as TotalPrice From (Guest join (Reservation join Room on (Reservation.roomNumber = Room.roomNumber)) on Reservation.guestID = Guest.guestID ) where reservation.guestID = "+gID+";");
while(rs.next())
System.out.println("Name: "+ rs.getString("firstName")+" "+ rs.getString("lastName")+ " Room Number:"+ rs.getInt("roomNumber") + " Class:"+ rs.getString("class")+ " Price:"+ rs.getFloat("price")+ rs.getDate("startDate")+" EndDate: "+ rs.getDate("endDate")+ " Total Price: "+ rs.getFloat("TotalPrice") + "р.");
}
End I have an error
java.sql.SQLIntegrityConstraintViolationException: Column 'roomNumber' in field list is ambiguous
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.StatementImpl.executeQuery(StatementImpl.java:1200)
at com.jdbc.Main.main(Main.java:172)
172 raw is rs = stmt.executeQuery("Select firstName, lastName...
May be somehow improve the procedure and code?
The exception, as #Abra and #Eric Brandt point out, is that you're querying multiple tables, and you would need to prefix the fields with the table names, or aliases, to prevent references to ambiguous columns (e.g. columns that have the same name in different tables)
Since, you're looking to improve the code, I would make a few suggestions.
As #Strawberry suggests, the procedure is not necessary if the end goal is just to query for a reservation. While it may be possible that you intend to expand the functionality of the procedure, it's generally better IMHO to avoid them for simple calculations, aggregations, etc. that could be done in plain SQL.
Concatenating strings together to form SQL, while using user input, can be dangerous. It's safe in this case, since keyboard.nextInt() would prevent a SQL injection attack, but you might consider using prepared statements to get additional level of protection, and prepared statements can have other advantages as well. For example, some databases will cache the runplan, which can be significant when a more complex query will be run a number of times.
You may always want to user an "on" clause in your joins. Otherwise you will get a cross join, which may not be what you want.
Once you get beyond simple examples, embedding SQL in Java code can become tedious, and externalizing it as a resource can be very useful, and sets up for templating the SQL, or having variations to deal with quirks between different databases (e.g. MySQL vs Oracle vs Postgres, etc.).
There are a whole bunch of opinions out there about things like natural keys vs surrogate keys, or lowerCamel columns vs lower snake case columns, when to use or avoid stored procedures, etc., but rather than attempt an exhaustive "best practices" list,which would just be my opinion anyway, here's an alternate example that's not too far from your original example (i.e. ignoring ORM's, etc)
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Hotel {
private static Connection connection;
private static ResultSet rs;
private static Scanner keyboard;
private static Statement stmt;
public static void main(String[] args) throws Exception {
if (args.length != 3) {
// Note: Don't pass passwords on the command line in real life.
System.err.println("Usage: java Hotel <dbUrl> <dbUser> <dbPwd>");
return;
}
// Initial set up
keyboard = new Scanner(System.in);
connection = DriverManager.getConnection(args[0], args[1], args[2]);
stmt = connection.createStatement();
// Do it the original way (from the post).
// orig();
// Do it a slightly different way.
anotherWay();
}
public static void orig() throws Exception {
System.out.println("(orig) Enter your ID guest:");
int gID = keyboard.nextInt();
rs = stmt.executeQuery("Select guestID from Reservation where guestId = " + gID + ";");
if (rs.next()) {
stmt.executeQuery("call calculateTotal(" + gID + ", #result);");
rs = stmt.executeQuery(
"Select firstName, lastName, Reservation.roomId as roomNumber, class, price, startDate, endDate, #result as TotalPrice From (Guest join (Reservation join Room on (Reservation.roomId = Room.id)) on Reservation.guestID = Guest.id ) where Reservation.guestID = "
+ gID + ";");
while (rs.next())
System.out.println(" Name: " + rs.getString("firstName") + " " + rs.getString("lastName")
+ "\n Room Number: " + rs.getInt("roomNumber") + "\n Class: " + rs.getString("class")
+ "\n Price: " + String.format("%.2f", rs.getFloat("price")) + "\n Start Date: "
+ rs.getDate("startDate") + "\n EndDate: " + rs.getDate("endDate") + "\n Total Price: "
+ String.format("%.2f", rs.getFloat("TotalPrice")));
}
}
public static void anotherWay() throws Exception {
System.out.println("(anotherWay) Enter your guest ID:");
int guestId = keyboard.nextInt();
// Get the SQL as a String. Normally this would be standardized into
// a utility, so it wouldn't be so messy.
String sql = new String(
Files.readAllBytes(Paths.get(Hotel.class.getResource("select_reservation.sql").toURI())));
// Prepare the statement
PreparedStatement ps = connection.prepareStatement(sql);
// Set the parameter
ps.setInt(1, guestId);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
printResult(rs);
}
rs.close();
ps.close();
}
public static void printResult(ResultSet rs) throws Exception {
System.out.println(
" Name: " + rs.getString("firstName") + " " + rs.getString("lastName")
+ "\n Room Number: " + rs.getInt("roomNumber")
+ "\n Class: " + rs.getString("class")
+ "\n Price: " + String.format("%.2f", rs.getFloat("price"))
+ "\n Start Date: " + rs.getDate("startDate")
+ "\n EndDate: " + rs.getDate("endDate")
+ "\n Room Charge: " + String.format("%.2f", rs.getFloat("roomCharge"))
+ "\n Extra: " + String.format("%.2f", rs.getFloat("extra"))
+ "\n Total Price: " + String.format("%.2f", rs.getFloat("totalPrice"))
);
}
}
Run it like this (don't use passwords on the command line in real life)...
java Hotel <url> <user> <pwd>
The output should look like this for guest 1...
(anotherWay) Enter your guest ID:
1
Name: Alice Smith
Room Number: 1
Class: premium
Price: 100.00
Start Date: 2020-05-15
EndDate: 2020-05-22
Room Charge: 700.00
Extra: 350.00
Total Price: 1050.00
and this for guest 2...
(anotherWay) Enter your guest ID:
2
Name: Bob Jones
Room Number: 2
Class: base
Price: 75.00
Start Date: 2020-05-15
EndDate: 2020-05-22
Room Charge: 525.00
Extra: 0.00
Total Price: 525.00
Here's the externalized SQL...
select
Guest.firstName,
Guest.lastName,
Room.id as roomNumber,
Room.class,
Room.price,
Reservation.startDate,
Reservation.endDate,
(DATEDIFF(Reservation.endDate, Reservation.startDate) * Room.price) as roomCharge,
IFNULL(extra.charges,0) as extra,
((DATEDIFF(Reservation.endDate, Reservation.startDate) * Room.price)
+ IFNULL(extra.charges,0)) as totalPrice
from
Reservation
inner join Guest on Reservation.guestId = Guest.id
inner join Room on Reservation.roomId = Room.id
left join ( -- Use subquery to calculate extra charges.
select -- Could be more efficient by specifying key.
guestId,
sum(price) as charges
from
RoomService
inner join Service on RoomService.serviceId = Service.id
group by
guestId) extra on extra.guestId = Guest.id
where
Reservation.guestId = ?;
Here's a full MySQL schema if you want to try it out...
-- Make it idempotent
drop database if exists hotel;
create database hotel;
-- Create the tables (using lowerCamel cols)
CREATE TABLE hotel.Guest (
id int AUTO_INCREMENT ,
firstName varchar(40),
lastName varchar (40),
PRIMARY KEY (id)
);
CREATE TABLE hotel.Room (
id int AUTO_INCREMENT ,
class varchar(40),
price decimal(13,2),
PRIMARY KEY (id)
);
CREATE TABLE hotel.Reservation (
id int AUTO_INCREMENT ,
guestId int,
roomId int,
startDate date,
endDate date,
PRIMARY KEY (id)
);
CREATE TABLE hotel.Service (
id int AUTO_INCREMENT ,
name varchar(40),
price decimal(13,2),
PRIMARY KEY (id)
);
CREATE TABLE hotel.RoomService (
id int AUTO_INCREMENT ,
guestId int,
roomId int,
serviceId int,
PRIMARY KEY (id)
);
INSERT INTO hotel.Guest (id,firstName,lastName) VALUES (1,'Alice','Smith');
INSERT INTO hotel.Guest (id,firstName,lastName) VALUES (2,'Bob','Jones');
INSERT INTO hotel.Guest (id,firstName,lastName) VALUES (3,'Mallory','Adams');
INSERT INTO hotel.Room (id,class,price) VALUES (1,'premium',100.00);
INSERT INTO hotel.Room (id,class,price) VALUES (2,'base',75.00);
INSERT INTO hotel.Room (id,class,price) VALUES (3,'budget',50.00);
INSERT INTO hotel.Reservation (id,guestId,roomId,startDate,endDate) VALUES (1,1,1,'2020-05-15','2020-05-22');
INSERT INTO hotel.Reservation (id,guestId,roomId,startDate,endDate) VALUES (2,2,2,'2020-05-15','2020-05-22');
INSERT INTO hotel.Service (id,name,price) VALUES (1,'WIFI',100.00);
INSERT INTO hotel.Service (id,name,price) VALUES (2,'Safe',100.00);
INSERT INTO hotel.Service (id,name,price) VALUES (3,'Washing clothes',450.00);
INSERT INTO hotel.Service (id,name,price) VALUES (4,'Food delivery',250.00);
INSERT INTO hotel.RoomService (id,guestId,roomId,serviceId) VALUES (1,1,1,1);
INSERT INTO hotel.RoomService (id,guestId,roomId,serviceId) VALUES (2,1,1,4);
DELIMITER //
CREATE DEFINER=`root`#`localhost` PROCEDURE hotel.CalculateTotal(IN ID int ,OUT total float)
BEGIN
SELECT
(DATEDIFF(Reservation.endDate, Reservation.startDate) * Room.price)
INTO
total
FROM
(select * from Guest Where id = ID) As R ,
Room,
Reservation
WHERE
Room.id = Reservation.roomId
AND Reservation.guestId = R.id;
END //
DELIMITER ;
My question is very simple. I just want to know how to write a create Table statement for MySQL using Java statements where the name of the table is a string.
I know how to insert String values as values of the coloumns using Java. I tried it that way but could not do it. I will show you my code:
String table = "CREATE TABLE table_name'" +
"(SL. No INT not NULL AUTO_INCREMENT, " +
" NAME VARCHAR(100), " +
" YEAR INT not NULL, " +
" IMDB INT not NULL)";
Here instead of table_name I want to input a string variable. The variable name is s2.
Now the Insert into table value is as follows:
myStmt.executeUpdate("insert into l1(id,email,usname,pwd)value('"+(i)+"','"+s1+"','"+s2+"','"+s5+"')");
Here s1,s2,s5 are string values. But this method is not working for Create Table and it is showing syntax error. What is the correct code?
You should remove additional ' sign and change name for SL. No column to somethin else so it looks like
String table = "CREATE TABLE table_name" +
"(slno INT not NULL AUTO_INCREMENT, " +
" NAME VARCHAR(100), " +
" YEAR INT not NULL, " +
" IMDB INT not NULL)"
If your table string is correct you can replace table_name with new name for each table with replace method on string or just use function
public static String getCreateTableQuery(String tableName) {
String table = "CREATE TABLE table_name" +
"(slno INT not NULL AUTO_INCREMENT, " +
" NAME VARCHAR(100), " +
" YEAR INT not NULL, " +
" IMDB INT not NULL)";
String createTableWithNewNameQuery = table.replaceFirst("table_name'", tableName);
return createTableWithNewNameQuery;
}
I am trying to insert data from ArrayLists into a mysql table in Java, however I keep getting the following error: java.sql.SQLException: Data truncated for column 'AAL' at row 1.
Here is some of the code:
stmt = conn.createStatement();
sql = "CREATE TABLE IF NOT EXISTS stocks "
+ "(id INTEGER not NULL AUTO_INCREMENT, date LONGBLOB , " + "time LONGBLOB, "
+ " PRIMARY KEY ( id ))";
stmt.executeUpdate(sql);
System.out.println("Created table in given database...");
for (int i = 0; i < stockList.size(); i++) {
System.out.println(stockList.get(i).getName() + i);
sql = "ALTER TABLE stocks ADD " + stockList.get(i).getName() + " DOUBLE";
stmt.executeUpdate(sql);
}
for (int i = 0; i < stockList.size(); i++) {
System.out.println(i);
sql = "INSERT INTO stocks (id, date, time, " + stockList.get(i).getName() + ") VALUES (NULL, '" + stockList.get(i).getDate() +
"', '" + stockList.get(i).getTime() + "', '" + stockList.get(i).getPrice() + "')";
stmt.executeUpdate(sql);
}
Any help is much appreciated.
You indicated that stockList.get(i).getPrice() is a string, and you are putting quotes around the value in the insert. So you are effectively trying to insert a string value into a DOUBLE column. Normally MySQL will auto convert strings to doubles, however, my suspicion is that at least some of your getPrice() values are not valid doubles. You can try this instead:
... "', " + Double.parseDouble(stockList.get(i).getPrice()) + ")";
..but if some of the prices are not valid doubles, this will fail as well.
There are some issues with your table and query design:
Use DATE, TIME, or DATETIME types for storing dates and times. LONGBLOB is not meant for this.
The data that is truncated is actually the price you're trying to insert into the DOUBLE column. If getPrice() is returning a string, you need to check decimal and thousant separators. MySQL uses . (point) as decimal and , (comma) as thousant separator by default. And do not use quotes in your query.
When dealing with prices, consider using DECIMAL as type. FLOAT and DOUBLE may not be exact.
I've created a very simple table, and am attempting to insert into it. The table exists, but nothing I try to insert sticks; the resultSet is always null. I think I'm auto-incrementing my primary key correctly. Any ideas? Thank you!
String createGenreTableSQL = "CREATE TABLE Genre (GenreID INTEGER NOT NULL GENERATED ALWAYS " +
"AS IDENTITY (START WITH 1, INCREMENT BY 1), genreName varchar(60))";
statement.executeUpdate(createGenreTableSQL);
String prepGenreInsert = "INSERT INTO Genre(genreName) VALUES (?)";
psInsert = conn.prepareStatement(prepGenreInsert);
allStatements.add(psInsert);
psInsert.setString(1,"Television");
psInsert.setString(1,"Movies");
psInsert.setString(1,"VideoGames");
psInsert.setString(1,"Animes");
String fetchAllDataSQL = "SELECT * from Genre";
resultSet = statement.executeQuery(fetchAllDataSQL);
while (resultSet.next()) { //resultSet shows null
int genreID = resultSet.getInt("genreID");
String genreName = resultSet.getString("genreName");
System.out.println("GenreID:" + genreID + " Name: " + genreName);
}
The setString method simply binds the given value to the given parameter index. It does not actually execute the query. I believe what you want to do is
psInsert.setString(1,"Television");
psInsert.execute();
psInsert.setString(1,"Movies");
psInsert.execute();
psInsert.setString(1,"VideoGames");
psInsert.execute();
psInsert.setString(1,"Animes");
psInsert.execute();
first sry if i do any grammar mistakes my motherlanguage is not English.
Here im printing out all the customers from database, and for each table row i add delete link which takes customers code as a parameter. When clicking on the link it should delete one row but it deletes all the customers with the same code, any ideas how can i delete just one row even if there are customers with same code?
for(Customers customer : customers)
{
String param = customer.getCode();
request.setAttribute("value3",param);
out.println(
"<tbody><tr> "
+ "<td>"+ customer.getFirst_name()+" "+"</td>"
+ "<td>"+ customer.getSurname()+" "+"</td>"
+ "<td>"+ customer.getCode()+" " +"</td></br>"
+ " "+"<td><a href='"+request.getContextPath()+"/Search?id="+param+"'>Delete</a></td></tr>"
);
dao.deleteCustomer(request.getParameter("id"));
}
Deleteing method :
public void deleteCustomer(String code)
{
try{
pst = getConnection().prepareStatement("delete from customer where "
+" code = '"+code +"'");
pst.executeUpdate();
}catch(Exception e)
{
throw new RuntimeException(e);
} finally {
closeResources();
}
}
Schema file :
CREATE SEQUENCE seq1 AS INTEGER START WITH 1;
CREATE TABLE customer (
id BIGINT NOT NULL PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
surname VARCHAR(255) NOT NULL,
code VARCHAR(255) NOT NULL,
);
INSERT INTO customer VALUES(NEXT VALUE FOR seq1,'Jane','Doe','123');
INSERT INTO customer VALUES(NEXT VALUE FOR seq1,'John','Doe','456');
INSERT INTO customer VALUES(NEXT VALUE FOR seq1,'Jack','Smith','789');
You should delete the customer based on their ID in the database rather than their code.
A user ID should always be unique, where a code may not be.
An example of your data might help further.
Try:
pst = getConnection().prepareStatement("DELETE FROM customer WHERE code = '"+ code + "' and id IN (select * from (SELECT MAX(c.id) FROM customer c where code = '"+ code + "') as d)");