I have a query in which I am using Cursors in Select clause along with some other columns Values.I wanted to iterate through its result via ResultSet in Java.But couldn't find a way to get the Cusror from the result set.Is it possible to do so?Can anyone help me?
For eg
select name, roll_no,
cursor (select subj1
from Subject
where id = 'abc'
) as cusr1
from student
Here would be a generic way to read columns from a ResultSet.
while (resultSet.next()) { //Read every row
int columnCount = resultSet.getMetaData().getColumnCount();
for (int column = 1; column <= columnCount; column++) { //Read every column
String columnName = resultSet.getMetaData().getColumnName(column);
Object value = resultSet.getObject(columnName);
if (value != null) {
doSomething(columnName, value);
}
}
}
I assume you are using an Oracle DB.
I also assume Java 7 or higher (try with resources).
You are using a Cursor Expression in your SQL.
The Oracle JDBC Driver returns a java.sql.Resultset object when you call Resultset.getObject(column number|column label) for a Cursor Expression column.
So it is safe to cast:
try (Resultset innerResultset = (Resultset) outerResultset.getObject(column number/label)) {
while(innerResultset.next()) {
...
}
One comment: In many cases, for example when creating "master-detail" queries, you use a correlated Cursor Expression, meaning there is a join on a table that appears in the outer query.
Related
I'm trying to write a generic tool for copying Cassandra table contents from one keyspace to another one (probably in a different cluster). All the tables are not too large.
Here is what I do:
Session source = ...
Session destination = ...
TableMetadata table = ...
final ResultSet rs = source.execute("select * from " + table.getName());
String insertCql = ...
PreparedStatement preparedStatement = destination.prepare(insertCql);
for (Row row : rs) {
final BoundStatement boundStatement = preparedStatement.bind();
for (int i = 0; i < rs.getColumnDefinitions().size(); i++) {
// bind column value from row to bountStatement
}
session.execute(boundStatement);
}
The problem is how to copy the column value from row to boundStatement. I can read it with row.getObject(i), but there is no corresponding setObject() in BoundStatement.
More precisely, this method exists in version 2.2 of the driver (it's cassandra-driver-dse), but that version does not work with Cassandra 3, and in version 3 of the driver (cassandra-driver-core) setObject() method does not exist. Instead, there are bunch of set() methods, all of them require Class, TypeToken or TypeCodec.
Where can I get those? ColumnDefinition only gives me DataType. It seems a doubtful idea to use row.getObject(i).getClass() to get Class.
Maybe there is a better approach to this task (schema-agnostic copying)?
I can look at DataType if the column and make a case per type to use setString() and so on, but this seems a bit overcomplicated and fragile.
You need to use bind variables in your insert statement and then bind the prepared statement with the column values from the result. Something along the lines of:
String insertCql = "INSERT INTO ks.tb (...) values (?,?,...)";
for (Row row : rs) {
List bindVariables = new ArrayList();
for (int i = 0; i < rs.getColumnDefinitions().size(); i++) {
bindVariables.add(rs.getObject(i));
}
final BoundStatement boundStatement = preparedStatement.bind(bindVariables.toArray(new Object[0]));
session.execute(boundStatement);
}
I have following question.
I'm using JDBC in my project and I made simple method to insert data into my database.
My problem is: What to do when I want to insert something like sysdate or just NULL to auto increment? To my method I send only strings and writing NULL to string doesn't work.
Can you give me any advice how to improve it?
This is the code with constant null in query, but it isn't what I want to.
public static void insertInto(String Table, ArrayList<String> values) throws SQLException
{
Connection conn = JavaConnectDB.ConnectDb();
OraclePreparedStatement pst = null;
StringBuilder Query = new StringBuilder("INSERT INTO " + Table + " VALUES (NULL, ");
for (int i = 0; i < values.size(); i++)
{
Query.append("? ");
if (i + 1 != values.size())
Query.append(", ");
}
Query.append(")");
pst = (OraclePreparedStatement) conn.prepareStatement(Query.toString());
for (int i = 0; i < values.size(); i++)
{
pst.setString(i + 1, values.get(i));
}
pst.executeUpdate();
}
This method creates query like "INSERT INTO TABLE VALUES (NULL, ?, ? ,?)" and then fills gaps with values from array.
There is java.sql.PreparedStatement.setNull(int, int)
Try, e.g.
pst.setNull(1, Types.BIGINT);
for (int i = 1; i < values.size(); i++)
{
pst.setString(i + 1, values.get(i));
}
Change Types.BIGINT for apporpriate type for your column.
Note, that values.get(0) is just ignored, but should present in the array.
Problem is the setString function. If you have a string "NULL" or "SYSDATE", it will result in the query being quoted ('NULL', 'SYSDATE'), so this will be inserted as string.
According to this answer, pst.setString(n, null) should do the trick already, so inserting SQL NULL values is yet relatively easy, just insert a Java null value into the array where you want the database value to be SQL NULL.
SYSDATE gets more delicate. But I think, here comes something more fundamental into play: how are you going to handle data types other than VARCHAR (see setString documentation). If you really wanted such a generic method, I would rather to pass ArrayList<Object> as parameter (or with ellipsis ...) and call the appropriate setXXX method for the specific Object type - or setObject with appropriate Type parameter set. You could then create your own class SysDate which could easily be detected.
Is the database layout known to your application? Then I'd rather recommend to have a separate insert method for each table accepting exactly the number of required parameters of correct type, such as
bool insertIntoTest(int someValue, Integer anotherValue, String andAnotherOne)
{
Connection conn = JavaConnectDB.ConnectDb();
OraclePreparedStatement pst
= (OraclePreparedStatement) conn.prepareStatement(
"INSERT INTO TEST (someValue, anotherValue) VALUES(?, ?)"
);
pst.setInt(1, someValue);
if(anotherValue == 0)
pst.setNull(2, Types.INTEGER);
else
pst.setInt(2, anotherValue);
// can handle null already...
pst.setString(3, andAnotherOne);
/* ... (execute, try/catch, return) */
}
Well you should define exactly what do ou want to do.
It's not possible to put null in an autoinkrement field on database by definition
Auto-increment allows a unique number to be generated when a new record is inserted into a table.
So if you want just to insert some filed to your table and delegate the genration of autoincrement to your database, you should create your query like that :
INSERT INTO TABLE VALUES (?, ? ,?).
Example :
Table employee(id,time,name)
Query :
INSERT INTO employee (time, name) VALUES (?, ?)
I want to retrieve all the data from database, and at the same time, I want to know how many rows of data I get. And this is my SQL:
rs = s.executeQuery("SELECT COUNT(*), * FROM tblUser");
Is this a valid SQL statement? and after I retrieved all the data, how to set them into different variables? For example, I have a column called UserIDin the database, I can simply get it by using rs.getString('UserID'), but how to get the result of the COUNT(*)?
Your SQL is not valid. The ANSI standard way to do what you want uses window functions:
select count(*) over () as total_cnt,
u.*
from tblUser u;
This adds a new column to every row -- which seems to be what you want. There are other mechanisms, depending on the underlying database for doing this.
The results you request are not interrelated, so run two queries:
rs1 = s.executeQuery("SELECT COUNT(*) FROM tblUser");
rs2 = s.executeQuery("SELECT * FROM tblUser");
and retrieve the values (one only for rs1) the usual way.
You can do this to count the rows in resultset
String query = "Select * from tblUser";
rs = s.executeQuery(query);
public int getCount(ResultSet rs) {
int rows = 0;
while(rs.next()) {
i++;
}
return i;
}
This way you can get the resultset as well as count
Since you are already accessing the recordset within VBA probably the simplest was to return the count of the record set is to:
rs = s.executeQuery("SELECT * FROM tblUser");
If Not rs.EOF Then
' Important: You must move to the last record to
' obtain the count of the full recordset
rs.MoveLast
rsCount = rs.RecordCount
' Remember to Return to the First Record so that you can
' continue to use the recordset
rs.MoveFirst
End If
An alternative if your RDBMS doesn't support window functions
rs = s.executeQuery("SELECT B.cnt, U.*
FROM tblUser U,
(SELECT count(*) cnt FROM tblUser) B");
I have a database in which more than one row has the same value.
Eg,
Column1 Column2
A X
A Y
A Z
A resultset gets all the values of column 2 as a single string.
How to get each unique value from database (or from result set)?
(I use java)
Thanks in advance.
Have a look at
SELECT columna ,
(SELECT GROUP_CONCAT(DISTINCT columnb SEPARATOR ' ') FROM test
WHERE columna=t.`columna` ) as columnb_string
FROM `test` t GROUP BY columna
Here is Fiddle Example
What is the query/code you are using to get all of column two as a string? It is always a good idea to test your query in the database system itself or you could use SQLFiddle to ensure you are getting the results you are expecting from your query
From the Doc:
A ResultSet object maintains a cursor pointing to its current row of data. Initially the cursor is positioned before the first row. The next method moves the cursor to the next row, and because it returns false when there are no more rows in the ResultSet object, it can be used in a while loop to iterate through the result set.
Read the rest of Java Doc for ResultSet
A typical approach to getting values from the data base is to
//Construct a statement
String yourStatement = "Select COLUMN_B from aTable WHERE COLUMN_A LIKE 'A'" // EDITED
PreparedStatement aPrepStatement = null;
ResultSet rs = null;
List<String> aList = new ArrayList<String>(); // ADDED
try
{
aPrepStatement = yourConnection.prepareStatement(yourStatement)
rs = aPrepStatement.executeQuery();
while(rs.next())
{
// You are now in the first row of data depending on your query
// String column1 = rs.getString(1); // 'A' In the table you descrbed above (for first iteration
String column2 = rs.getString(1); // 'X' In the table you descrbed above
// Now do what you need to with the data
aList.add(column2) // EDITED
}
}
catch (Exception ex) {
// deal with any exceptions that arise
ex.printStackTrace();
}
finally
{
//Close your Resultset and prepared statement (this will possibly need a try catch block also
if(rs != null)
rs.close();
if(aPrepStatement != null)
aPrepStatement.close();
}
// ADDED BELOW
for(String s: aList)
System.out.println(s) // should give output
// X
// Y
// Z
Doc for PreparedStatement and Connection
I have a managed bean which makes SQL queries to Oracle database. This is just very simple example how I make SQL queries. This is the table structure:
GLOBALSETTINGS
---------------------------------
SessionTTL VARCHAR2(40 BYTE)
MAXACTIVEUSERS NUMBER
ACTIVEUSERS VARCHAR2(20 BYTE)
I use this table just to store application settings. In the example listed below I can fetch just one string with one SQL statement. I want with SQL query to fetch the content of the three rows - SessionTTL, MAXACTIVEUSERS, ACTIVEUSERS. Is it possible?
public String CheckUserDB(String userToCheck) throws SQLException {
String storedPassword = null;
String SQL_Statement = null;
if (ds == null) throw new SQLException();
Connection conn = ds.getConnection();
if (conn == null) throw new SQLException();
try {
conn.setAutoCommit(false);
boolean committed = false;
try {
SQL_Statement = "SELECT Passwd from USERS WHERE Username = ?";
PreparedStatement passwordQuery = conn.prepareStatement(SQL_Statement);
passwordQuery.setString(1, userToCheck);
ResultSet result = passwordQuery.executeQuery();
if(result.next()){
storedPassword = result.getString("Passwd");
}
conn.commit();
committed = true;
} finally {
if (!committed) conn.rollback();
}
}
finally {
conn.close();
}
return storedPassword;
}
P.S I want the content of the rows.
I'm hoping I understand what you are asking for, but I fear I don't as it seems too simple, but anyway...
I think you want the contents of 3 columns, not rows. And yes you can, you just specify the columns you want returned in your SQL statement:
SELECT SessionTTL, MAXACTIVEUSERS, ACTIVEUSERS FROM GLOBALSETTINGS WHERE (condition)...
you can also use * as a shortcut for all columns iof you don't want to explicitly specify them:
SELECT * FROM GLOBALSETTINGS WHERE (condition)...
Some background reading on SQL syntax might be useful
If I read this correctly (sorry if mistaken), all you want to do is change your SQL command to select ALL COLUMNS in your database table.
To do so:
string SqlAll = #"SELECT Database.SessionTTL, Database.MAXACTIVEUSERS, Database.ACTIVEUSERS FROM Database";
This will retrieve ALL columns in the database. You can also have conditional statements in your queries when you want to filter for logical reasons, such as TOP 20 to get the first 20 results from the result set.
If you like to return multiple lines with one sql query, you may want to look into ArrayList as you need a loop, where the code would go through your records and match and find all possible results until the end of the records list.