JDBC Multiple Columns with the same name - java

I'm having a problem with the value being populated from a column from a different table instead of the table I'm wanting it to pull from.
From mySQL, I get the desired result of null; however, from within the program, it is displaying the value (If I have given it one for that row,) or the value from a different table. This is even while using aliases and explicitly stating which table to pull from.
I have a device table and a device type table. The device table has all the same fields as the device, but it is just 1's and 0's that dictate which fields are needed. (This is used when generating the edit / create a device GUI form.)
This only happens when using the resultSet.getInt("column_with_issue") if the values are INTs in both tables. It is returning a proper null when I do a resultSet.getString("column_with_no_issues") as long as the types are different.
Here is my original query, and what I've tried to change as per suggestion to fix it.
SELECT d.*, dt.type, os.os_name FROM device d inner join device_type dt on d.type_id = dt.id left outer join operating_system os on d.os = os.id
WHERE d.division_number = 1 or 1
AND (d.asset_tag = 1 or 1)
AND (dt.type = 1 or 1);
Possible fix as described in other peoples stackoverflow/javaranch questions. This will give each specific column its own name. However even when I go to pull from (as an example one that has two different variable types) dwireless, I still get the integer value that should be from my device_type.wireless for that kind of device instead of the expected null value.
SELECT d.id as did, d.division_number as ddivision_number, d.current_location as dcurrent_location, d.type_id as dtype_id, d.model as dmodel, d.asset_tag as dasset_tag, d.serial_number as dserial_number, d.manufacture_date as dmanufacture_date, d.screen as dscreen, d.os as dos, d.users_name as dusers_name, d.office_installed as doffice_installed, d.memory as dmemory, d.series as dseries, d.ip_address as dip_address, d.host_name as dhostname, d.vm_host as dvm_host, d.processor as dprocessor, d.wireless as dwireless, d.purchase_quality as dpurchase_quality, d.purchase_price as dpurchase_price, d.active as dactive, d.notes as dnotes, dt.type, os.os_name
FROM device d inner join device_type dt on d.type_id = dt.id left outer join operating_system os on d.os = os.id
WHERE d.division_number = 1 or 1
AND (d.asset_tag = 1 or 1)
AND (dt.type = 1 or 1);
Here is the Java code that I'm using to pull the variables from the result set.
private ObservableList<Device> getDevices(String sqlStatement) throws SQLException {
ObservableList<Device> devices = FXCollections.observableArrayList();
// Run the query to select all of our devices.
Statement searchDeviceStatement = Main.myConn.createStatement();
ResultSet rs = searchDeviceStatement.executeQuery(sqlStatement);
// Add all of our devices into our array list to be displayed.
// These are the actual columns of the database.
while (rs.next()) {
devices.add(new Device(rs.getInt("did"), rs.getInt("ddivision_number"), rs.getInt("dtype_id"),
rs.getString("type"), rs.getString("dmodel"), rs.getInt("dasset_tag"), rs.getString("dserial_number"),
rs.getInt("dmanufacture_date"), rs.getString("dscreen"), rs.getInt("dos"), rs.getString("os_name"),
rs.getString("dusers_name"), rs.getInt("doffice_installed"), rs.getString("dmemory"),
rs.getString("dseries"), rs.getString("dip_address"), rs.getString("dhost_name"),
rs.getString("dvm_host"), rs.getString("dprocessor"), rs.getInt("dwireless"),
rs.getString("dpurchase_quality"), rs.getDouble("dpurchase_price"), rs.getInt("dactive"), rs.getString("dnotes")));
}
return devices;
}
The query works as intended from mySQL Workbench, as seen here, but when displaying the data in my program it looks like this.

Answer: I am an idiot. Default values for integers are 0, while strings are null. JDBC is returning null but when it creates my Device object with that value it is defaulted to 0. This is explained about 1/3rd of the way down on this page.

Related

How to subtract quantity between two tables based on item types in Java Netbeans?

