Retrieving data from oracle table using scala jdbc giving wrong results - oracle

I am using scala jdbc to check whether a partition exists for an oracle table. It is returning wrong results when an aggregate function like count(*) is used.
I have checked the DB connectivity and other queries are working fine. I have tried to extract the value of count(*) using an alias, But it failed. Also tried using getString. But it failed.
Class.forName(jdbcDriver)
var connection = DriverManager.getConnection(jdbcUrl,dbUser,pswd)
val statement = connection.createStatement()
try{
val sqlQuery = s""" SELECT COUNT(*) FROM USER_TAB_PARTITIONS WHERE
TABLE_NAME = \'$tableName\' AND PARTITION_NAME = \'$partitionName\' """
val resultSet1 = statement.executeQuery(sqlQuery)
while(resultSet1.next())
{
var cnt=resultSet1.getInt(1)
println("Count="+cnt)
if(cnt==0)
// Code to add partition and insert data
else
//code to insert data in existing partition
}
}catch(Exception e) { ... }
The value of cnt always prints as 0 even though the oracle partition already exists. Can you please let me know what is the error in the code? Is this giving wrong results because I am using scala jdbc to get the result of an aggregate function like count(*)? If yes, then what would be the correct code? I need to use scala jdbc to check whether the partition already exists in oracle and then insert data accordingly.

This is just a suggestion or might be the solution in your case.
Whenever you search the metadata tables of the oracle always use UPPER or LOWER on both side of equal sign.
Oracle converts every object name in to the upper case and store it in the metadata unless you have specifically provided the lower case object name in double quotes while creating it.
So take an following example:
-- 1
CREATE TABLE "My_table_name1" ... -- CASE SENSISTIVE
-- 2
CREATE TABLE My_table_name2 ... -- CASE INSENSITIVE
In first query, we used double quotes so it will be stored in the metadata of the oracle as case sensitive name.
In second query, We have not used double quotes so the table name will be converted into the upper case and stored in the metadata of the oracle.
So If you want to create a query against any metadata in the oracle which include both of the above cases then you can use UPPER or LOWER against the column name and value as following:
SELECT * FROM USER_TABLES WHERE UPPER(TABLE_NAME) = UPPER('<YOUR TABLE NAME>');
Hope, this will help you in solving the issue.
Cheers!!

Related

How to validate a query without executing in PowerBuilder

wondering if there is way to validate a query before executing
Is there way to check/validate Query without executing it?
One way that we validate SQL is to add a condition to the SQL that could never be true.
Example:
long ll_rc
long ll_result
string ls_sql, ls_test
string ls_message
//Arbitrary SQL
ls_sql = "SELECT * FROM DUAL"
//This SQL when executed will always return 0 if successful.
ls_test = "select count(*) from ( " + ls_sql + " WHERE 1 = 2 )"
DECLARE l_cursor DYNAMIC CURSOR FOR SQLSA ;
PREPARE SQLSA FROM :ls_test;
OPEN DYNAMIC l_cursor;
ll_rc = SQLCA.SQLCODE
choose case ll_rc
case 0
//Success
ls_message = "SQL is properly formed"
case 100
//Fetched row not found. This should not be the case since we only opened the cursor
ls_message = SQLCA.SQLERRTEXT
case -1
//Error; the statement failed. Use SQLErrText or SQLDBCode to obtain the detail.
ls_message = SQLCA.SQLERRTEXT
end choose
CLOSE l_cursor ; //This will fail if open cursor failed.
messagebox( "Result", ls_message )
Note: If your SQL is VERY complicated, which I suspect it isn't, the database optimizer may take several seconds to prepare your SQL. It will be significantly less time than if you run the entire query.
Since the database is the final arbitrator for what is "valid" (table and column names and such) the general answer is no. Now you could come up with a class in PB which checks statement syntax, object names, etc. so you wouldn't have to touch the db but it would be obsolete as soon as any changes were made to the db.
Put the select statement in any script and compile it. Part of the work will be to check the SQL syntax against the database you are connected to.
Watch out: you need at least one bound variable in the column list of your SQL statement. This is not the case for other DML statements.
Example:
in my case:
select noms into :ls_ttt from contacts;
results in a message Unknown columns 'noms' in 'field list'.
However,
select nom into :ls_ttt from contacts;
does not show any error.
Hope this helps.

Oracle no index for function calls in sql query

