Java Oracle jdbc COLUMN statement - java

The problem is following
By executing the below queries in SQL Plus, everything is working perfect:
column firstname new_value v_firstname
select firstname from tbcustomer where customer_id = 111
select '&v_firstname', wrk.* from tbwork where customer_id = 111
But when when i tried to execute these queries from Java program, i get java.sql.SQLException: ORA-00900: invalid SQL statement on the first SQL query
Connection connection = null;
Statement stat = null;
String query = "column due_date new_value v_due_date";
try {
// Load the JDBC driver
String driverName = "oracle.jdbc.driver.OracleDriver";
Class.forName(driverName);
connection = DriverManager.getConnection(url, username, password);
stat = connection.createStatement();
boolean res_num = stat.execute(query);
} catch (ClassNotFoundException e) {
// Could not find the database driver
} catch (SQLException e) {
e.printStackTrace();
}
Now the question is how to overcome this error and execute first query or do you have any other solution to define variable on the oracle session and use it in other SQL statements.
For instance third query is one of the many queries that i need to execute and all of them will have same first name field

column is a SQL*Plus command. It is not valid in SQL or PL/SQL so you cannot use it in a Java application.
Substitution variables like &v_firstname are also a SQL*Plus construct-- they are not valid in SQL or PL/SQL so you cannot use them in a Java application.
If your goal is to get the firstname from tbcustomer and all the columns from tbwork in a single query, you would need to join the two tables. Assuming that both tables have a customer_id column and that is how the two tables are supposed to be joined
SELECT cust.firstname,
work.*
FROM tbcustomer cust
JOIN tbwork work ON (cust.customer_id = work.customer_id)
WHERE cust.customer_id = 111
Assuming that you will be executing this query for multiple customer_id values, however, 111 should be a bind variable instead of a literal and your Java code should be using a PreparedStatement to prepare the SQL statement, then binding a value like 111 using the setInt method before executing the query.
If you want to break this into two database calls, you can simply do something like
PreparedStatement stmtGetFirstName = connection.prepareStatement("select firstname from tbcustomer where customer_id = ?");
stmtGetFirstName.setInt( 1, 111 );
ResultSet rsGetFirstName = stmtGetFirstName.executeQuery();
String firstName = rsGetFirstName.getString();
PreparedStatement stmtGetWork = connection.prepareStatement("select ?, work.* from tbwork where customer_id = ?");
stmtGetWork.setString( 1, firstName );
stmtGetWork.setInt( 2, 111 );
ResultSet rsGetWork = stmtGetWork.executeQuery();
If you can guarantee that all 600 million executions will occur in the same database session, you could use a database context. You would need to create the context and the package it uses in the database
SQL> create or replace context fname_ctx using scott.pkg_get_fname;
Context created.
SQL> ed
Wrote file afiedt.buf
1 create or replace package pkg_get_fname
2 is
3 procedure set_fname( p_customer_id in number );
4 function get_fname return varchar2;
5* end;
SQL> /
Package created.
SQL> create or replace package body pkg_get_fname
2 is
3 procedure set_fname( p_customer_id in number )
4 as
5 begin
-- Obviously, you'd get the data here from your table rather than hard-coding 'Bob'
6 dbms_session.set_context( 'fname_ctx', 'fname', 'Bob' );
7 end;
8
9 function get_fname
10 return varchar2
11 is
12 l_fname varchar2(100);
13 begin
14 l_fname := sys_context( 'fname_ctx', 'fname' );
15 return l_fname;
16 end;
17 end;
18 /
Package body created.
From Java, you could then call pkg_get_fname.set_fname(111) to set the context and use the function pkg_get_fname.get_fname in your query.
It seems odd, however, to be concerned about performance and to be planning to execute 600 million queries from Java against the database. That's going to involve a ton of round-trips over the network between the middle tier and the database server-- if you're really concerned about performance, you'd push that work to stored procedures in the database to eliminate the network round-trips. And the fact that you're executing them so many times makes me suspect that you're doing a lot of row-by-row processing rather than letting the database do set-based operations. That's also going to be a major source of poor performance. Plus, databases are born to join, so it's pretty unusual for a simple join like this to add appreciably to the cost of a query assuming that proper indexes are in place.

Related

Why is SQL Server sequence jumping by two when fetched from Java code?

