Issue at like operation for numbers in oracle - java

This is a project on java with openjpa ORM. I have an issue with like selection for type NUMBER(10,2) in Oracle database.
The type of number in JPA is BigDecimal and numbers could be like integer and not integer, for example:
123456
or 123456,01; 123456,15
At presentation layer user has global filter, but not only for this column, where he can choose column and operator (like, equal or between) and define value.
For examaple: column1 like '%56%'
Also numbers at presentation layer has presision 2, so:
123456,00 ->'123456,00'
123456,01 -> '123456,01'
When Oracle database executes like opearaion, nuber is converted ot String type:
123456,00 -> '123456'
and 123456,01 -> '123456,01'
So the result of operation column1 like '%,0%' is only
123456,01 but not both.
I also tried call native SQL function like here but we use OpenJPA 1.2.3 with JPA 1.0 implementation.
Please help me find workaround at my issue.

I don't know if this helps you but on Oracle side you should use:
select *
from your_table
where to_char(your_column,'99999999.99') like '%.0%';

Related

Liquibase preconditions: How do I check for a column being the correct data type?

I have a db upgrade script to change some datatypes on a few columns. I want to do a preCondition check, and call ALTER TABLE only when it is a DECIMAL datatype, but I will want it to be changed to INTEGER.
Couldn't find a predefined precondition for this, and could not write an sqlCheck either.
There's no built-in precondition for column's dataType in liquibase.
You may just check whether the column exists or not. If it's already of the datatype you need, no error will be thrown.
OR
You can use sqlCheck in your preconditions and it'll be something like this:
<preConditions onFail="MARK_RAN">
<not>
<sqlCheck expectedResult="DECIMAL">
SELECT DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'your_table_name'
AND COLUMN_NAME = 'your_column_name'
</sqlCheck>
</not>
</preConditions>
Another answer already mentions how to do a sqlcheck. However, the actual SQL for Teradata would be something different.
In Teradata you would use a query similar to the following and expect the columnType='D' for decimal values
Select ColumnType
From DBC.ColumnsV
Where databasename='yourdatabasename'
and tablename='yourtablename'
and columnname='yourcolumnname';
You could also do something like this if you want a more human readable column type instead of a type code:
Select Type(tablename.columnname);
I know the question was for Teradata, but principle is the same.
I prefer SQL files, so in changelog I have (for Oracle), is:
<include file="roles.sql" relativeToChangelogFile="true" />
and then in roles.sql
there is
--changeset betlista:2022-01-04_2200-87-insert
--preconditions onFail:MARK_RAN
--precondition-sql-check expectedResult:0 select count(*) from ddh_audit.DDH_USER_ROLE where id = 87;
insert into ddh_audit.DDH_USER_ROLE(id, role_name, description)
values(87, 'CONTAINERS_READONLY', 'Can read Containers reference data');
the query added by David Cram would make the trick.
I do not know and I didn't try if condition could be on multiple lines, I know --rollback can.

JOOQ and PostgreSQL types in a DSL select

