Unable to DROP Index (Sybase) on a table from Java Code - java

I have a Stored Procedure which drops index on a particular table in the DB. This SP when executed from Database console works fine without errors.
When I use JDBC to execute the SP using a Callable Statement, it gives an SQL exception and says the index cannot be dropped.
When checked on the database, the indexes are dropped too.
CREATE PROCEDURE sp_drop_idx as
BEGIN
DROP INDEX sp_close_1.XPKusr1
DROP INDEX sp_close_1.ilxuser22
DROP INDEX sp_close_1.indx_billid1
DROP INDEX sp_close_1.cycle_ind
END
GO
This SP is called within another SP, let's call that outerSP from the java code using plain JDBC call.
cb = conn.prepareCall("{call outerSP}");
s = cb.executeQuery();
while(rs.next()){
num = (Integer)rs.getInt(1);
}

It was a simple change in the SP :
For every index we used an IF condition -
IF EXISTS(select * from sysindexes where id = object_id('sp_close_1') and name ='XPKusr1')
DROP INDEX sp_close_1.XPKusr1

Related

Select Not returning results when an Update statement is running on the same row?

I have a table where it has columns as
Task_Track
TaskID Number (PK AutoGeneratedSequence)
TaskCd Varchar2
RefCd Varchar2
RefID varchar2
Params varchar2
...etc
I am working on a scenario where I run a select query on this table get the result set.
Select * from Task_Track where RefCd = ? and RefID = ? and TaskCd = ?;
If i don't have any results I will insert a new task with RefCd RefID TaskCd Params values. Params is ususaly a person_id related to the task.
If i get the resultset I will append the new param and update the resultset.
if(resultset!=null and resultSet.length()>0)
update params logic
else
insert new task logic.
This is working as expected in a sequential run.
But when I have 2 parallel queues running and get the same RefCd RefID TaskCd values at the same time.
My first bucket is finding the resultset and is going to perform the update logic as expected but the second queue is not able to find the result and is going into insert logic.
From what I understand even if the first queue has locked the row for the update, the second queue should not have any problems with the read and should fail while updating because of the lock if the first queue hasn't released the lock. But my read itself is failing where it is not throwing any exception but returning an empty resultset(length=0). Because of which it is moving into insert logic.
Is it possible that the read is affected by the update happening in parallel? If so how should I resolve it?
Note: I am using Oracle 11G and Java8 with Websphere 9
Thank you
You need to cache the resultSet before make another request. Try this:
CachedRowSet crs = RowSetProvider.newFactory().createCachedRowSet();
crs.populate(myResultSet);

Checking if table exist or not