Let's say there is a sequence created on SQL Server:
CREATE SEQUENCE dbo.my_seq
START WITH 1
INCREMENT BY 1
NO CYCLE;
GO
And the following Java code to fetch the next sequence value:
Connection conn = ...;
String sql = "SELECT NEXT VALUE FOR my_seq;";
try (Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(sql)) {
while (resultSet.next()) {
long seq = resultSet.getLong(1);
System.out.println(seq);
}
}
Why are sequences jumping by two when this code is executed repeatedly?
2
4
6
I've tried with the CACHE option on and off. It makes no difference.
Sequences are incremented by one if I execute the same query multiple times on Azure Data Studio.
I'm running Microsoft SQL Server 2019 (RTM-CU15) (KB5008996) - 15.0.4198.2 (X64). I tried the same code with com.microsoft.sqlserver:mssql-jdbc:10.2.0.jre8 and com.microsoft.sqlserver:mssql-jdbc:11.1.1.jre8-preview drivers and got the same behavior.
I analyzed the SQL Server query history, and the Java code made only one query to fetch the next sequence value per execution.
According to Gary's answer to a similar question, this is a known behavior when using the selectMethod=cursor option. Just remove this option from the connection URL, and sequence numbers won't skip anymore.
What if you must use selectMethod=cursor for some reason? Then try the sys.sp_sequence_get_range stored procedure instead as demonstrated below.
Connection conn = ...;
String sequenceName = "my_seq";
try (CallableStatement statement = conn.prepareCall("{call sys.sp_sequence_get_range(?, ?, ?)}")) {
statement.setString("sequence_name", sequenceName);
statement.setLong("range_size", 1);
statement.registerOutParameter("range_first_value", microsoft.sql.Types.SQL_VARIANT);
statement.execute();
long seq = statement.getLong("range_first_value");
System.out.println(seq);
}
It doesn't skip sequence numbers even if the selectMethod=cursor option is enabled.

sql query returning 0 rows

I have this sql query which runs fine and return 3 rows when run on sql developer but when I execute the same query in a jsp page, it executes properly but doesn't return any rows. There is no problem with database connection because all other queries work fine.
Server - Tomcat 7
database - Oracle 10g
query -
select slno from lbk_tab where log_date = to_date('18-06-2017','DD-MM-YYYY')
jsp -
String dtol = "select slno from lbk_tab where log_date = to_date('18-06-2017','DD-MM-YYYY')";
Statement st = connection.createStatement();
ResultSet resultSet = st.executeQuery(dtol);
if (resultSet.next()) {
out.print(Integer.parseInt(resultSet.getString(1)));
}
Table lbk_tab has columns slno and log_date.
How can I fix this?
Try these things :
Classfiles are being generated afresh ? Clear & re-build project /
workspace.
Print the query and try to run printed query. Theoretically it looks the same from code, but just to be sure..
Check for query being fired at database also, may be java messes
with date object or date format. Hence the actual date fired from jsp says something else while fired at mysql points at something else ? debug / log / print query actually fired at mysql
end.
More clarity is required here, "to_date" referenced in query is
function ? what are column types.
I Think you need to use to_char()
select slno from lbk_tab where log_date = to_char(to_date('18-06-2017','DD-MM-YYYY'))

Can I execute multiple queries separated by semicolon with MySQL Connector/J? [duplicate]