I have a problem with jOOQ 3.8.
So, I have a table in PostgreSQL 9.5, something like.
CREATE TABLE my_table(
id bigserial,
types my_type[]
)
where the my_type is a type like
CREATE TYPE my_type AS(
id smallint,
something text
)
Now, in jOOQ 3.8 I want to do something like
dsl.selectDistinct(MY_TABLE.ID)
.from(MY_TABLE)
.join(TYPE_TABLE).on(TYPE_TABLE.ID.equal(DSL.any(
MY_TABLE.TYPES.ID
))
.fetch(MY_TABLE.ID);
Clearly the step in which I do MY_TABLE.TYPES.ID is wrong. I was thinking about using DSL.select(MY_TYPE.ID)... but clearly the my_type is a type, not a table.
How can I access type properties using jOOQ?
How to solve this with PostgreSQL
I don't think there's an easy way to transform your my_type[] into an integer[] type in PostgreSQL, extracting my_type.id for each value, for it to be usable with the any() operator.
But you can work around this limitation by using UNNEST(), something like this:
SELECT DISTINCT my_table.id
FROM my_table
CROSS JOIN LATERAL unnest(my_table.types)
The above will yield something like
id types id something
----------------------------------------------
1 {"(1,a)","(2,b)"} 1 a
1 {"(1,a)","(2,b)"} 2 b
2 {"(1,a)","(2,b)","(3,c)"} 1 a
2 {"(1,a)","(2,b)"} 2 b
2 {"(1,a)","(2,b)"} 3 c
Now this, you can join again to TYPE_TABLE, such as:
SELECT DISTINCT my_table.id
FROM my_table
CROSS JOIN LATERAL unnest(my_table.types) types
INNER JOIN type_table ON type_table.id = types.id
Or, probably better performing:
SELECT my_table.id
FROM my_table
WHERE EXISTS (
SELECT 1
FROM type_table
JOIN unnest(my_table.types) AS types ON type_table.id = types.id
)
How to solve this with jOOQ
jOOQ's unnest support is currently (as of version 3.8) rather simple, i.e. you don't get all the type information in the resulting table, which is why you need to do some plain SQL mingling. But it's certainly doable! Here's how:
create().select(MY_TABLE.ID)
.from(MY_TABLE)
.whereExists(
selectOne()
.from(unnest(MY_TABLE.TYPES).as("types",
MY_TYPE.ID.getName(),
MY_TYPE.SOMETHING.getName()
))
.join(TYPE_TABLE)
.on(TYPE_TABLE.ID.eq(field(name("types", MY_TYPE.ID.getName()),
MY_TYPE.ID.getDataType())))
)
.fetch(MY_TABLE.ID);

Java PreparedStatement Cross-DB with casting

I have a PreparedStatement intended to be run both on ORACLE and on MYSQL.
But I cannot figure out how to handle the CAST(NULL AS ...)
On Oracle the following works (but not on Mysql):
SELECT TIMB_INS,
CAST(NULL AS TIMESTAMP) AS TIMB_CLO
FROM TOPS
On Mysql the following works (but not on Oracle):
SELECT TIMB_INS,
CAST(NULL AS DATETIME) AS TIMB_CLO
FROM TOPS
(Please note that the first column selected, "TIMB_INS", returns the correct data type for target database type in both cases, i.e. TIMESTAMP for Oracle and DATETIME for MySql.)
There is a way to put it so that it works for both?
I.E. Can i make it db-indipendent in some way?
Thanks
Marco
Based on the tags I can see you're calling this statement from some java code. There are several ways doing so:
Use the DAO pattern. I.e. for each SQL flavor provide a java file that contains the SQL-s.
Use an ORM like Hibernate or JPA. That will take care of this kind of differences.
As a quick hack, you can edit the SQL manually, like in the snippet below. But then you have to determine somehow if the underlying database is Oracle or MySQL
String SQL_PATTERN = "... CAST(NULL AS %s) AS TIMB_CLO ...";
String SQL = String.format(SQL_PATTERN, isOracle ? "TIMESTAMP" : "DATETIME");

Hibernate and Postgres : function st_buffer(bytea, numeric) is not unique

I'm working with Hibernate 5.1.0 in a Java application. I'm connecting both to a Postgres 9.5 with Postgis extensions and Oracle databases.
I need to find all the geometries in my database that intersect with a given geometry to which I apply a buffer, such as :
Query query = session
.createQuery("select b from Block b where intersects(b.geom, buffer(:geometry, " + bufferDistance + ")) = "
+ UtilsHelper.getTrueBooleanValue(em));
query.setParameter("geometry", geom);
List<Block> blocks = query.list();
That works in Oracle, but in Postgres I will get the error :
Caused by: org.postgresql.util.PSQLException: ERROR: function st_buffer(bytea, numeric) is not unique
Hint: Could not choose a best candidate function. You might need to add explicit type casts.
Position: 243
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270)
This makes sense, as it will not be able to choose between one of the following functions :
geometry ST_Buffer(geometry g1, float radius_of_buffer);
geography ST_Buffer(geography g1, float radius_of_buffer_in_meters);
The UtilsHelper.getTrueBooleanValue(em) will just get the right boolean value depending on the entity manager, that is, 0/1 for Oracle and true/false for Postgres.
One obvious solution would be to drop one of the functions. Other than that, is there any way I can fix this?
I won't claim to know much about Hibernate, but it seems that a simple fix is to explicitly cast the bytea with CAST(:geometry AS geometry), and modernize the rest query to add a "ST_" prefix, which is used with newer PostGIS versions.
More importantly, you should never write a query with the form:
SELECT b
FROM Block b
WHERE ST_Intersects(b.geom, ST_Buffer(CAST(:geometry AS geometry), :bufferDistance)) = TRUE;
Using a buffer to select a region is slower and imperfect than using a distance-based ST_DWithin function to find the geometries that are within a distance. ST_DWithin can also use a spatial index, if available. And a boolean operator does not need to have the = + UtilsHelper.getTrueBooleanValue(em) part (i.e. TRUE = TRUE is TRUE). Just remove it.
Try to write a function that looks more like:
SELECT b
FROM Block b
WHERE ST_Dwithin(b.geom, CAST(:geometry AS geometry), :distance);
(using two parameters :geometry and :distance)

Complicated LIKE Expression in derby (Java DB)

i've a table with ID, Name both are String type in ID i'v value like
1.3.6.1,
1.3.6.2,
1.3.6.1.2,
1.3.6.1.3,
1.3.6.1.4,
1.3.6.2.1.
1.3.7.2,
1.3.7.5,
1.3.8.1,
etc
I need to retrieve records like 1.3.6. .. but not like 1.3.6.ANY_NUMBER. ..,
Can u help me to write a Derby query for it
Thanks in advance
Hanks
You wrote the answer yourself
WHERE id LIKE '1.3.6%' AND id NOT LIKE '1.3.6.1%'
Maybe you better don't use LIKE but a simple equals:
SELECT * FROM db WHERE id='1.3.6';
Use this to select data from [column_name] in format up to 3 dots (like 1, 1.1, 1.1.1 but never 1.1.1.1)
SELECT SUBSTRING_INDEX([column_name],".",3) FROM [table_name];
or
Use this to select rows where [column_name] is not longer than 5 chars (1, 1.1, 1.1.1 but never 1.1.1.1)
SELECT [column_name] FROM [table_name] WHERE CHAR_LENGTH([column_name]) < 6

Categories