I am working on a flight reservation system where users can log into an account to make reservations.
In my sql database, I have a table called ticket where there is a column called seatnum. I have another table called aircraft and that has a column called seats.
In my jsp page, I want to assign a random seat number to a person buying a ticket, but I can only assign so many seats before the seats in the aircraft table gets full.
I want to declare a global counter for the number of seats I assign to a particular flight, but my counter keeps being reset to 0 but I can't declare a static variable in a jsp. What should I do instead?
CREATE TABLE `ticket` (
`cid` int,
`flight_num` int,
`ticket_num` int NOT NULL AUTO_INCREMENT,
`seatnum` int,
PRIMARY KEY (`ticket_num`),
FOREIGN KEY (`flight_num`) REFERENCES flight (`flight_num`) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (`cid`) REFERENCES user (`cid`) ON UPDATE CASCADE ON DELETE CASCADE
)
CREATE TABLE `aircraft` (
`2letterid` varchar(2),
`aircraft_num` int,
`seats` int,
PRIMARY KEY (`2letterid`, `aircraft_num`),
FOREIGN KEY(`2letterid`) REFERENCES `airline` (`2letterid`)
)
int counter = 0;
String seats = "select seats from flight join aircraft(flight_num) " +
"where flight_num = " + flightNum;
if (counter > seats) {
enter a waiting list
}
You can store the counter in a hidden field or in the session.
Related
I created a java class with the same name as a table from a SQL database, and using the retrieved information from that table I created multiple objects out of that Java class, and stored them inside An ArrayList.
CREATE TABLE `orderdetails` (
`orderNumber` int(11) NOT NULL,
`productCode` varchar(15) NOT NULL,
`quantityOrdered` int(11) NOT NULL,
`priceEach` decimal(10,2) NOT NULL,
`orderLineNumber` smallint(6) NOT NULL,
PRIMARY KEY (`orderNumber`,`productCode`),
KEY `productCode` (`productCode`),
CONSTRAINT `orderdetails_ibfk_1` FOREIGN KEY (`orderNumber`) REFERENCES `orders` (`orderNumber`),
CONSTRAINT `orderdetails_ibfk_2` FOREIGN KEY (`productCode`) REFERENCES `products` (`productCode`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
tuples have repeating orderNumbers, for example:
(10100,'S18_1749',30,'136.00',3),
(10100,'S18_2248',50,'55.09',2),
(10100,'S18_4409',22,'75.46',4),
Each tuple is then turned into a java object of the class with the same name as the table, and to be stored inside an Arraylist.
public ArrayList<OrderDetails> getOrders(String tableName) throws SQLException{
ArrayList<OrderDetails>od=new ArrayList<OrderDetails>();
try {
String query="SELECT * FROM "+tableName;
Statement s= con.createStatement();
ResultSet rs= s.executeQuery(query);
while(rs.next()) {
int orderNumber=rs.getInt("orderNumber");
String productCode=rs.getString("productCode");
int quantityOrdered=rs.getInt("quantityOrdered");
double priceEach=rs.getDouble("priceEach");
int orderLineNumber=rs.getInt("orderLineNumber");
OrderDetails temp=new OrderDetails(orderNumber, productCode, quantityOrdered, priceEach, orderLineNumber);
od.add(temp);
}
}
catch(SQLException e) {
System.out.println("SQL exception happened while retriving data, close connection");
throw new RuntimeException(e);
}
return od;
}
I am trying to Loop through the ArrayList and output the total amount of value (priceEach times quantityOrdered )for each checkNumber. But if I simply just loop through the ArrayList one object by object, that isn't going to work. As I will simply see the sum for each object, not each checkNumber, on the console.
ArrayList<OrderDetails>od= this.getOrders("orderdetails");
for(int i=0;i<=od.size();i++) {
System.out.println(od.get(i).getPriceEach()*od.get(i).getQuantityOrdered());
}
I'm expecting something like this to show up on console (no repeating checkNumber)
CheckNumber 10100, total value: 8494.62 (if you add up the product between priceEach and quantityOrdered for the three tuples shown above earlier in my question is the rsult)
In short is there a way for me to combine objects with repeating attributes into one?
I apologize if my question seems very vague and you don't know exactly what the problem is.
It would be greatly appreciated if you try to reach out for me and ask for further clarifications, sometimes it is very difficult to describe a problem that's too specific..
Why not simply do the computation in the database? SQL is a set-based language that is very efficient at this type of operation, compared to an iterative loop in Java.
Consider the following aggregate query:
select orderNumber, sum(quantityOrdered * priceEach) totalValue
from mytable
group by orderNumber
This gives you one record per order, with the total value over all corresponding rows.
I currently have a student grade/class input program which accepts the following inputs: Student ID, First Name, Last Name, Class ID, Class Name, Grade Point, and Letter Grade.
For obvious reasons I would like to limit the user from entering Duplicate records for the same student/course (student id, class id) pair, as well as duplicate records for the same student id and first name/last name. (Two students should not be able to fill the same ID.
Currently I have a very basic method to add this data, what is the best method to implement my intentions?:
db=openOrCreateDatabase("STUDENTGRADES", Context.MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS CUSTOMER_TABLE(studentid VARCHAR, fname VARCHAR, lname VARCHAR, classid VARCHAR, classname VARCHAR, pointgrade INTEGER, lettergrade VARCHAR);");
add.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(fname.getText().toString().trim().length()==0||
lname.getText().toString().trim().length()==0 || studentid.getText().toString().trim().length()==0)
{
showMessage("Error", "Please enter First & Last Name and Student ID");
return;
}
db.execSQL("INSERT INTO CUSTOMER_TABLE VALUES('"+studentid.getText()+"','"+fname.getText()+"','"+lname.getText()+"','"+classid.getText()+"','"+classname.getText()+
"','"+pointgrade.getText()+"','"+lettergrade.getText()+"');");
showMessage("Success", "Student Record added successfully");
clearText();
}
});
You can use method insertWithOnConflict with CONFLICT_IGNORE flag, if you don't want to replace this rows. If there is no same raw, method returns -1, so you can handle it
EDITED:
At first, you need to create UNIQUE rows (in your case - class id and student id):
db.execSQL("CREATE TABLE YOURDB ("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "STUDENTID TEXT UNIQUE, "
+ "CLASSID TEXT UNIQUE);");
then create variable for checkking result of method
int k = 0;
try to insert values and get result into our k
try {
SQLiteDatabase db = dbHelper.getWritableDatabase();
k = db.insertWithOnConflict("YOURDB",null, contentValues, SQLiteDatabase.CONFLICT_IGNORE);
db.close();
}
and, finally check your variable (I was made all in AsyncTask, so method for check is located in onPostExecute() method)
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (k==-1){
Toast.makeText(getApplicationContext(), "Same raws", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "not same raws", Toast.LENGTH_SHORT).show();
}
}
if there are coincidence of values, DataBase will not be updated and your k get -1 value, so, you can make Toast or something else to handle it
EDIT 2:
about ContentValue initialize:
at first, you should get values, for example, you get them from editText:
String studentIdUpdate = studentEditText.getText().toString();
String classIdUpdate = classEditText.getText().toString();
and then create ContentValues variable and put values into it
ContentValues contentValues = new ContentValues();
contentValues.put("STUDENTID", studentIdUpdate);
contentValues.put("CLASSID", classIdUpdate);
When you use a simple flat file containing all that information, it is easy to get things out of sync. That is, same student ID associated with multiple names, or same class ID associated with multiple class names. And extra work is required to keep things in sync if a student name or class name needs to be changed. Not to mention the need to minimize duplicate records. The first step to sorting out this mess is to redesign your database. For the data you mention here, I would use three tables:
Students
ID Name
------------ ---------------------------------
1 Henry
2 Molly
3 George
Classes
ID Name
------------ --------------------------------
1 Ohio History
2 US History
3 World History
Grades
StudentID ClassID Grade LetterGrade
------------ ------------ ------------ ------------
1 1 98 A
2 3 85 B
3 2 77 C
1 2 85 B
3 3 92 A
Set the primary key on Students and Classes to the ID field, and for Grades to a composite of (StudentID, ClassID). This will prevent a given student from having multiple grades for the same class, and will also prevent multiple students from having the same id. Same for classes.
Now your user interface can let the user choose a student, choose a class, then assign a grade. The letter grade can be calculated, or keyed.
Here is how I would define the tables:
create table if not exists students (
id integer primary key autoincrement,
last_name varchar,
first_name varchar);
create table if not exists classes (
id integer primary key autoincrement,
name varchar);
create table if not exists grades (
student_id integer not null,
class_id integer not null,
point_grade integer,
letter_grade varchar,
primary key (student_id, class_id),
foreign key (student_id) references students,
foreign key (class_id) references classes)
without rowid;
The foreign key constraints prevents grades from being entered for non-existent students or classes, and also prevents students or classes with grades from being deleted. There are other clauses to allow you to delete all grades for a student or class if a student or class is deleted.
The relationship between the students and classes is called a many-to-many relationship. That means that many students can be assigned to a single class, and many classes can be assigned to a single student. Not that the only keys that are auto increment are the student and class ID's. The ID's in the grades file reference the associated student and class rows. In the above data example,
Henry has grades for two classes (Ohio History (98) and US History (85)), Molly has grades for only one class (World History (85)), and George has grades for two classes (US History (77) and World History (92)).
You can create a single view that combines the students classes and grades like this:
create view if not exists student_view (
last_name, first_name, class_name, point_grade, letter_grade)
as (
select last_name, first_name, name, point_grade, letter_grade
from students
join grades on grades.student_id = students.id
join classes on classes.id = grades.class_id;
I'm currently making a code that uses a database. This is the class of the database:
public class ScriptDLL {
public static String getCreateTableCliente(){
StringBuilder sql = new StringBuilder();
sql.append(" CREATE TABLE IF NOT EXISTS CLIENTE (");
sql.append(" CODIGO INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,");
sql.append(" NOME VARCHAR (250) NOT NULL DEFAULT (''),");
sql.append(" ENDERECO VARCHAR (255) NOT NULL DEFAULT (''),");
sql.append(" EMAIL VARCHAR (200) NOT NULL DEFAULT (''),");
sql.append(" TELEFONE VARCHAR (20) NOT NULL DEFAULT ('') )");
return sql.toString();
}
}
Ok, so i want to make a SQLite code to set CODIGO back to 1. How could i write this code?
Thanks!
I would suggest to increment the version by 1 and the old table is dropped and new table is created, this will avoid failure due to uniqueness constraint if records already exist in the table(you take care of migration ofcourse). If you have specific need just to reset codigo then try the below code. It resets the value to 1 in the internal sqllite record SQLITE_SEQUENCE.
Refer documentation which explains more about autoincrement and SQLITE_SEQUENCE : https://sqlite.org/autoinc.html
public static String resetKey(){
return "UPDATE SQLITE_SEQUENCE SET seq = 1 WHERE name = CLIENTE";
}
If this is just a one-off then just Delete the App's data, or uninstall the App and rerun.
If you want to do this frequently (ignoring the fact that relying upon the column being specific values most likely indicates a flaw in the design) then:-
You could DROP and recreate the table as is often done in the onUpgrade method of the Database Helper. Doing this in the onUpgrade method could be problematic/complicated if you had multiple tables and potentially even more complicated if you had multiple versions.
You could have a specific method such as :-
public void resetCODIGO() {
this.getWritableDatabase.execSQL("DROP TABLE IF EXISTS CLIENTE;");
this.getWritableDatabase.execSQL(getCreateTableCliente());
}
DROPing a table will result in the respective row in the sqlite_sequence table being deleted by SQLite.
The sqlite_sequence table has a row per table that has a column with AUTOINCREMENT (only 1 allowed per table).
the sqlite_sequence table has two defined columns name for the table name and seq for the last inserted sequence number.
Another solution that would involve DROP and CREATE BUT does involve updating the sqlite_sequence table could be to delete all rows from the table and to then delete the respective row in the sqlite_sequence table.
Thus alternately you could have :-
public void resetCODIGO() {
this.getWritableDatabase.delete("CLIENTE");
String whereclause = "name=?";
String[] whereargs = new String[]{"CLIENTE"};
this.getWritableDatabase.delete(
"sqlite_sequence",
whereclause,
whereargs
);
}
Note the above code is in-principle code and hasn't necessarily been tested, so it may contain some errors.
This is my scenario. I have a Parent table Files_Info and a child table Files_Versions.
create table files_info(
id bigint primary key,
name varchar(255) not null,
description varchar(255) not null,
last_modified TIMESTAMP,
latest_version integer default 0 not null
);
create table files_versions(
id bigint primary key,
file_id bigint references files_info(id),
version integer not null,
location text not null,
created TIMESTAMP,
unique(file_id, version)
);
This is mainly to track a file and its various versions. When the user initiates a new file creation (not yet uploaded any version of the file), an entry is made to the files_info table with basic info like name, description. The latest_version will be 0 initially.
Then when the user uploads the first version, an entry is created in the files_versions table for that file_id and the version
value is set as parent's latest_version + 1. Parent's latest_version is now set to 1.
The user can also upload an initial version of the file when he/she initiates a new file creation. In that case, parent record
will be created with latest_version as 1 and also the corresponding version 1 child record.
I do not know how to design this using JPA / Hibernate.
I wrote my Entity and Repository classes and the save methods seem to work independently. But I do not know how to do the simultaneously latest_version updates.
Can this be done using JPA / Hibernate? Or should it be a database trigger?
A trigger is a valid option, but It can be done using JPA/Hibernate.
I'll suggest to use #PrePersist annotation on some method defined at the files_versions entity ... This method will be called by JPA when you execute: EntityManager.persist(FileVersion); and it can be use to update entity's derivative attributes ... In your case, will be the sum of the file last_version + 1 ... Example:
#Entity
#Table(name = "files_info")
public class FileInfo {
}
#Entity
#Table(name = files_versions)
public class FileVersion {
... //some attributes
#Column(name = "version")
private int version;
#ManyToOne
#JoinColumn(name = "file_id")
private FileInfo fileInfo;
... //some getters and setters
#PrePersist
private void setupVersion() {
// fileInfo should be set before of calling persist()!
// fileInfo should increase its lastest Version before of calling persist()!
this.version = this.fileInfo.getLastVersion();
}
}
I want to create a java class that contains only 1 column from OneToMany ManyToOne etc. type connection not the whole row.
How can I do that?
(I'm not sure that I could express myself so I made an example)
TABLE e_skill
(
id int NOT NULL AUTO_INCREMENT,
skill_name VARCHAR (20) NOT NULL,
PRIMARY KEY (id)
);
TABLE t_person
(
id int NOT NULL AUTO_INCREMENT,
user_id int NOT NULL,
primary_skill int,
PRIMARY KEY (id),
FOREIGN KEY (primary_skill) REFERENCES e_skill(id)
);
TABLE t_secondaryskills
(
id int NOT NULL AUTO_INCREMENT,
t_person_id int NOT NULL,
skill_name int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (t_person_id) REFERENCES t_person(id),
FOREIGN KEY (skill_name) REFERENCES e_skill(id)
);
public enum Skill {
...
}
#Entity
#Table(name = "t_person")
public class Employee {
#Id
#GeneratedValue
private Integer id;
#ManyToOne
#Enumerated(EnumType.STRING)
//????????
//get skill_name column from e_skill
//????????
private Skill primarySkill;
#OneToMany
#Enumerated(EnumType.STRING)
//????????
//get skill_name column from e_skill
//????????
private Set<Skill> secondarySkills;
//getters setters
}
The only way I could do it now is to create a Entity to represent the e_skill table, I want to avoid that, because I only need 1 column from it.
If I understand your question correctly, you can't do what you want because of the secondary skills (because it's a collection). You can only map the primary skill name though using the #SecondaryTable annotation.
When you map things using an ORM there's no such thing as I only want a column in this scenario as you're mapping Objects, and usually in your objects you don't want to replicate data (unless they are outside your domain model). If this is unacceptable for you, I suggest you to take a look at other tools like myBtais, which gives you full control on the data you get back.
So bottom line, map your skill as an entity and live with it even if it has many columns, or choose a different tool (but not an ORM).