JOOQ Update Table with condition of a joined Table - java

I got two Tables like this: Enrollment and Student
create table [LECTURE_DB].[dbo].[ENROLLMENT](
[EXAM_PASSED] bit null default ((0)),
[EXAM_TAKEN] bit null default ((0)),
[YEAR] int not null,
[LECTURE_ID] numeric(19) not null,
[STUDENT_ID] numeric(19) not null,
constraint [PK__ENROLLME__FE468F5B2739D489]
primary key (
[YEAR],
[LECTURE_ID],
[STUDENT_ID]
)
)
create table [LECTURE_DB].[dbo].[STUDENT](
[ID] numeric(19) identity(1, 1) not null,
[FIRSTNAME] varchar(255) null,
[GENDER] varchar(255) null,
[LASTNAME] varchar(255) null,
[YEAR_OF_BIRTH] int null,
constraint [PK__STUDENT__3214EC273493CFA7]
primary key ([ID])
)
I now try to Update a bunch of Enrollments (the exam_passed column) with some lastnames, an Lecture_ID and a year. From this I got the idea to use the joined Table.
private void updateStudentExamPassed(boolean passed, int lidx, int year, String... studentName) {
Enrollment enrollment = Enrollment.ENROLLMENT;
Student student = Student.STUDENT;
Table<?> joined = enrollment.leftJoin(student).on(enrollment.STUDENT_ID.eq(student.ID));
ctx.update(joined)
.set(enrollment.EXAM_PASSED, passed)
.where(student.LASTNAME.in(studentName))
.and(enrollment.YEAR.eq(year))
.and(enrollment.LECTURE_ID.eq(BigInteger.valueOf(lidx)))
.execute();
}
But I get an DataAccessException on the .execute()
Exception in thread "main" org.jooq.exception.DataAccessException: SQL [update [LECTURE_DB].[dbo].[ENROLLMENT] left outer join [LECTURE_DB].[dbo].[STUDENT] on [LECTURE_DB].[dbo].[ENROLLMENT].[STUDENT_ID] = [LECTURE_DB].[dbo].[STUDENT].[ID] set [LECTURE_DB].[dbo].[ENROLLMENT].[EXAM_PASSED] = ? where ([LECTURE_DB].[dbo].[STUDENT].[LASTNAME] in (?, ?) and [LECTURE_DB].[dbo].[ENROLLMENT].[YEAR] = ? and [LECTURE_DB].[dbo].[ENROLLMENT].[LECTURE_ID] = ?)]; Falsche Syntax in der Nähe des left-Schlüsselworts.
at org.jooq_3.12.1.SQLSERVER2014.debug(Unknown Source)
at org.jooq.impl.Tools.translate(Tools.java:2717)
at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:755)
at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:383)
at org.jooq.impl.AbstractDelegatingQuery.execute(AbstractDelegatingQuery.java:119)
at de.esteam.lecturedb.jooq.tasks.RecordFeaturesTask.updateStudentExamPassed(RecordFeaturesTask.java:42)
at de.esteam.lecturedb.jooq.tasks.RecordFeaturesTask.run(RecordFeaturesTask.java:28)
at de.esteam.lecturedb.jooq.common.LectureDBAnalysis.run(LectureDBAnalysis.java:100)
at de.esteam.lecturedb.jooq.common.LectureDBAnalysis.main(LectureDBAnalysis.java:56)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Falsche Syntax in der Nähe des left-Schlüsselworts.
The Documentation did not help me since the condition relies on another table. Is there any hope to get this to work or do I need to get each Enrollment by it self and update it single handedly?

Using vendor specific syntax
The question you've linked is about MySQL. SQL Server does not support this kind of syntax, but you can achieve an equivalent semantics by using the UPDATE .. FROM clause. I.e. try this:
ctx.update(enrollment)
.set(enrollment.EXAM_PASSED, passed)
.from(joined)
.where(student.LASTNAME.in(studentName))
.and(enrollment.YEAR.eq(year))
.and(enrollment.LECTURE_ID.eq(BigInteger.valueOf(lidx)))
.execute();
Notice that a LEFT JOIN does not make any sense here if you're turning it again into an INNER JOIN by having a predicate on the student table in your WHERE clause.
Using standard syntax
I personally prefer using standard SQL syntax whenever it is possible in these cases, as these UPDATE .. FROM or UPDATE .. JOIN statements can often be replaced by IN or EXISTS predicates. For example:
ctx.update(enrollment)
.set(enrollment.EXAM_PASSED, passed)
.where(enrollment.STUDENT_ID.in(
select(student.ID)
.from(student)
.and(student.LASTNAME.in(studentName))
))
.and(enrollment.YEAR.eq(year))
.and(enrollment.LECTURE_ID.eq(BigInteger.valueOf(lidx)))
.execute();