This question already has answers here:
Multiple queries executed in java in single statement
(6 answers)
Closed 4 years ago.
My jdbc driver for mysql db is of version 5.1.25.
I want to execute sql query like so:
statement.execute("select fullName from user where user_id=1; select fullName from user where user_id=2");
And I always receive exception:
Exception in thread "main" 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 'select fullName from user where user_id=2' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1054)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4187)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4119)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2809)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2758)
at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:894)
at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:732)
at dbViewer.model.UserConnectionManager.retrieveRoutinesNames1(UserConnectionManager.java:622)
at dbViewer.model.UserConnectionManager.main(UserConnectionManager.java:637)
BUT when I run this same query(separated by semicolon) from command line it works perfectly and outputs two tables as expected.
Using ; in a query for most databases doesn't work as it is usually not part of the statement syntax itself, but a terminator for command line or script input to separate statements. The command line or script processor sees a semi-colon as the signal that the statement is complete and can be sent to the server.
Also in JDBC a single statement prepare (or execute) should only be one actual statement so multiple statements are not allowed and so there is also no need to have a semi-colon, and as for some (most?) databases the semi-colon isn't part of the statement syntax, it is simply a syntax error to have one included.
If you want to execute multiple statements, you need to use separate executes. Technically, MySQL does have an option to support multiple executions which can be enabled by a connection property. This behavior is not compliant with the JDBC specification/API and makes your code less portable. See allowMultiQueries on Driver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J
I want to execute sql query like so:
statement.execute("select fullName from user where user_id=1; select fullName from user where user_id=2");
This is possible only when you have set one database connection property to allow multiple queries to execute all at once. And the property name is allowMultiQueries=true. This property has to be set and send along with a database connection request to the server. General syntax is like this:
String dbUrl = "jdbc:mysql:///test?allowMultiQueries=true";
This is additional connection property to those if already exists some, like autoReConnect=true, etc.
Acceptable values for allowMultiQueries property are true, false, yes, and no. Any other value is rejected at runtime with an SQLException.
You have to use execute( String sql ) or its other variants to fetch results of the query execution.
multiQuerySqlString = "select fullName from user where user_id=1; ";
multiQuerySqlString += "select fullName from user where user_id=2; ";
// you can multiple types of result sets
multiQuerySqlString += "select last_login from user_logs where user_id=1; ";
boolean hasMoreResultSets = stmt.execute( multiQuerySqlString );
To iterate through and process results you require following steps:
int rsNumber = 0;
while ( hasMoreResultSets ) {
rsNumber += 1;
Resultset rs = stmt.getResultSet();
// based on the structure of the result set,
// you can handle column values.
if ( rsNumber == 1 ) {
while( rs.next() ) {
// handle your rs here
} // while rs
} // if rs is 1
else if ( rsNumber == 2 ) {
// call a method using this rs.
processMyResultSet( rs ); // example
} // if rs is 2
// ... etc
// check whether there exist more result sets
hasMoreResultSets = stmt.getMoreResults();
} // while results
Refer to:
Multiple queries executed in java in single statement
One of the similar postings on SO, for which I gave an answer.
No you can't. What are you expecting to get by calling statement.execute(...)?
It returns one ResultSet (... which means one table).
You can just call "select fullName from user where user_id in (1, 2)" to geht back both results.
Having semicolons in JDBC statements is very error prone in general. Some JDBC drivers do not support this (e.g. IBM's JDBC driver for DB2 10.x throws an exception if you close your SQL statement with ";").

different results from query in java code and on oracle db server: but no connection error

I have java code that connects to a remote oracle 11g EE db server. If i run a particular query in sqlplus it returns one result
SQL> SELECT COURSENAME from COURSES where skillID=1;
COURSENAME
--------------------
basic
But if I run the same query from the java code below it returns no results. I can copy the query syntax out of the query variable in the java debugger and running it on oracle so I know there is no syntax issue with the query. Also, it is not SQL exceptions or class not found exceptions so it seems to be running the query successfully -- just returning zero results.
What might be going on?
private String getCourseForSkill(int skillID){
try{
Class.forName("oracle.jdbc.OracleDriver");
String query="SELECT COURSENAME from COURSES where skillID=" + skillID ;
con = DriverManager.getConnection(url, user, password);
Statement stmt = con.createStatement();
rs = stmt.executeQuery(query);
rs.next();
return rs.getString("COURSENAME");
}
catch (ClassNotFoundException ex){
System.out.println(ex.getMessage());
}
catch (SQLException ex) {
System.out.println(ex.getMessage());
}
return null;
}
I think you're connecting to different Oracle instances, or more likely, as different Oracle users in the two cases
#GreyBeardedGeek the URL looks like "jdbc:oracle:thin:#website:port:orcl I get to the manual query by doing ssh#website, authenticating and then running command=sqlplus
Safer to run sqlplus <username>/<password>#<orainstancename>, because you can explicitly specify the oracle instance ID. In your case, it seems your program is using jdbc connection jdbc:oracle:thin:#website:port:orcl, so your orainstancename would be 'orcl' - just ensure that your tnsnames.ora file has the instance 'orcl' with the same 'port' as used by the jdbc connection
How to debug a little more
Run the following code:
con = DriverManager.getConnection(url, user, password);
con.setAutoCommit(false);
String insert="INSERT INTO COURSES (SKILLID, COURSE)"+ // can add other columns
"values (?, ?) );" // add ? for other columns
PreparedStatement ps = con.createPreparedStatement();
ps.setInt(1, 999);
ps.setString(2, "Complete Bullwarks");
// can set other columns
ps.executeUpdate(insert);
con.commit();
NOW connect manually, re-run your original select statement & see if the added row is there. If no error in java and no new row in Oracle: extremely likely you're using 2 different Oracle instances/schemas.
ALSO rerun your original java select code, but with SkillID=999 - extremely likely it will work.
Cheers
I had to do a commit to add the rows. When I typed commit; into the sql plus terminal then the remote jdbc connection could 'see' the rows. I am used to SQL server where you don't have to explicitly do these kinds of commits when using linq-to-sql or sql management studio.
It can be three issues.
1) skillID <> 1 in your Java code. Add debug and check.
2a) You are connecting to another database.
2b) You are connecting to the same database but SELECTING from a table in another schema.
To check 2a and 2b:
select user from dual; -- connect username
select name from v$database; -- database name
select host_name from v$instance; -- host name database is running on
This query returns all three into one result.
select user || '' || d.name || '' || i.host_name
from v$database d, v$instance i;
Assuming you are actually connecting to the same database this is caused by not committing the INSERT in the sql*plus connection.
Oracle by default does not run in auto-commit mode when connecting via OCI (which sql*plus uses to connect). Any DML(INSERT ...) executed in sql*plus will not be visible to any other session until it is committed. This is because Oracle provides a read committed isolation level by default. The only thing visible to other users across sessions are write locks.
It doesn't matter if you connect the second connection via JDBC or OCI, it won't see the changes till you commit the first connection.
To test this out try opening 2 sql*plus connections and run the following:
-- Executing DDL in Oracle causes an implicit commit before and after the
-- command so the second connection will see the existence of this table:
CREATE TABLE foobar ( x VARCHAR(1) );
Execute this in connection #1 - you should get zero (we haven't inserted anything yet):
SELECT COUNT(*) FROM foobar;
Execute this in connection #2:
INSERT INTO foobar ( x ) VALUES ( 'A' );
Execute this in connection #1 - you should still get zero (INSERT is not committed so connection #1 cannot see it):
SELECT COUNT(*) FROM foobar;
Execute this in connection #2:
COMMIT;
Execute this in connection #1 - you should get 1 (it's committed now):
SELECT COUNT(*) FROM foobar;

