Column in field list is ambiguous - java

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 ;

Related

Creating a unique listing_no (Java/PostgreSQL)

I am working on a option in a Menu function that posts the car for the sale in a database. The option asks for the user to enter the year, make, condition and price, which is then inserted into the table car_sale in the database. However, a unique listing_no must also be generated during this option. I cannot define my tables to uniquely generate the 10 digit number the option but I must code the program to insert uniquely generated listing_no. Below you will find the code of me trying to do this, however the code only works in Oracle but I cannot use Oracle. I can only PostGreSQL and Java. Therefore, my problem arises as the functions and relations I am using cannot be used in PostGre.
Code to Generate Listing No:
public int generateListingNo() throws SQLException
{
int listingSeq = 0;
Statement select = connection.createStatement();
result = select.executeQuery("select (to_char(sysdate,'yyyymmdd')||AUDIT_SEQ.NEXTVAL)valnext from dual");;
if(result.next())
{
listingSeq = result.getInt(1);
}
int seq = listingSeq;
return seq;
}
Code in The Option Function to insert the lisitng_no generated from generateListingNo()
public void option() throws SQLException
{
int listing_no = generateListingNo();
// insert information into books_for_sale table
sql_insert = "INSERT INTO car_sale VALUES(" + listing_no +", "
+ "'" + year + "'" + ", " +
"'" + make + "'" +", " +
"'" + condition + "'" + ", "
+ price + ")";
Erros I am Getting:
Exception in thread "main" org.postgresql.util.PSQLException: ERROR: relation "dual" does not exist
Position: 69 at
org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:217)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:421)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:318)
at org.postgresql.jdbc.PgStatement.executeQuery(PgStatement.java:281)
Creating the car_sale table
create table car_sale(
listing_no int not null,
year varchar not null,
make varchar not null,
condition varchar not null,
price decimal(12,2) not null,
primary key (listing_no),
Change you query for generateListingNo as below:
select q from (select (to_char(now(),'yyyymmdd') || NEXTVAL('AUDIT_SEQ') )q )sq
or
select (to_char(now(),'yyyymmdd') || NEXTVAL('AUDIT_SEQ')) as newseqval
or on your cocde:
public int generateListingNo() throws SQLException
{
int listingSeq = 0;
Statement select = connection.createStatement();
result = select.executeQuery("select (to_char(now(),'yyyymmdd') || NEXTVAL('AUDIT_SEQ')) as newseqval");;
if(result.next())
{
listingSeq = result.getInt(1);
}
int seq = listingSeq;
return seq;
}
Since you dont have sequence :
Either create sequence using below query:
CREATE SEQUENCE public."AUDIT_SEQ"
INCREMENT 1
START 1
MINVALUE 1
MAXVALUE 9223372036854775807
CACHE 1;
or use UUID:
public String generateListingNo() throws SQLException
{
return UUID.randomUUID().toString();
}
your table structure will need to change :
create table car_sale(
listing_no varchar not null,
year varchar not null,
make varchar not null,
condition varchar not null,
price decimal(12,2) not null,
primary key (listing_no),
For PostgreSQL, you have to call query this way from java :
SELECT nextval('ACCOUNT_TRANSACTION_NO')

Mysql in Java: Data truncated for column 'AAL' at row 1 error

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.

Android: Delete all sqlite rows NOT IN top 5

I have a database for my leaderboard. Currently, I insert all scores into my leaderboard, and select the 5 highest scores to show on my app. I think it would take up too much room to never delete the other scores, so I would like to delete them. How can I do this?
Here's how I select the top 5 scores, ranked first by score and second by time if score is equal:
public Cursor gethmLeaderboard(SQLiteDatabase db){
String[] columns = {TableInfo.LB_RANK, TableInfo.LB_SCORE, TableInfo.LB_TIME};
Cursor c = db.query(TableInfo.TABLE_HM, null, null, null, null, null, TableInfo.LB_SCORE + " DESC, " + TableInfo.LB_TIME + " ASC", "5");
return c;
}
Here's how I create my table:
public String CREATE_HMQUERY = "CREATE TABLE " + TableInfo.TABLE_HM + "("
+ TableInfo.LB_RANK + " INTEGER PRIMARY KEY AUTOINCREMENT DEFAULT 1 ," + TableInfo.LB_SCORE +
" INT,"+ TableInfo.LB_TIME + " VARCHAR );";
I want to delete all rows NOT IN that query. How can I do that?
Edit:
I tried this query:
public String DEL_ALLBUTES = "DELETE FROM " +
TableInfo.TABLE_HM + " WHERE " +
TableInfo.LB_RANK + " NOT IN (SELECT " +
TableInfo.LB_RANK + " FROM " +
TableInfo.TABLE_HM + " ORDER BY " +
TableInfo.LB_SCORE + " DESC, " +
TableInfo.LB_TIME + " ASC LIMIT 5);";
In this format:
db.rawQuery(DEL_ALLBUTES, null);
But when I check the database there are still tons of rows so it doesn't work.
Your table needs to have some unique ID. Use that to identify the rows you want to keep:
DELETE FROM ES
WHERE ID NOT IN (SELECT ID
FROM ES
ORDER BY Score DESC, Time ASC
LIMIT 5);
You can create temp table insert top 5 score into temp table and delete all table then insert temp table into main table.
CREATE TEMP TABLE TempES AS SELECT
ID
FROM
ES
ORDER BY
Score DESC,
Time ASC
LIMIT 5;
DELETE
FROM
ES;
INSERT INTO ES SELECT
*
FROM
TempES;
DROP TABLE TempES;

How to retrieve a data between dates

I have 2 tables. A booking table and a room table. In the booking table I have the following columns: BookingID StartDate EndDate CustomerID RoomID
In the Room table I have the following columns: RoomID RoomSize
I am creating a booking system. I want to be able to query the database where I am able to get a list of rooms that are booked between 2 dates which are also based on size (small, medium or large) types.
E.g. if user clicks on small room and enters dates between 2010-02-02 to 2010-02-25 then 4 should appear as my database contains 4 small rooms that are booked between those dates.
This is what I have so far:
String sqlStatement = "select RoomID from Booking where RoomID in (select Room.RoomID from Room where Room.RoomSize is " + type + ") AND ((Booking.StartDate between "+ startD +" AND " + endD + ") OR (Booking.EndDate between "+ startD + " AND " + endD + "))";
This is the error I am getting:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 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 'Medium) AND ((Booking.StartDate between 2016-02-09 AND 2016-02-09) OR (Booking.E' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
I am new to SQL and having trouble doing this. Also, is my logic right?
startD and endD represents the dates that the user has entered and typeOfRoom represent the type of the room the user wants to book; e.g. eithier Small, Medium or Large
Do not use string concatenation to insert user-supplied values into SQL, especially for strings. It will leave you open to SQL Injection attacks, and SQL syntax issues. Use a PreparedStatement.
Also, replace is with =.
String sql = "select RoomID" +
" from Booking" +
" where RoomID in (" +
"select Room.RoomID" +
" from Room" +
" where Room.RoomSize = ?" +
")" +
" and ((Booking.StartDate between ? AND ?)" +
" or (Booking.EndDate between ? AND ?))";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, type);
stmt.setDate (2, startD);
stmt.setDate (3, endD);
stmt.setDate (4, startD);
stmt.setDate (5, endD);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
// code here
}
}
}
The date handling look ok I think, but you need to quote the type string in the statement. And you should not use is, just use normal =
String sqlStatement = "select RoomID from Booking where RoomID in (select Room.RoomID from Room where Room.RoomSize = '" + type + "') AND ((Booking.StartDate between "+ startD +" AND " + endD + ") OR (Booking.EndDate between "+ startD + " AND " + endD + "))";
Can you try if this statement works? I have replaced the 'is' keyword with '=' operator and put all the variables between "".
String sqlStatement = "select RoomID from Booking where RoomID in (select Room.RoomID from Room where Room.RoomSize = \"" + type + "\") AND ((Booking.StartDate between \""+ startD +"\" AND \"" + endD + "\") OR (Booking.EndDate between \""+ startD + "\" AND \"" + endD + "\"))";

How to Append existing integer in DB ACCESS with new integer from java

for example
i have a table in access name : Sale
in sale table have 2 column: productID,sale_Quantity
existing data in ACESS:
productID = G001 | sale_Quantity =2
in java user input G001 and sale_quantity 3.. so i want to update the data in ACCESS so that
`sale_Quantity= 2+3..` total is 5..
how the sql statement?
tq..
this is my 2 sql statement that i have try in java..
st.executeUpdate ("UPDATE Product(productID,sale_quantity) SET sale_quantity=sale_quantity+quantity[i] WHERE productID('"+productID[i]+"');"); // UPDATE ROWS IN PRODUCTS
st.executeUpdate("UPDATE SALE SET sale_quantity=sale_quantity+quantity[i] WHERE productID='productID[i]'");
Make sure you correct the SQL String as below. In your code you need to append the values as below.
String sql = "UPDATE SALE SET "
+ " sale_quantity = (sale_quantity + " + quantity[i] + ") "
+ " WHERE productID = " + productID[i];
st.executeUpdate(sql).

Categories

Resources