Hi I have two tabels PURCHASE and DELIVERY where by I want to show the remaining quantity in another table 'STOCK'.
Below is the output I got from my STOCK table and the code I did, but the calculation is wrong.
Can anyone help me with this?
private void stock(){
dbConection db = new dbConection();
Connection con=db.getConnection();
String sql = "Select delivery.pro_Name, delivery.pro_Code, (sum(purchase.pur_qty) - sum(delivery.Qty)) AS bal from delivery, purchase where purchase.productCode = delivery.pro_Code GROUP BY delivery.pro_Code ";
PreparedStatement pst = con.prepareStatement(sql);
ResultSet rs = pst.executeQuery();
DefaultTableModel tm = (DefaultTableModel)stockTable.getModel();
tm.setRowCount(0);
while(rs.next()){
Object o[]={rs.getString("pro_Code"), rs.getString("pro_Name"), rs.getString("bal")};
tm.addRow(o);
}
}catch(Exception ex){
JOptionPane.showMessageDialog(null,ex);
}
First of all, this is only a SQL problem, and Java is only for view the results.
The above code will be for MS SQL Server, as you did not provide the type of SQL Database.
A final stock is calculated starting from an initial stock.
So you will must have something like:
initial_stock + purchase_qty - delivery_qty = final_stock (group by ProductId)
Now, if you store your articles/products in your database as FIFO, that means you imply also the price in this formula, so group by implies also Fifo_Price . This could be also more complex SQL Select, based of related tables.
Supposing you don't need FIFO, but only a remaining quantity stock, the select syntax will be something like this:
-- Supposing initial stock is stored in Product Table
Select pr.ProductID, pr.InitialStock, Sum(IsNull(pc.Quantity,0)) AS QuantityIn,
Sum(IsNull(dv.Quantity,0)) AS QuantityOut,
pr.InitialStock + sum(IsNull(pc.Quantity,0) - IsNull(dv.Quantity,0)) AS FinalStock
From Products pr
Left Join Purchase pc on pr.ProductID = pc.ProductID
Left Join Delivery dv on pr.ProductID = dv.ProductID
Group By pr.ProductID, pr.InitialStock
-- if you want to see only products that are implied in purchase and delivery tables, you must Inner Join all tables
Edit: I have deleted the rest of answer, because was not relevant to question.
Edit 2: Please look at this picture. I have made a simple test showing what are results as I did and as you did:
Considering that initial stock is not null, I did not force a replacement with 0, but you can replace that too, so st.qty will be IsNull(st.Qty, 0) as InitialStock

Can I compare resultsets like this? I'm facing the below error