Why am I getting these errors from Apache Derby?

I run my program, the database is connected to and then it gives me two errors. One saying
'Schema "ROOT" does not exist'
and another saying
'Lexical error at line 1, column 8. Encountered: "#"(64), after:"".
Here is the code from the two SQL statements:
private void UpdateJTable() {
String sql ="select idhonscores AS RowNo , Name, Characters, Kills, Deaths, Assists, XPM, CK from honscores";
try {
st = conn.prepareStatement(sql);
rs = st.executeQuery();
table.setModel(DbUtils.resultSetToTableModel(rs));
} catch(Exception e) {
JOptionPane.showMessageDialog(null, e);
}
}
That is from the first error and
String sql3 ="SELECT "+"#rn:=#rn+1"+" AS Rank, Name, Kills
FROM (Select Name, sum(Kills) as Kills
from honscores group by Name order by Kills DESC) t1,
(SELECT "+"#rn:=0"+") t2;";
Is for the second error
In derby the default schema is always the schema of the user you use to create the jdbc connection. I can't tell from you question, how you initialize and setup the derby database. But appending ;create=true to the jdbc-url might help (this will create the db and schema if it does not exist).
You can change to a different schema by executing:
SET SCHEMA MYSCHEMA;
The #-syntax might not be available in derby. Not everything that works in another db (especially if it is db specific) will work in derby.
What has been said about username being the default schema is true. If you do not specify a username the default schema will be APP. This schema always exists. If you connect as user root the schema "root" will not be created until you create a table in it. E.g:
ij> connect 'jdbc:derby:memory:foo;user=root;create=true';
ij> show schemas;
TABLE_SCHEM
------------------------------
APP
NULLID
SQLJ
SYS
SYSCAT
SYSCS_DIAG
SYSCS_UTIL
SYSFUN
SYSIBM
SYSPROC
SYSSTAT
11 rows selected
ij> create table foo(i int) ;
0 rows inserted/updated/deleted
ij> show schemas;
TABLE_SCHEM
------------------------------
APP
NULLID
ROOT
SQLJ
SYS
SYSCAT
SYSCS_DIAG
SYSCS_UTIL
SYSFUN
SYSIBM
SYSPROC
SYSSTAT
12 rows selected
Wrt. # in table and column names: That is only allowed if you quote the name containing #. E.g.:
ij> create table #T#(#c# int);
ERROR 42X02: Lexical error at line 1, column 14. Encountered: "#" (64), after : "".
ij> create table "#T#"("#c#" int);
0 rows inserted/updated/deleted
ij> insert into "#T#" values (0),(1),(2);
3 rows inserted/updated/deleted
ij> select * from "#T#";
#c#
-----------
0
1
2
3 rows selected
Note however, that when quoting a name it becomes case-sensitive. So in the previous example the following fails:
ij> select * from "#t#";
ERROR 42X05: Table/View '#t#' does not exist.
because in quotes, #T# and #t# are considered different names.

Categories

Resources