Related

Inserting a table with two key values

I´m using Postgres and java to write files out of a .csv into a db. In my CREATE TABLE stmnts, I have a table which stores two keys. These I want to insert. I now have a subquery but i always get a null value for the ckey, so the syntax must be wrong. The INSERT does not work. ERROR: null value in column "ckey" of relation "gamesin" violates not-null constraint. The other value I get out of a list I created. I´m using a prepared statement. Help appreciated!
CREATE TABLE Games(
Year INT PRIMARY KEY,
Name VARCHAR(32) NOT NULL,
StartDate Date NOT NULL,
EndDate Date NOT NULL
);
CREATE TABLE Cities(
CKey SERIAL PRIMARY KEY,
Name VARCHAR(128) UNIQUE NOT NULL,
Noc CHAR(3) REFERENCES Countries NOT NULL
);
CREATE TABLE GamesIn(
Year INT REFERENCES Games,
CKey INT REFERENCES Cities,
PRIMARY KEY(Year, CKey)
);
String sql = "INSERT INTO gamesin (year, ckey) VALUES (?, (SELECT ckey from cities WHERE cities.name = '\" + name + \"'))";

Ways to dynamically change SQL database through JafaFx table Cell editing

My javaFx application has many tables with editable table cells to populate data from sql database.I also want to make changes in database after data editing through table cells.According to this toturial "https://docs.oracle.com/javafx/2/ui_controls/table-view.htm"
I have created my editable table cell with the following code.
item_price_col.setCellValueFactory(
new PropertyValueFactory("price")
);
item_price_col.setCellFactory(TextFieldTableCell.forTableColumn());
item_price_col.setOnEditCommit(
new EventHandler<CellEditEvent<Item, String>>() {
#Override
public void handle(CellEditEvent<Item,String> t) {
String old_price=t.getOldValue();
((Item) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setPrice(t.getNewValue());
String new_price=t.getNewValue();
System.out.println("Old Price:"+old_price);
System.out.println("New Price:"+new_price);
}
}
);
But it doesn't make any changes in database after editing.So,I think have to write update Query inside of that handle method.But I can only know old value and new value. I can't make query statement like that "update item set price=new_price where price=old_price".If I update a single price of a item to new value,every items in my item table that have the same price with my edited item will make changes to new price value.Are there any ways to solve this problem?
Here is my item table structure.
item | CREATE TABLE `item` (
`code` int(11) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`price` varchar(50) NOT NULL,
`whole_sale_price` varchar(50) NOT NULL,
`orginal_price` varchar(50) DEFAULT NULL,
PRIMARY KEY (`code`),
UNIQUE KEY `code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
Keep an id field to your item as it is given in the database.
If you have not primary or unique key in the database probably you made some architectural mistake. Anyway there is a row id specified in some database servers.
private int id; // id field for item object.
While updating include id as condition.
update sometable set price = item.getPrice() where id = item.getId();
I know sql is not well written but I hope you'll get it
And you don't have to show value of id field in your table grid.
This technique is used in most systems
EDITED 2015.12.18
You have code column in the table. Retrieve by jdbc into your item object's id field.
There is an example
http://www.tutorialspoint.com/jdbc/jdbc-update-records.htm

Update table with primary key and unique columns using Hibernate and mySQL

I have a table containing four columns:
CREATE TABLE `participants` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(128) NOT NULL,
`function` VARCHAR(255) NOT NULL,
`contact` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `name_function_contact` (`name`, `function`, `contact`)
)
From the application I get participants-objects, which might have values for name, functionand contactwhich are already in that exact matter in the database. In this case I want Hibernate to get me the idof that object, otherwise I want to save the object.
Using saveOrUpdate()I just get an:
org.hibernate.exception.ConstraintViolationException: Duplicate entry 'NAME-FUNCTION-CONTACT: NAME' for key 'name_function_contact'
How can I accomplish this? Thanks a lot!
Since the answers suggested that Hibernate cannot do it on its own (bummer!) I solved it the "native sql" way:
Participants tempParti = ((Participants) session.createQuery("FROM Participants WHERE name = '" + p.getName() + "' AND function = '" + p.getFunction() + "' AND contact = '" + p.getContact() + "'").uniqueResult());
if (tempParti != null) {
p = tempParti;
} else {
session.save(p);
}
Works like a charm! Thanks to all of you!
I am no expert in Hibernate. But from Mysql perspective, you do the following.
use INSERT IGNORE INTO... to add the value in the table. If the number of rows inserted is 0, then you can manually get the ID of the row by a SELECT statement.
EDIT: LAST_INSERT_ID() was wrong here. I have edited the answer.

Java Swing & Postgres user authentication: Close old connection when new connection opened

I have a Java Swing application that accesses a Postgres database using a simple Singleton Pattern:
public class DatabaseConnection {
private static final String uname = "*******";
private static final String pword = "*******";
private static final String url = "*******************************";
Connection connection;
// load jdbc driver
public DatabaseConnection(){
try{
Class.forName("org.postgresql.Driver");
establishConnection();
} catch (ClassNotFoundException ce) {
System.out.println("Could not load jdbc Driver: ");
ce.printStackTrace();
}
}
public Connection establishConnection() {
// TODO Auto-generated method stub
try{
connection = DriverManager.getConnection(url, uname, pword);
} catch (SQLException e){
System.out.println("Could not connect to database: ");
e.printStackTrace();
}
return connection;
}
}
public class SingletonConnection {
private static DatabaseConnection con;
public SingletonConnection(){}
public static DatabaseConnection instance(){
assert con == null;
con = new DatabaseConnection();
return con;
}
}
This is my user table created by Pgadmin3 (hence the ugly upper cases):
CREATE TABLE "user"
(
id serial NOT NULL,
"userRoleId" integer NOT NULL,
"employeeId" bigint NOT NULL,
"subjectId" bigint NOT NULL,
username text NOT NULL,
cryptpwd text NOT NULL,
"userStatusId" integer NOT NULL,
md5pwd text NOT NULL,
CONSTRAINT pk_user PRIMARY KEY (id),
CONSTRAINT "subjectId" FOREIGN KEY ("subjectId")
REFERENCES subject (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT user_employee_id FOREIGN KEY ("employeeId")
REFERENCES employee (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "user_userRole_id" FOREIGN KEY ("userRoleId")
REFERENCES "userRole" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "user_userStatus_id" FOREIGN KEY ("userStatusId")
REFERENCES "userStatus" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "unique_user_userName" UNIQUE (username)
)
Since this application will be run on many machines in a local network, I would like to have only a single connection instance per specific user. That is, if userA logs in from one machine, and userA logs in from another machine moments later, notifications should appear on both machines with the second log in having the option to continue with the connection - in which case, the existing connection is dropped/lost.
I imagine I'd have to add a new column (logged_on boolean) in my user table ... in which case the second log in is handled by finding the value of logged_on and acting appropriately. My question is, how then will I be able to close the first connection? How can I maintain a maximum of one connection - per user - at database level?
Ok, this is what I'm working on. Surprisingly, I was thinking of something along the lines you mentioned Zamezela ... I haven't got it working yet, but I think this should work.
My user table:
CREATE TABLE "user"
(
id serial NOT NULL,
"userRoleId" integer NOT NULL,
"employeeId" bigint NOT NULL,
"subjectId" bigint NOT NULL,
username text NOT NULL,
cryptpwd text NOT NULL,
"userStatusId" integer NOT NULL,
md5pwd text NOT NULL,
"loggedIn" boolean NOT NULL DEFAULT false,
CONSTRAINT pk_user PRIMARY KEY (id),
CONSTRAINT "subjectId" FOREIGN KEY ("subjectId")
REFERENCES subject (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT user_employee_id FOREIGN KEY ("employeeId")
REFERENCES employee (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "user_userRole_id" FOREIGN KEY ("userRoleId")
REFERENCES "userRole" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "user_userStatus_id" FOREIGN KEY ("userStatusId")
REFERENCES "userStatus" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "unique_user_userName" UNIQUE (username)
)
I've created a table that records each and every user login. Will help track down on user activity:
CREATE TABLE "userLoginHistory"
(
"userId" integer NOT NULL,
_datetime timestamp without time zone NOT NULL,
hostname text NOT NULL,
"osUsername" text NOT NULL,
id bigserial NOT NULL,
CONSTRAINT "pk_userLoginHistory" PRIMARY KEY (id),
CONSTRAINT "userLoginHistory_user_id" FOREIGN KEY ("userId")
REFERENCES "user" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE
)
I now have three main Stored functions thus far ... may add on to them tomorrow. Getting late.
First one involves requesting for a user login. This returns the user id, role, whether someone is logged on on this user account, and whether this user is active:
create type userLoginRequestReturnType as
(
userId integer, -- user.id
userRoleId integer, -- user.roleId
loggedIn boolean, -- user.loggedIn
userActive boolean -- whether user is active
);
CREATE OR REPLACE FUNCTION "user_login_request"(usernameIn text, passwordIn text)
returns setof userLoginRequestReturnType as
$$
declare
user_Id integer;
user_RoleId integer;
user_StatusId integer;
user_loggedIn boolean;
user_Active boolean;
sql text;
begin
user_Active = false;
select into user_Id, user_RoleId, user_StatusId, user_loggedIn id, "userRoleId", "userStatusId", "loggedIn" from "user" where username = usernameIn and cryptpwd = crypt(passwordIn, cryptpwd);
if (user_id > 0) then -- record found
select into user_Active "user_is_active"(user_StatusId);
else
user_id = 0;
user_RoleId = 0;
user_loggedIn = false;
user_Active = false;
end if;
sql = 'select ' || user_Id || ', ' || user_RoleId || ', ' || user_loggedIn || ', ' || user_Active ||';';
return query execute sql;
end;
$$ language 'plpgsql';
This is passed to the front end. If user_loggedIn is true, and all the other attributes support a successful log in, then the front end will notify the user that there is an existing connection, and whether to continue (disconnecting the existing connection). If it is false, then it just continues (without any prompt) to this function:
CREATE OR REPLACE FUNCTION "user_login_complete"(userIdIN integer, hostnameIN text, osUsernameIN text)
returns bigint as
$$
declare
currentTime timestamp without time zone;
userLoginHistoryId bigint;
begin
-- update user.loggedIn
update "user" set "loggedIn" = true where id = userIdIN;
-- insert into userLoginHistory
currentTime = NOW()::timestamp without time zone;
insert into "userLoginHistory" ("userId", _datetime, hostname, "osUsername") values (userIdIN, currentTime, hostnameIN, osUsernameIN);
select into userLoginHistoryId currval('"userLoginHistory_id_seq"');
return userLoginHistoryId;
end;
$$ language 'plpgsql';
The userLoginHistoryId is stored on the front end, since I'm using an MVC architecture for my Java Swing project, my abstract Model Class will call the following function in its constructor. I have taken your advice and will close the connection in each method.
-- function to check if the current logged in session is the last one recorded in database
-- to be run before each connection to the database as per userId
-- new userLoginHistoryId must be inserted into table userLoginHistory, and the id PK value stored in the front end
--
-- returns: true, if current session is the last session recorded in table userLoginHistory for this user_autosuggest_by_ID
-- : false, if another login session has been recorded.
-- MUST BE EXECUTED BEFORE EACH AND EVERY DATABASE TRANSACTION!!!!!
CREATE OR REPLACE FUNCTION "user_login_session_check"(userIdIN integer, userLoginHistoryIdIN bigint)
returns boolean as
$$
declare
results boolean;
userLoginHistoryId bigint;
begin
results = true;
select into userLoginHistoryId id from "userLoginHistory" where "userId" = userIdIN ORDER BY id DESC LIMIT 1;
if (userLoginHistoryIdIN = userLoginHistoryId) then
results = true;
else
results = false;
end if;
end;
$$ language 'plpgsql';
Will test tomorrow and hopefully it works fine. Please feel free to comment.
Thanks.
#greatkalu your problem is much deeper and very hard achievable, I will suggest you some approach: when user log in you should update two fields(last_access_timestamp, computer_id) and for every access to the database you should update last_access_timestamp. computer_id and last_access_time should be valid maybe 1 hour or less depends of the use of the application. when other person tries to login with same user_id then if now() - 1 hour < last_access_timestamp then that user should not be grant access.
computer_id is generated from application and for every computer should be unique and always generated same computer_id.
I hope this will help

How to get super table information in java?

My database had a lot of parent and child tables.The tables contains the foreign key which has the link with the parent table.I wants to get the information of parent table of the child table using java?How can I achieve that?
For ex,consider the student and mark table,
The student table contains the information like studentID,name.
studentID-Primary key
The marks table contains the markId,studentId,Sub1,sub2,sub3 etc
markId-Primarykey
studentID-Foreignkey refers Student table
My table creation queries are,
CREATE TABLE `Student12` (
`studentId` SMALLINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`studentId`)
)
ENGINE = InnoDB;
CREATE TABLE `Marks` (
`markId` SMALLINT NOT NULL AUTO_INCREMENT,
`subject1` SMALLINT NOT NULL,
`subject2` SMALLINT NOT NULL,
`studentId` SMALLINT NOT NULL,
PRIMARY KEY (`markId`),
CONSTRAINT `FK_Marks_Student` FOREIGN KEY `FK_Marks_Student` (`studentId`)
REFERENCES `Student12` (`studentId`)
ON DELETE RESTRICT
ON UPDATE RESTRICT
)
ENGINE = InnoDB;
If I give the mark table name as input, how can I get its parent or super table name student and information about student table?Any help should be appreciable.
It totally depends on the way tables are created. Foreign keys are not mandatory to create, they could be a simple column in one table with no explicit relationship to the other table. If you are very sure that the links are created explicitly (the foreign keys are defined) then you could use information_schema. But if there is no foreign key defined (which is true in most of the databases I have seen), then there is no way for you to find the links inside the database. You have to look into the code (if there is any available) and try to find a clue.
The JDBC DatasetMetaData interface provides a couple of methods that may help. (The following text is copied from the javadoc.
ResultSet getExportedKeys(String catalog, String schema, String table)
Retrieves a description of the foreign key columns that reference the given table's primary key columns (the foreign keys exported by a table).
ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable)
Retrieves a description of the foreign key columns in the given foreign key table that reference the primary key or the columns representing a unique constraint of the parent table (could be the same or a different table).
Of course, these can only work if the relevant columns have been declared as foreign keys in the SQL table DDL.
You can use the DatabaseMetaData to retrieve informations about foreign keyes
and the referenced Tables. Im not sure if it works with all kinds of MySql Tables.
The principle is to use the follwing code (not tested) to retrieve information about the super tables
ResultSet rs = null;
DatabaseMetaData dm = conn.getMetaData( );
// get super tables of table marks
ResultSet rs = dm.getSuperTables( null , null, "marks" );
while( rs.next( ) ) {
System.out.println(String.format("Table Catalog %s", rs.getString("TABLE_CAT") );
System.out.println(String.format("Table Schema %s", rs.getString("TABLE_SCHEM") );
System.out.println(String.format("Table Name %s", rs.getString("TABLE_NAME") );
System.out.println(String.format("Table Name %s", rs.getString("SUPERTABLE_NAME") );
}
You can use thes informations to get additional informations about the referenced table
and the foreigen and referenced primary keys:
ResultSet rs = dm.getCrossReference( null , null , "student" , null , null , "marks" );
System.out.println(String.format("Exported Keys Info Table %s.", "marks"));
while( rs.next( ) ) {
String pkey = rs.getString("PKCOLUMN_NAME");
String ptab = rs.getString("PKTABLE_NAME");
String fkey = rs.getString("FKCOLUMN_NAME");
String ftab = rs.getString("FKTABLE_NAME");
System.out.println("primary key table = " + ptab);
System.out.println("primary key = " + pkey);
System.out.println("foreign key table = " + ftab);
System.out.println("foreign key = " + fkey);
}
And finally you can retrieve the information about the super table by
ResultSet rs = dm.getTables(null,null,"student" ,null);
System.out.println("Table name:");
while (rs.next()){
String table = rs.getString("TABLE_NAME");
System.out.println(table);
}

Categories