I have 2 ResultSets. 1st ResultSet contains the records from table1 from database1 and 2nd ResultSet contains the records from table2 from database2. I need a list of records from resultset1 which are not present in resultSet2. For this I wrote this logic but it is not working and throwing me the following error.
java.sql.SQLException: Invalid operation for read only resultset: deleteRow
if ( table1ResultSet != null )
{
while ( table1ResultSet.next() )
{
final String table1Record = table1ResultSet.getString( 1 );
if ( table2ResultSet != null )
{
while ( table2ResultSet.next() )
{
final String table2Record = table2ResultSet.getString( 1 );
if ( table1Record.toString().equalsIgnoreCase( table2Record.toString() ) )
{
table1ResultSet.deleteRow();
break;
}
}
}
}
}
return table1ResultSet;
That exception says what the problem is - your result set doesn't support delete. In order to have updateable result set there are some requirements:
When you prepare statement did you make it with ResultSet.CONCUR_UPDATABLE?
A query can select from only a single table without any join operations.
The query must select all non-nullable columns and all columns that do not have a default value. A query cannot use "SELECT * ". Cannot select derived columns or aggregates such as the SUM or MAX of a set of columns.
You might want to move the results sets into Java sets before working doing what you are doing though because using deleteRow will actually delete the row from the database (unless that's the expected result)
There is another problem with your code though. Even if delete works your code will fail on the second iteration of result set 1 because you never reset table2ResultSet and for the second iteration there won't be more results in table2resulset.
But on top of all that. Why would you go through all that hussle and get all that rows that you don't need instead of doing it with one single query like:
select * from table 1 where id not in select id from table 2
or
delete from table 1 where id not in select id from table 2
if that's the goal
Your logic:
Assumes the records come in some order (which may or may not be true, depending on your SQL)
Consumes the entire result set 2 for each row of result set 1, which is unlikely your intent
Deletes things, which is also not what you mentioned in the question
Your question can be implemented easily as such:
Set<String> list1 = new HashSet<>();
while (table1ResultSet.next())
list1.add(table1ResultSet.getString(1).toLowerCase());
while (table2ResultSet.next())
list1.remove(table2ResultSet.getString(1).toLowerCase());
System.out.println(list1);
This will print all the values (without duplicates) that are present in the first result set, but not in the second.

Foreign Key Not Outputting Query Data

try {
Statement s = conn.createStatement();
ResultSet result2 = s.executeQuery("Select Distinct * From Poem p,Recording r Where r.PoemTitle = p.PoemTitle AND r.poemTitle = 'poem1'");
System.out.print("Result (Select with Join): ");
while (result2.next()) {
System.out.println(result2.getString(1)+ " " + result2.getString(2)+ result2.getString(3));
}
} catch(Exception e) {
System.out.print(e.getMessage());
}
I am trying to output the poemtitle and the date it was recorded. When this runs it outputs the poemtitle and then gives the date the poem was created instead of recorded? Is this because of the relationship?
Most likely it's because of the * in the SELECT list.
Specify the columns that you want returned, in the order you want them returned.
We're just guessing at the name of the column that contains "date recorded" and which table it's in:
SELECT p.PoemTitle
, r.dateRecorded
, r.readBy
FROM Poem p
JOIN Recording r
ON r.PoemTitle = p.PoemTitle
WHERE r.poemTitle = 'poem1'
GROUP
BY p.PoemTitle
, r.dateRecorded
, r.readBy
ORDER
BY p.PoemTitle
, r.dateRecorded DESC
, r.readBy
Notes:
Ditch the old-school comma syntax for the join operation and use the JOIN keyword instead, and relocate the join predicates from the WHERE clause to an ON clause.
Avoid using * in the SELECT list. Explicitly list the columns/expressions to be returned. When we read the code, and that SQL statement, we don't know how many columns are being returned, what order the columns are in, or what the datatypes are. (We'd have to go look at the table definitions.)
Explicitly listing the columns/expressions being returned only takes a little bit of work. If code was only ever written, then it would be fine, save the time writing. But code is READ ten times more than it is written. (And the SQL statement with the * makes the SQL statement virtually indecipherable in terms of which column is being referenced by getString(1).
Listing the columns columns can also make it more efficient on the database, to prepare a resultset with a few columns vs a resultset of dozens of columns, and we also transfer a smaller resultset from the database to the client. With a subset of columns, its more likely we can use a covering index for the query.

Working with a large Resultset

I'm trying to write a java function that can work with large result sets.
The table has 1.2 billion rows which is 189 Gb of data.
Currently I query all the data and extract the information which I store in their respective objects.(using a million row sample db)
TreeMap <Long, Vessel> vessels = new TreeMap<Long, Vessel>(); //list for all vessels
try{
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT mmsi, report_timestamp, position_geom, ST_X(position_geom) AS Long, "
+ "ST_Y(position_geom) AS Lat FROM reports2 WHERE position_geom IS NOT NULL ORDER by report_timestamp ASC");
while(rs.next()){
long mmsi = rs.getLong("mmsi");
java.util.Date time = rs.getTime("report_timestamp");
double longitude = rs.getDouble("Long");
double latitude = rs.getDouble("Lat");
Coordinate coordinate = new Coordinate(longitude, latitude, time);
Vessel vessel = new Vessel(mmsi);
if(!vessels.containsKey(mmsi)) { //if vessel is not present in vessels
vessel.addCoor(coordinate);
vessels.put(mmsi, vessel);
}
else{ //if vessel is already in vessels
vessels.get(mmsi).addCoor(coordinate);
}
}
}catch(Exception e){
JOptionPane.showMessageDialog(null, e);
}
With 189 Gb of data, my computer's memory won't be able to hold the information
I've never touched a table with a billion+ rows and some of my methods involve having all the tables attributes
Can I make Resultset collect 1,000,000 queries at a time and then delete objects after I run functions on them -> then collect another 1,000,000 and so on
Is it possible to hold a 1.2 billion row resultset in approx. 43,000,000 vessel objects (will it take too much space/time ?)
Do I try and limit my query by having a way to select a specific key or attribute and run functions on specified data?
Is there another option ?
If memory is an issue with the ResultSet you can set the fetch size, though you'll need to clear objects during fetch to ensure you don't run out of memory. With Postgres you need to turn off Auto commit or fetch size will not occur.
connection.setAutoCommit(false);
Statement stmt = connection.createStatement();
stmt.setFetchSize(fetchsize);
You can read more about buffering the Result set at https://jdbc.postgresql.org/documentation/94/query.html#query-with-cursor
From your code it seems that you are builing a java object that collects alla the coordinates with the same mmsi field. You did not provide information about this object (mmsi and it list of coordinates) usage. Given this information you can query the data sorting by mmsi and then timestamp (you order by clause is only by timestamp now), when in the resultset you find a different value of mmsi you collected all the data about than specific mmsi so you can use it wihout reading other data.
I don't think you really need to get all the data in memory; you can rewrite the query in order to get only a fixed (a sliding window) number of Vessel objects; you must page the data (i.e. retrieve a block of 10 vessels starting from vessel at position x)
In order to provide a more detailed response you have to explain what you are doing with Vessels.