I have a table with name t(abc varchar2(50),xyz varchar2(50), ..etc) and index enabled on column abc. Oracle uses the index for userfunction(a) which takes long time. This is a dynamic query formed can have another conditions that must use index on abc so I don't want to use no_index hint.
select *from t
where
userfunction(a) = 0
and exists (select 1 from tab where t.abc='' ...etc)
and ..etc
I tried to re-write the query with nested query by moving the function to nested query, but oracle is re-writing and still executing userfunction(a) at the first and the query is taking long time.
select *from (
select *from t
where
and exists (select 1 from tab where t.abc='' ...etc)
..etc
)
userfunction(a) = 0
Also tried using WITH clause but no luck.
Any idea of oracle not to use index for user function calls or certain condition in where clause?
Your query is not logically consistent: you reference table t and tab, but only desribe t. Assuming you meant t when you wrote tab, I can't see why you need the exists clause with a sub-query. EXISTS will just return TRUE when the expression in the subselect evaluates to TRUE; so why not just use that expression in the main query on t?

PL SQL - Stored procedure update column if parameter is not NULL

I've written a stored procedure that updates a table.
But I would like to take into account where one or more of the parameters are NULL.
In such an instance, I don't want to update the column, I want to leave the existing value as is.
I've tried to use:
UPDATE
VS_USER_T
SET
USR_FIRST_NAME = ISNULL(p_NewUsrFName, #p_NewUsrFName)
WHERE
USR_ID = lv_Num_UsrId;
But I get an error on the '#', I'm using Oracle 12c.
This is the procedure call
PROCEDURE UpdateUser
( p_UserId IN VS_USER_T.USR_ID%TYPE,
p_NewUsrFName IN VS_USER_T.USR_FIRST_NAME%TYPE,
p_NewUsrLName IN VS_USER_T.USR_LAST_NAME%TYPE,
p_NewUsrname IN VS_USER_T.USR_LOGIN%TYPE)
Please advise how my UPDATE statement should look like, when 'p_NewUsrname ' can be NULL, in which case I want to leave the existing value as is.
Thanks in advance.
To keep the existing value you need to refer to the existing column value:
USR_FIRST_NAME = ISNULL(p_NewUsrFName, USER_FIRST_NAME)
or you could use:
USR_FIRST_NAME = CASE WHEN p_NewUsrFName is null THEN USER_FIRST_NAME ELSE NewUsrFName END
ISNULL() is not yet a standard Oracle function (at least in the Oracle 12c version that you say you are using). If is of course possible to write a PL/SQL function called ISNULL() and use that.
For a standard Oracle 12c installation, try using NVL or COALESCE instead.
USR_FIRST_NAME = NVL(p_NewUsrFName, USR_FIRST_NAME)
or
USR_FIRST_NAME = COALESCE(p_NewUsrFName, USR_FIRST_NAME)
You could use a decode statement e.g.
update my_table t
set username = decode(p_NewUsrname, NULL, t.username, p_NewUsrname)
where t.id = p_UserId;

oracle not using defined indexes

As seen below there is a simple join between my Tables A And B.
In addition, there is a condition on each table which is combined with Or operator.
SELECT /*+ NO_EXPAND */
* FROM IIndustrialCaseHistory B ,
IIndustrialCaseProduct A
where (
A.ProductId IN ('9_2') OR
contains(B.KeyWords,'%some text goes here%' ) <=0
)
and ( B.Id = A.IIndustrialCaseHistoryId)
on ProductId defined a b-tree index and for KeyWords there is a function index.
but I dont know why my execution plan dose not use these indexes and performs table access full?
as I found in this URL NO_EXPAND optimization hint could couse using indexes in execution plan(The NO_EXPAND hint prevents the cost-based optimizer from considering OR-expansion for queries having OR conditions or IN-lists in the WHERE clause ). But I didn't see any use of defined indexes
whats is oracle problem with my query?!
Unless there is something magical about the contains() function that I don't know about, Oracle cannot use an index to find a matching value that leads with a wildcard, i.e. a text string value within a varchar2 column but not starting in the first position with that value. [OR B.KeyWords LIKE'%some text goes here%' -- as opposed to -- OR B.KeyWords LIKE'Some text starts here%' -- optimizable via index.] The optimizer will default back to the full table scan in that case.
Also, although it may not be material, why use IN() if there is only one value in the list? Why not A.ProductId = '9_2' ?

h2 index corruption? embedded database loaded with runscript has "invisible" rows

Using h2 in embedded mode, I am restoring an in memory database from a script backup that was previously generated by h2 using the SCRIPT command.
I use this URL:
jdbc:h2:mem:main
I am doing it like this:
FileReader script = new FileReader("db.sql");
RunScript.execute(conn,script);
which, according to the doc, should be similar to this SQL:
RUNSCRIPT FROM 'db.sql'
And, inside my app they do perform the same. But if I run the load using the web console using h2.bat, I get a different result.
Following the load of this data in my app, there are rows that I know are loaded but are not accessible to me via a query. And these queries demonstrate it:
select count(*) from MY_TABLE yields 96576
select count(*) from MY_TABLE where ID <> 3238396 yields 96575
select count(*) from MY_TABLE where ID = 3238396 yields 0
Loading the web console and using the same RUNSCRIPT command and file to load yields a database where I can find the row with that ID.
My first inclination was that I was dealing with some sort of locking issue. I have tried the following (with no change in results):
manually issuing a conn.commit() after the RunScript.execute()
appending ;LOCK_MODE=3 and the ;LOCK_MODE=0 to my URL
Any pointers in the right direction on how I can identify what is going on? I ended up inserting :
Server.createWebServer("-trace","-webPort","9083").start()
So that I could run these queries through the web console to sanity check what was coming back through JDBC. The problem happens consistently in my app and consistently doesn't happen via the web console. So there must be something at work.
The table schema is not exotic. This is the schema column from
select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME='MY_TABLE'
CREATE MEMORY TABLE PUBLIC.MY_TABLE(
ID INTEGER SELECTIVITY 100,
P_ID INTEGER SELECTIVITY 4,
TYPE VARCHAR(10) SELECTIVITY 1,
P_ORDER DECIMAL(8, 0) SELECTIVITY 11,
E_GROUP INTEGER SELECTIVITY 1,
P_USAGE VARCHAR(16) SELECTIVITY 1
)
Any push in the right direction would be really appreciated.
EDIT
So it seems that the database is corrupted in some way just after running the RunScript command to load it. As I was trying to debug to find out what is going on, I tried executing the following:
delete from MY_TABLE where ID <> 3238396
And I ended up with:
Row not found when trying to delete from index "PUBLIC.MY_TABLE_IX1: 95326", SQL statement:
delete from MY_TABLE where ID <> 3238396 [90112-178] 90112/90112 (Help)
I then tried dropping and recreating all my indexes from within the context, but it had no effect on the overall problem.
Help!
EDIT 2
More information: The problem occurs due to the creation of an index. (I believe I have found a bug in h2 and I have working on creating a minimal case that reproduces it). The simple code below will reproduce the problem, if you have the right set of data.
public static void main(String[] args)
{
try
{
final String DB_H2URL = "jdbc:h2:mem:main;LOCK_MODE=3";
Class.forName("org.h2.Driver");
Connection c = DriverManager.getConnection(DB_H2URL, "sa", "");
FileReader script = new FileReader("db.sql");
RunScript.execute(c,script);
script.close();
Statement st = c.createStatement();
ResultSet rs = st.executeQuery("select count(*) from MY_TABLE where P_ID = 3238396");
rs.next();
if(rs.getLong(1) == 0)
System.err.println("It happened");
else
System.err.println("It didn't happen");
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I have reduced the db.sql script to about 5000 rows and it still happens. When I attempted to go to 2500 rows, it stopped happening. If I remove the last line of the db.sql (which is the index creation), the problem will also stop happening. The last line is this:
CREATE INDEX PUBLIC.MY_TABLE_IX1 ON PUBLIC.MY_TABLE(P_ID);
But the data is an important player in this. It still appears to only ever be the one row and the index somehow makes it inaccessible.
EDIT 3
I have identified the minimal data example to reproduce. I stripped the table schema down to a single column, and I found that the values in that column don't seem to matter -- just the number of rows. Here is the contents of (snipped with obvious stuff) of my db.sql generated via the SCRIPT command:
;
CREATE USER IF NOT EXISTS SA SALT '8eed806dbbd1ea59' HASH '6d55cf715c56f4ca392aca7389da216a97ae8c9785de5d071b49de5436b0c003' ADMIN;
CREATE MEMORY TABLE PUBLIC.MY_TABLE(
P_ID INTEGER SELECTIVITY 100
);
-- 5132 +/- SELECT COUNT(*) FROM PUBLIC.MY_TABLE;
INSERT INTO PUBLIC.MY_TABLE(P_ID) VALUES
(1),
(2),
(3),
... snipped you obviously have breaks in the bulk insert here ...
(5143),
(3238396);
CREATE INDEX PUBLIC.MY_TABLE_IX1 ON PUBLIC.MY_TABLE(P_ID);
But that will recreate the problem. [Note that my numbering skips a number every time there was a bulk insert line. So there really is 5132 rows, though you see 5143 select count(*) from MY_TABLE yields 5132]. Also, I seem to be able to recreate the problem in the WebConsole directly now by doing:
drop table MY_TABLE
runscript from 'db.sql'
select count(*) from MY_TABLE where P_ID = 3238396
You have recreated the problem if you get 0 back from the select when you know you have a row in there.
Oddly enough, I seem to be able to do
select * from MY_TABLE order by P_ID desc
and I can see the row at this point. But going directly for the row:
select * from MY_TABLE where P_ID = 3238396
Yields nothing.
I just realized that I should note that I am using h2-1.4.178.jar
The h2 folks have already apparently resolved this.
https://code.google.com/p/h2database/issues/detail?id=566
Just either need to get the code from version control or wait for the next release build. Thanks Thomas.

Resources