I am developing a web application using JSP + Servlets and Oracle10 as back-end.
I have a table for storing information related to Customers:
|ID |Name |City |
|N0001 |ABC |NASIK |
|N0002 |PQR |NASIK |
|N.... |... |NASIK |
|N9999 |XYZ |NASIK |
|N10000 |LMN |NASIK |
|N10001 |MNO |NASIK |
In above table ID is a primary key, which is auto-generated depending upon the City (first Character of City + Number(Number must be minimum 4 character long, so for first ID, three leading zeroes will be added to number))
For Generating ID:
I am using following query for getting Largest ID from table, and then some java code Auto Generate Next ID.
query = "select ID from CUST where CITY='NASIK' order by ID desc";
Then getting the first ID from ResultSet which is as expected till the ID reach to the N9999, but when ID is N10000 or above then query is giving me N9999 as Largest ID.
Output after N9999:
ID
----------
N9999
N10001
N10000
N0002
N0001
Output Expecting
ID
----------
N10001
N10000
N9999
N0002
N0001
So my question is that is there anything wrong in above query? Or is there any better way to Auto Generate ID which contains String.
Edit1
My requirement is to auto generate ID which will contain character at starting position.
use this query
select ID from CUST where CITY='NASIK' order by to_number(substr(ID,2)) desc;
Since ID is a String not a number, it is sorted differently. it would sort as you wish if you had done sth like:
0001N
0002N
...
or stored only numbers, not Strings
With the INSERT, without inserting the prinary key ID, you can get the "generated keys."
String sql = "INSERT INTO Customers(Name, City) VALUES (?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql,
PreparedStatement.RETURN_GENERATED_KEYS);
stmt.setString(1, ...);
stmt.setString(2, ...);
int affectedRows = stmt.executeUpdate();
// Get the ID:
String pk = "";
ResultSet keys = stmt.getGeneratedKeys();
if (keys.next()) {
pk = keys.getString(1);
}
It is so ugly, loop x loop, as one could have inserted more than one row, and the generated keys per row could be more than one.
As you can see, this is prove against concurrent parallel INSERTS.
About the sorting problem: you might go for a purely numerical ID, maybe a composed primary key CHAR(1), INT.
quick fix would be to increase the number of leading '0' after the character. But then the problem will occur later (e.g. 99999 and 100000).
Hence i would suggest to interpret the ID as a number from the second character on and do the order comparison upon that number value.
Related
My server would retrieve the latest ID from the database, now it is stuck and keeps returning the id 99999, even though the latest id is now 100040
My code is:
String insertTable = "SELECT * FROM dutyofcare ORDER BY Id DESC LIMIT 1";
ps = conn.prepareStatement(insertTable);
rs = ps.executeQuery();
String ResultS = "";
if (rs.next()) {
ResultS += rs.getString("Id");
}
The issue is that the ORDER BY in your query is doing a lexical (character-by-character) sort where 9 always comes after 1, and not numeric sort which handles the digit positions. This is because of the column type of ID. What you need is to ensure ID is a number before the sort is done.
Either change your ID to a numeric column type and run below query:
SELECT MAX(ID) from dutyofcare;
Or if you want to retain your column type (less efficient than above option):
select MAX(cast(ID AS UNSIGNED)) from dutyofcare;
Or if you want to retain your column type AND just fix your existing query (least efficient of all the options)
select * from dutyofcare order by CAST(ID AS UNSIGNED) desc limit 1;
All these methods basically treat the ID as number and choose the biggest value.
I'm using MySQL and fetching a few different values from a table and then perform some basic math on it. Currently three seperate SELECT statements are in use and afterwards I perform some simple addition and subtraction with the outputs I get in Java.
I'm trying to optimize my code but sadly I gotta admit I'm a complete SQL noob. I'm pretty sure there's a way to join these select querys and the calculations so that I actually only get one output but I've not been able to find it.
My table looks something like this:
ID | value | inc | timestamp
--------------------------------------
0 | 5 | 4 | 2018-02-01 10:28:21
1 | 8 | 3 | 2018-02-01 10:28:47
...
My code currently looks like this:
int maxValue = MySQL.executeQuery("SELECT MAX(`value`) AS value FROM `table` where ID = idvalue AND `timestamp` >= TIMESTAMPADD(DAY,-3,NOW())");
int minValue = MySQL.executeQuery("SELECT MIN(`value`) AS value FROM `table` where ID = idvalue AND `timestamp` >= TIMESTAMPADD(DAY,-3,NOW())");
int minInc = MySQL.executeQuery("SELECT `inc` FROM `table` where ID = id AND value = minValue");
int output = maxValue - minValue + minInc;
Is there a way to shorten it to a single
int output = MYSQL.executeQuery( ??? );
?
Simply do select (select ...) - (select ...) + (select ...)
In your case, you can do( not tested in real environment )
select (SELECT MAX(`value`) AS value FROM `table` where ID = idvalue AND `timestamp` >= TIMESTAMPADD(DAY,-3,NOW())) - ( SELECT MIN(`value`) AS value FROM `table` where ID = idvalue AND `timestamp` >= TIMESTAMPADD(DAY,-3,NOW())) + (SELECT `inc` FROM `table` where ID = id AND value = minValue)
First off, there's something funky going on with the maxValue and minValue selects. The Max() and Min() operators will give you the max and min values of a given column of a given set of rows. Using one of these operators with such a specific where (by what seems to be a table's primary key) is probably not what you want to be doing.
Now, answering your question, I think you could do something along the lines of:
SELECT MAX('value') as max, MIN('value') as min
FROM `table` as t
WHERE ...
to "join" (careful with this word) the first 2 queries. This is simple select syntax: usually, there's no problem with selecting more than a column or an aggregate function at a time. Or, something like:
SELECT `inc`
FROM `table`
WHERE ID = id AND
value = (SELECT MIN('value') FROM 'table' WHERE ...)
to "join" the last two.
Single statement is possible using INNER JOIN since you are using a single able. Try this
SELECT MAX(`a.value`)-(MIN(`a.value`)+b.`inc`) AS Output
FROM `table` a
INNER JOIN `table` b ON a.ID=b.ID
AND a.ID = idvalue AND `a.timestamp` >= TIMESTAMPADD(a.DAY,-3,NOW())
AND b.value=(select MIN(value) from table WHERE ID=id);
I'm calling a java function using a url from my front end to insert data to the data base
This is my url:
http://localhost:49779/BackEnd/mobile/rideshare/addride/1590105&toyota&4&Himalaya&10&good&12-04-2017
This is the Java method:
#Path("addride/{student_id}&{vehicle}&{seats}&{destination}&{price}&{description}&{datetime}")
#GET
public void addRide(#PathParam ("student_id") int S_id, #PathParam ("vehicle") String vehicle, #PathParam("seats") int seats,
#PathParam("destination") String destination, #PathParam("price") int price, #PathParam("description") String description,#PathParam("datetime") String datetime) throws ClassNotFoundException,SQLException{
Connection myCon = null;
Class.forName("oracle.jdbc.OracleDriver");
myCon=DriverManager.getConnection("jdbc:derby://localhost:1527/ride_share","yadhu","yadhu");
Statement st=myCon.createStatement();
st.executeUpdate("INSERT INTO RIDES (STUDENT_ID,VEHICLE,SEATS,DESTINATION,PRICE,DESCRIPTION,DATETIME) VALUES "
+ "("+S_id+",'"+vehicle+"',"+seats+",'"+destination+"',"+price+",'"+description+"','"+datetime+"')");
}
The table RIDES has a column RIDES_ID, which is made with auto increment property.
This is how I created the table:
CREATE TABLE RIDES (RIDE_ID INTEGER GENERATED ALWAYS AS IDENTITY (start with 1000), STUDENT_ID INTEGER, VEHICLE VARCHAR(200), SEATS INTEGER, DESTINATION VARCHAR(200), PRICE INTEGER, DESCRIPTION VARCHAR(200), DATETIME VARCHAR(50));
The insertion works when I do it implicitly, but when I call the method using the url it's showing the error. I couldn't find the mistake please help me.
The error means that the number of columns you are trying to add does not match the number of declared columns.
IE. insert into table (col1, col2) values (val1, val2, val3).
This could be due to a code error when reading the parameters from the URL.
This can also be due if one of the values your are passing contains a coma "," .
first level of debug:
Do SYSTEM.OUT.PRINTLN to the statement before executing it and check its outcome in the console to spot possible errors.
Also, please do use PreparedStatement instead of Statement since this will prevent your code from having SQL Injections and avoid many errors.
I am trying to create a nested SELECT SQL statment. I store all value and id and want to select rows that satisfy multiple values. How can I generate a SELECT statement using Java? For example,
ID VALUE
1 RED
2 BIG
1 SMALL
1 SMOOTH
2 TALL
.....
To select an item that is both red and small the statement would be:
SELECT *
FROM table
WHERE table.value = RED AND
id IN (SELECT *
FROM table
WHERE table.value = SMALL AND id IN (...))
This type of problem is called Relational Division
SELECT ID
FROM tableName
WHERE VALUE IN ('SMALL','SMOOTH')
GROUP BY ID
HAVING COUNT(*) = 2
SQLFiddle Demo
the query above will result 1 since the ID contains both records.
If no unique constraint was enforce on value for every ID, DISTINCT is required.
SELECT ID
FROM tableName
WHERE VALUE IN ('SMALL','SMOOTH')
GROUP BY ID
HAVING COUNT(DISTINCT VALUE) = 2
SQLFiddle Demo
SQLFiddle Demo (with duplicate)
OTHER(s)
SQL of Relational Division
select ID
from MyTable
where VALUE in ('RED', 'SMALL')
group by ID
having count(distinct VALUE) = 2
SQL Fiddle Example
Results:
| ID |
------
| 1 |
Here is a general way to approach this:
select id
from t
group by id
having max(case when value = 'Red' then 1 else 0 end) = 1 and
max(case when value = 'Small' then 1 else 0 end) = 1
In other words, membership in the set becomes a clause in the having statement. These can be both inclusion and exclusion (use = 0 instead of = 1) and optional (use or instead of and).
I am making an application in NetBeans (java). This application has unique id combination of string and integer like abc/111 or xyz/253 and the integer part should increase by when a new entry takes place in the database i.e. abc/112 and xyz/254.
The problem is the value of integer part increase until it has reached 10 in a proper way but after that it does not increase and remain same for further entries in database.
I used the following code -
try{
String sql = "SELECT RegNumber FROM Death ORDER BY RegNumber DESC ";
pst = conn.prepareStatement(sql);
rs = pst.executeQuery();
if (rs.next()) {
String add1 = rs.getString("RegNumber");
String[] parts= add1.split("/");
String part1= parts[0];
String part2= parts[1];
int a,b;
a= Integer.parseInt(part2);
b=a+1;
jTextField20.setText(""+part1+"/"+b);
JOptionPane.showMessageDialog(null, "done");
}
}
"Integer part increase till 10" means that if I start the first value of id in database like abc/1 then new id generates automatically for the next entry with the increasing value 1 that is abc/2 and for next entry it is abc/3 and so on in sequential order like this: abc/4, ..., abc/10
But when it has reached abc/10 the new generated id remains same i.e. abc/10 for every new entry in database. (I am using MS Access 2007 and the id is of text type). The first id in the database is created by the application itself.
If anyone has another alternative to generate id, please tell me.
The problem is that
String sql = "SELECT RegNumber FROM Death ORDER BY RegNumber DESC ";
will sort on descending alphabetic order, and alphabetically speaking
"abc/9" > "abc/10"
and that's why your program always fetches 9 over and over again...
I think you will have to split up that column for storage, and store the numeric part as an actual number type in the database. That's probably not as hard as it sounds, you can always sort on 2 fields
String sql = "SELECT RegNumber FROM Death ORDER BY RegString DESC, RegNumber DESC ";
You could also consider using a SERIAL (autoincrement) datatype for the RegNumber part in certain cases (ie if RegNumber is not reset eg when the string part changes) to simplify your insertion logic further.
Your select query is sorting the entries in desc order, which are Varchar type
"SELECT RegNumber FROM Death ORDER BY RegNumber DESC "
Which means after sorting its getting values as
abc/9, abc/8, abc/7, abc/6, abc/5, abc/4, abc/3, abc/2, abc/10, abc/1.
Which means first id is 9 always, which means next value would be 10 always.