I am retrieving data from database using jdbc. In my code I am using 3-4 tables to get data. But sometimes if table is not present in database my code gives exception. How to handle this situation. I want my code to continue working for other tables even if one table is not present. Please help.
I have wrote a code like this
sql="select * from table"
now Result set and all.
If table is not present in database it give exception that no such table. I want to handle it. In this code I cannot take tables which are already present in advance . I want to check here itself if table is there or not.
Please do not mark it as a duplicate question. The link you shared doesnot give me required answer as in that question they are executing queries in database not through JDBC code
For Sybase ASE the easiest/quickest method would consist of querying the sysobjects table in the database where you expect the (user-defined) table to reside:
select 1 from sysobjects where name = 'table-name' and type = 'U'
if a record is returned => table exists
if no record is returned => table does not exist
How you use the (above) query is up to you ...
return a 0/1-row result set to your client
assign a value to a #variable
place in a if [not] exists(...) construct
use in a case statement
If you know for a fact that there won't be any other object types (eg, proc, trigger, view, UDF) in the database with the name in question then you could also use the object_id() function, eg:
select object_id('table-name')
if you receive a number => the object exists
if you receive a NULL => the object does not exist
While object_id() will obtain an object's id from the sysobjects table, it does not check for the object type, eg, the (above) query will return a number if there's a stored proc named 'table-name'.
As with the select/sysobjects query, how you use the function call in your code is up to you (eg, result set, populate #variable, if [not] exists() construct, case statement).
So, addressing the additional details provided in the comments ...
Assuming you're submitting a single batch that needs to determine table existence prior to running the desired query(s):
-- if table exists, run query(s); obviously if table does not exist then query(s) is not run
if exists(select 1 from sysobjects where name = 'table-name' and type = 'U')
begin
execute("select * from table-name")
end
execute() is required to keep the optimizer from generating an error that the table does not exist, ie, the query is not parsed/compiled unless the execute() is actually invoked
If your application can be written to use multiple batches, something like the following should also work:
# application specific code; I don't work with java but the gist of the operation would be ...
run-query-in-db("select 1 from sysobjects where name = 'table-name' and type = 'U'")
if-query-returns-a-row
then
run-query-in-db("select * from table-name")
fi
This is the way of checking if the table exists and drop it:
IF EXISTS (
SELECT 1
FROM sysobjects
WHERE name = 'a_table'
AND type = 'U'
)
DROP TABLE a_table
GO
And this is how to check if a table exists and create it.
IF NOT EXISTS (
SELECT 1
FROM sysobjects
WHERE name = 'a_table'
AND type = 'U'
)
EXECUTE("CREATE TABLE a_table (
col1 int not null,
col2 int null
)")
GO
(They are different because in table-drop a temporary table gets created, so if you try to create a new one you will get an exception that it already exists)
Before running the query which has some risk in table not existing, run the following sql query and check if the number of results is >= 1. if it is >= 1 then you are safe to execute the normal query. otherwise, do something to handle this situation.
SELECT count(*)
FROM information_schema.TABLES
WHERE (TABLE_SCHEMA = 'your_db_name') AND (TABLE_NAME = 'name_of_table')
I am no expert in Sybase but take a look at this,
exec sp_tables '%', '%', 'master', "'TABLE'"
Sybase Admin

Invalid character encountered error - selecting rows

I am trying to get rows from table using SQLDeveloper by writing simple query:
SELECT * FROM agreements WHERE agreementkey = 1;
SELECT * FROM agreements WHERE agreementkey = 4;
but getting invalid character encountered error. It's not a problem with query(working using other keys, i.e. agreementkey = 3) but with XMLType column in this table - there is something wrong with data in some rows. Is there a way to select this affected row(I know keys of this affected rows) using queries? Maybe export to file or something? Solution of copying value manually is not acceptable.
Create an empty copy of the table and then run an INSERT into it based on a select from the original table but do it using the DML error logging clause.
This should show you any rows that fail to load and the reason for the failure.
CREATE TABLE test_agreements
AS SELECT * FROM agreements
WHERE ROWNUM <1;
INSERT INTO test_agreements
SELECT *
FROM agreements
LOG ERRORS REJECT LIMIT UNLIMITED
This will create you an error logging table called ERR$TEST_AGREEMENTS which you can query to find the problem rows.
Problem is in WHERE key = 1 cause key is a Reserve Word in Oracle. You should escape it like
SELECT * FROM table WHERE "key" = 1;
KEY is a reserved word so to overcome that you need to use double quotes "".
SELECT * FROM table WHERE "key" = 1;
I think the problem can be solved by putting the argument in quotes:
SELECT * FROM agreements WHERE agreementkey = "1";
I wish I were familiar with XML, but I have run into this with VARCHAR2 columns that are supposed to have all numeric values. Oracle looks at the request
where agreementkey = 1
and tries to convert agreementkey to a number rather than 1 to a varchar2.
If the database contains invalid characters I would try one the following:
Maybe the solution of BriteSponge will work, using an insert statemant with error logging clause.
Use datapump to export the data to a file. I think the log will contain information to identify the invalid columns.
There was a tool called "character set scanner" that checked the characters of the data of a table, here is some documentation: CSSCAN. Or maybe you can use the Database Migration Assistent for Unicode (DMU) mentioned in the same manual.
4- You can write a small PL/SQL program that retrieves the rows row by row and in case of an error catches the exception and notifies you about the row.
DECLARE
invalid_character_detected EXCEPTION;
PRAGMA EXCEPTION_INIT(invalid_character_detected, ???); begin
for SELECT rowid into rec FROM agreements do begin
for
SELECT * into dummy
FROM agreements
where rowid=rec.rowid
do
null;
end loop;
except
WHEN invalid_character_detected THEN
dbms_ouput.put_line(rec.rowid)
end;
end loop;
end;
I did not compile and test the program. ??? is the (negative) error code, e.g. -XXXXX if the error is ORA-XXXXX

Returning just column names of ResultSet without actually performing the query (Oracle and Java)

I'm wondering if there is a way to return the column names of a results set (Oracle database, in Java) that would be generated IF I actually executed a query. For example, say I had SQL looking something like this:
select * from <complex table join>;
Is there a way to send this query to oracle and have it tell me just what the column names are on the result set it will return WITHOUT actually performing the query (because it is expensive)?
I think using a PreparedStatement could work:
PreparedStatement stmt = connection.prepareStatement("select ...");
ResultSetMetaData meta = stmt.getMetaData();
for (int col=0; col < meta.getColumnCount(); col++)
{
System.out.println("Column: " + meta.getColumnName(col + 1));
}
(Edit): I tried this with Oracle 11.2 and driver version 11.2.0.3 and it works.
If that fails you could simply append a where 1=0 to the query and execute it then. At least it will not return all the rows then (possibly also using Statement.setMaxRows() as well, just to be sure.
A final (yet pretty complicated) option would be to use dbms_sql to open, prepare and describe the statement. See the manual for details: http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/d_sql.htm
You could try wrapping the query in an outer select and adding where 1=0 to prevent it from fetching any rows:
SELECT * from (
<your query here>
)
WHERE 1=0
SELECT
COLUMN_NAME
FROM
ALL_TAB_COLUMNS
WHERE
TABLE_NAME ='tableName';
is probably what you meant.. however it is still a query...just that instead of querying application tables you are querying special tables
same with answers that request metadata

How to invertly select columns in sql?

If I have a SQL table with columns:
NR_A, NR_B, NR_C, NR_D, R_A, R_B, R_C
and on runtime, I add columns following the column's sequence such that the next column above would be R_D followed by R_E.
My problem is I need to reset the values of columns that starts with R_ (labeled that way to indicate that it is resettable) back to 0 each time I re-run my script . NR_ columns btw are fixed, so it is simpler to just say something like:
UPDATE table set col = 0 where column name starts with 'NR_'
I know that is not a valid SQL but I think its the best way to state my problem.
Any thoughts?
EDIT: btw, I use postgres (if that would help) and java.
SQL doesn't support dynamically named columns or tables--your options are:
statically define column references
use dynamic SQL to generate & execute the query/queries
Java PreparedStatements do not insulate you from this--they have the same issue, just in Java.
Are you sure you have to add columns during normal operations? Dynamic datamodels are most of the time a realy bad idea. You will see locking and performance problems.
If you need a dynamic datamodel, take a look at key-value storage. PostgreSQL also has the extension hstore, check the contrib.
If you don't have many columns and you don't expect the schema to change, just list them explicitly.
UPDATE table SET NR_A=0;
UPDATE table SET NR_B=0;
UPDATE table SET NR_C=0;
UPDATE table SET NR_D=0;
Otherwise, a simple php script could dynamically build and execute your query:
<?php
$db = pg_connect("host=localhost port=5432 user=postgres password=mypass dbname=mydb");
if(!$db) die("Failed to connect");
$reset_cols = ["A","B","C","D"];
foreach ($col in $reset_cols) {
$sql = "UPDATE my_table SET NR_" . $col . "=0";
pg_query($db,$sql);
}
?>
You could also lookup table's columns in Postgresql by querying the information schema columns tables, but you'll likely need to write a plpgsql function to loop over the query results (one row per table column starting with "NR_").
if you rather using sql query script, you should try to get the all column based on given tablename.
maybe you could try this query to get all column based on given tablename to use in your query.
SELECT attname FROM
pg_attribute, pg_type
WHERE typname = 'tablename' --your table name
AND attrelid = typrelid
AND attname NOT IN ('cmin', 'cmax', 'ctid', 'oid', 'tableoid', 'xmin', 'xmax')
--note that this attname is sys column
the query would return all column with given tablename except system column

Categories