find column names and metadata from select query without executing the query - java

I have a scenario, where the user will provide a Select statement. I need to find out the columns (their names, type, and other metadata), but I do not want to execute the query.
I know that I can execute the query and figure it from the ResultSet, but if the query returns many rows, then it may not be a good approach.
For example, consider the query
select name, age from people where people.dob = '1976';
Is there a way of getting the projected column metadata (i.e. metadata of name and age columns) without executing the query?

Solved this by using a PreparedStatement. A PreparedStatement does not execute the statement.

Related

How to determine type of the sql query for jdbcTemplate in JAVA?

My requirement is I want to determine type of sql query so that I can choose jdbcTemplate method accordingly.
Suppose my sql query is of type insert or update then I will choose
String sql ="insert/update sql query";
jdbcTemplate.update(sql);
jdbcTemplate method and if type of my sql query is select then I will choose
String sql ="select sql query";
jdbcTemplate.query(sql);
jdbcTemplate method.
How to determine type of sql query in java effectively?
Which jdbcTemplate method to choose if my query contains both update and select sql statements? e.g.
update table set column_name="abc" where column_name in (select
column_name from table where column_name ="xyz");
Update: In reality I am accepting sql queries from the users of my application from the web form so that is the reason where actual problem arises because user can post any type of sql query through form and I want to choose specific jdbcTemplate method depending upon type of query.
in Oracle you can parse a query before executing it
declare
l_theCursor integer default dbms_sql.open_cursor;
begin
dbms_sql.parse( l_theCursor, 'SELECT 1 FROM DUAL', dbms_sql.native );
end;
which is a good practice anyway since you will be receiving your SQL from user input. if the statement is not valid you will get the appropriate error message. Of course the statement is not executed by the above.
After parsing the statement you can query v$sql to find out the command_type:
select command_type, sql_text
from v$sql t
where sql_text = 'SELECT 1 FROM DUAL';
The various commands_types are like so:
2 -- INSERT
3 -- SELECT
6 -- UPDATE
7 -- DELETE
189 -- MERGE
you can get the full list by select * from audit_actions order by action
Hope that helps :)
SELECT subqueries are irrelevant for the final result. So the command, the first verb is indicative of the result (int updateCount vs. ResultSet).
boolean isSqlSelect = sql.toUpperCase().startsWith("SELECT")
|| sql.toUpperCase().startsWith("WITH");
You can run an SQL UPDATE query via the .select() method, and you can run an SQL SELECT query via the .update() method.
So why are there 2 different methods?
The update method returns a single number; this number represents the amount of changed/created rows.
The select method returns a resultset, which is like a little table: It has a number of (typed and named) columns, and you can walk through the resultset, getting a row's worth of data every time.
In practice, running a SELECT SQL statement via .update() will run the select (and if that select somehow writes to the DB, for example because you run SELECT NEXTVAL('someSequence'), those effects do occur, but you get 0 back because it didn't change/add any rows to any tables. If you run an UPDATE SQL via .select(), the updates go through, and you get an empty resultset back, or possibly a resultset with 1 column of some numberic type, and one row, with the one value that row has being equal to the update count. It depends on the JDBC driver.
There's another method (execute), which returns nothing. The same applies here: If you run an UPDATE via this method, it still works, you just don't get the updatecount back.
My advice: Use .select for all of it, and write a nice renderer that reports the resultset back to the user.
If you'd like to investigate some code that's already done all this, check out the h2 console.

Is it possible to merge these two queries?

I'm writing a sql query to count objects. I have about 50 pre-written queries, and each of them is essentially written like so:
"select count(1) from SOME_TABLE where identifier = :ID"
I have it in Java. SOME_TABLE is already written into the query (different for each query). At runtime, a switch/case determines which query to execute and which ID to send it.
Essentially, there are various queries which can be called, but ID is the only thing that changes inside the queries.
So, if I want to count all the pinetrees in a forest, I'd send pineTree as an ID to a query that counts Tree. Simple enough. As I mentioned, there's a giant switch/case which determines TABLE_NAME, ID, and the exact query.
The problem is, I'm trying to count all of the objects of a table, and I'm trying to count them with various IDs. For example:
query1: "select count(1) from LIST_OF_TOYS where animalId = theListOfIDsfromQuery2"
query2: "select allThePetIDs from LIST_OF_PETS where ownerId = :myID
This is essentially what I'm trying to do. I want to count all the toys owned by my pets, but there is no direct link between my ID and the LIST_OF_TOYS table.
I know how to do this with two separate queries, but I would strongly prefer to write one query that just takes ownerId as a parameter, so that I can add it to my giant switch/case (and keep my code neat). I can write the query however I want, but I was wondering if it's possible to do this as a single query and a single argument. Thanks for the help!
select count(1) from LIST_OF_TOYS where animalId in (select allThePetIDs from LIST_OF_PETS where ownerId = :myID)

How to execute a SQL statement in Java with many values in a single variable in where in clause

I have to execute below query through JDBC call
select primaryid from data where name in ("abc", adc", "anx");
Issue is inside in clause I have to pass 11000 strings. Can I use prepared statement here? Or any other solution any one can suggest. I dont want to execute the query for each record, as it is consuming time. I need to run this query in very less time.
I am reading the strings from an XML file using DOMParser. and I am using sql server db.
I'm just wondering why you would need to have a manual set of 11,000 items where you need to specify each item. It sounds like you need to bring the data into a staging table
(surely it's not been selected from the UI..?), then join to that to get your desired resultset.
Using an IN clause with 11k literal values is a really bad idea - off the top of my head, I know one major RDBMS (Oracle) that doesn't support more than 1k values in the IN list.
What you can do instead:
create some kind of (temporary) table T_NAMES to hold your names; if your RDBMS doesn't support "real" (session-specific) temporary tables, you'll have to add some kind of session ID
fill this table with the names you're looking for
modify your query to use the temporary table instead of the IN list: select primaryid from data where name in (select name from T_NAMES where session_id = ?session_id) or (probably even better) select primaryid from data join t_names on data.name = t_names.name and t_names.session_id = ?session_id (here, ?session_id denotes the bind variable used to pass your session id)
A prepared statement will need to know the number of arguments in advance - something along the lines of :
PreparedStatement stmt = conn.prepareStatement(
"select id, name from users where id in (?, ?, ?)");
stmt.setInt(1);
stmt.setInt(2);
stmt.setInt(3);
11,000 is a large number of parameters. It may be easiest to use a 'batch' approach as described here (in summary - looping over your parameters, using a prepared statement
each time)
Note - if your 11,000 strings are the result of an earlier database select, then the best approach is to write a stored procedure to do the whole calculation in the database (avoiding passing the 11,000 strings back and forth with your code)
You can merge all your parameter strings into one bitg string separating by ';' char
bigStrParameter=";abc;adc;anx;"
And use LOCATE to find substring.
select primaryid from data where LOCATE(concat(';',name,';'),?)>=0;

Error occurring in Hibernate when join column is String

I have two tables that I want to join using hibernate. The join column, as represented in my model is a String (its a varchar(10) in my database). When I run the HQL query, what I see is the following error, "conversion failed when converting the varchar value 'AS00' to data type int. "AS500" is the first value of join column in the first row.
I do not know why hibernate is doing this. My join column is not an int. I have checked both models corresponding to my tables and they are both defined as Strings. Is there some kind of restriction on the data types that can be used for join columns?
Please post both your model and the hql query.
If I had to take a guess (and that's all any of us can do without specifics), I would say that your hql query does not use .setParameter and it does not have single quotes around the string value in your query... so it is trying to implicitly convert the value to int.
Example that would cause this error:
Query query = session.createQuery("from Person where name = bob");

Determine if JOIN resulted in any columns

I have a sql statement with multiple joins; sometimes there are records resulting from the joins and sometimes not. It is not an error when the joins are empty.
Is there a way to test whether a particular join is empty without having to trap the exception occurring when a resulting column is not found in the result set?
In other words, if, using JDBC, I execute the following sql statement:
select * from AA left outer join BB on AA.keyField = BB.keyField
where keyField = "123"
I would like to know whether that join found any fields without having to trap an exception. If I then execute the java statement:
String valueString = rs.getString("BB.keyField");
I get an exception. I cannot compare rs.getString("BB.keyField") to null, because the getString throws an exception if it did not find any values in the join.
I hope this makes the question more clear, and I apologize for not having expanded on it more in the first place.
The query won't return columns with such names. It will just use the simple names of the columns (name, keyField, etc.). Execute the query inside your database query tool, and you'll see which names are assigned to the retrieved columns.
You should never do a select *, and always select specific columns. And you should assign aliases to columns if two columns have the same name:
select AA.id as aId, AA.name as aName, BB.id as bId, BB.name as bName from ...
And, then, you can safely use
rs.getString("aId");
rs.getString("bName");
...
Also, the exception thrown contains a message, which should help you identify the problem. Read it. And if you don't understand it, post it.

Categories