JPQL count returning 0 when there is a row

I am using two identical JPQL NamedQueries, except that one is a COUNT. Here are the queries:
select i from IssueRingReqsBrit i where i.ringDataRequest = 'I' and i.onRingIssue = 'Y' and i.noCardIssued = 0
select COUNT(i) from IssueRingReqsBrit i where i.ringDataRequest = 'I' and i.onRingIssue = 'Y' and i.noCardIssued = 0
IssueRingReqsBrit is a view.
The first query is returning a list of 6, which is correct.
The second query, the count, return 0.
Databased being used is Oracle. Using Glassfish with Eclipselink. Shared cache mode on the PU is set to none.
Using native queries in Oracle, the correct values are returned.
Below is the code I use to execute the queries, and check the results. There is no other code between these lines, they were copy and pasted as they are in the Java.
query = em.createNamedQuery("IssueRingReqsBrit.onRingIssue_toSend_initial");
System.out.println("Size: " + query.getResultList().size() );
//ringingRequestRingIssueYesToSendInitial
query = em.createNamedQuery("IssueRingReqsBrit.onRingIssue_toSend_initial_count");
ringingRequestRingIssueYesToSendInitial = ((Long)query.getSingleResult()).intValue();
System.out.println("ringingRequestRingIssueYesToSendInitial = " + ringingRequestRingIssueYesToSendInitial);
Any suggestions are appreciated.
Based on the JPQL Language reference, in the COUNT function, the path expression that is the argument to the aggregate function must terminate in a state-field. The path expression argument to COUNT may terminate in either a state-field or a association-field, or the argument to COUNT may be an identification variable. So try something like this
select COUNT(i.<field>) from IssueRingReqsBrit i where i.ringDataRequest = 'I' and i.onRingIssue = 'Y' and i.noCardIssued = 0
COUNT returns Long.
Make use you are returning the resulat in a Long.

Categories

Resources