Pull from Oracle sequence with Hibernate - oracle

I've a sequence defined in my Oracle database.
Can I pull from this sequence using Hibernate? I don't want to use the sequence for generating ids for my objects, so #GeneratedValue and #Id are not the things I am looking for.

Something like this:
<sql-query name="sequenceValue">
<return alias="mySeq" class="MySequences"/>
select my_schema.seq_myid.nextval as mySeq from dual
</sql-query>

Have you tried:
select my_schema.seq_myid.nextval from dual;
This will return a one record result set with the next value in your sequence. You can then use
select my_schema.seq_myid.currval from dual;
To get the current value of the sequence.

Related

Mybatis, insert in Oracle with sequence id

I have tried with this:
<insert id="insertPersonalizacionUsuario" useGeneratedKeys="true" keyProperty="param1.id" keyColumn="id">
INSERT INTO dsk_prop_personali (idpersonalizacion, idusuario, valor, centro)
VALUES (#{param1.idPersonalizacion}, #{param1.idUsuario}, #{param1.valor}, #{param2})
And with this:
<insert id="insertPersonalizacionUsuario" useGeneratedKeys="true" keyProperty="param1.id" keyColumn="id">
<selectKey keyProperty="id" resultType="int">
SELECT id.nextVal from dual
</selectKey>
INSERT INTO dsk_prop_personali (id, idpersonalizacion, idusuario, valor, centro)
VALUES (#{id}, #{param1.idPersonalizacion}, #{param1.idUsuario}, #{param1.valor}, #{param2})
But not working. Thanks
You must add the order attribute with BEFORE value to <selectKey> element. In your case you are using an Oracle database which until version 12c (review your case) it doesn't have auto-generated column types and works with a sequence is not related with your column by the rdbms.
If you take a look the documentation reference there is a section which explains your case:
MyBatis has another way to deal with key generation for databases that
don't support auto-generated column types, or perhaps don't yet
support the JDBC driver support for auto-generated keys.
Here's a simple (silly) example that would generate a random ID
(something you'd likely never do, but this demonstrates the
flexibility and how MyBatis really doesn't mind):
<insert id="insertAuthor">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
insert into Author
(id, username, password, email,bio, favourite_section)
values
(#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR})
In the example above, the selectKey statement would be run first, the
Author id property would be set, and then the insert statement would
be called. This gives you a similar behavior to an auto-generated key
in your database without complicating your Java code.
So, to be sure the selectKey statement will run first, you would need to use the Order attribute with BEFORE value, the attribute is explained very good after this example in the reference documentation:
order This can be set to BEFORE or AFTER. If set to BEFORE, then it
will select the key first, set the keyProperty and then execute the
insert statement. If set to AFTER, it runs the insert statement and
then the selectKey statement – which is common with databases like
Oracle that may have embedded sequence calls inside of insert
statements.
Therefore, you must match your keyProperty value with the insert param as you have done (keyProperty="id" will be the Param in insert statement:#{id}), and specify the resultType as int so it is a numeric sequence.
Otherwise, you must do your select using the sequence id name, in your case be sure your sequence is called id (because you are using id.NEXTVAL):
SELECT YOUR_SEQ.NEXTVAL FROM DUAL
<insert id="insertAuthor">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select MYSEQUENCE.nextval from dual
</selectKey>
insert into Author
(id, username, password, email,bio, favourite_section)
values
(#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR}

How to update string value by string comparison condition PL/SQL

I want update all values in my tables, but this can kill my database
UPDATE Table_1
SET Value = 'Some string with but changed'
where value = 'Some string without changes';
Can I do this by procedures, and it guarantee that it will not perform in infinty please i need some tips?
Edit
I read about cursors, but how can i use it
Your SQL seems fine and that is the preferred solution. A cursor will normally be far, far slower.
If you cannot create an index and the update above is really that slow, try the following. Considering I don't have the rest of the table definition to work with, I assume your primary key is a single field named ID:
First, create a temporary table with only the matching records:
CREATE TEMPORARY TABLE temp as
SELECT *
FROM Table_1
WHERE value = 'Some string without changes';
Then, update using this temporary table:
UPDATE Table_1 SET
Table_1.Value = 'Some string with but changed'
WHERE EXISTS (
SELECT *
FROM Temp
WHERE Temp.ID = Table_1.ID
);
Another approach if your DB is higher than 11g R1 version. Oracle has provided a beautiful package called DBMS_PARALLEL_EXECUTE which is used for large DMLS or any process which can be split into chunks and can be parallely done.

Oracle order by varchar2 with numeric values in it

I have an issue where a Oracle DB column(say 'REF_NO') is VARCHAR2 and carries values similar to the ones below
If I do an ORDER BY REF_NO I get this:
LET-2-1
LET-2-10
LET-2-11
LET-2-2
LET-2-3
Which makes sense because the values are being treated as characters. I have been asked to change this so that the returned results are ordered like this:
LET-2-1
LET-2-2
LET-2-3
LET-2-10
LET-2-11
I cannot guarantee the format of these values either so I cannot really see how I can use regex or sub-string as it's a completely free text entry for users to enter values. The example above just happens to be what the requested data looks like. Other data could be completely different.
I cannot see how this is possible, so was hoping for some suggestions.
Additional information
To add to the complexity, here are some more examples from other customers:
Customer 1: OB 12, WE-11, WAN-001
Customer 2: P4, D1, W9
Customer 3: NTT-33A, RLC-33L, ARR-129B
Here are the steps
create table test01 (c varchar2(30));
insert into test01 values ('LET-2-1');
insert into test01 values ('LET-2-10');
insert into test01 values ('LET-2-2');
Query
select * from test01
order by to_number(SUBSTR(C,INSTR(C,'-',1)+1,INSTR(C,'-',1,2)-INSTR(C,'-',1)-1)),
to_number(SUBSTR(C,INSTR(C,'-',-1)+1));
Assuming all the values are having structure of -- - in the above query I try to extract numbers and converted to number in order by clause.
select * from TABLE
ORDER BY LENGTH(REF_NO), REF_NO
first you need to order by length and then order by REF_NO

SQL Server 2008 search for date

I need to search rows entered on a specific date.
However the datatype of column I need to search on is datetime, and the datatype of argument is Date.
I can use the the query like
Select result
from table
where
convert(date, Mycolumn) = #selectedDate
but this would affect the SARGability of the query and will not use indexes created on mycolumn.
I was trying to use the following query:
Select result
from table
where
Mycolumn
BETWEEN #selectedDate AND Dateadd(s, -1, Dateadd(D, 1, #selectedDate))
However this does not work since the #selectedDate is Date type and a second can't be added or removed.
Can someone help me with a working query?
Thanks.
It is my understanding that using:
convert(date, Mycolumn) = #selectedDate
is SARGable. It will use the index on Mycolumn (if one exists). This can easily be confirmed by using the execution plan.
Select result
from table
where
Mycolumn >= #selectedDate
AND Mycolumn < Dateadd(D, 1, #selectedDate)
If you need to do these searches a lot, you could add a computed, persisted column that does the conversion to DATE, put an index on it and then search on that column
ALTER TABLE dbo.YourTable
ADD DateOnly AS CAST(MyColumn AS DATE) PERSISTED
Since it's persisted, it's (re-)calculated only when the MyColumn value changes, e.g. it's not a "hidden" call to a stored function. Since it's persisted, it can also be indexed and used just like any other regular column:
CREATE NONCLUSTERED INDEX IX01_YourTable_DateOnly ON dbo.YourTable(DateOnly)
and then do:
SELECT result FROM dbo.YourTable WHERE DateOnly = #SelectedDate
Since that additional info is stored in the table, you'll be using a bit more storage - so you're doing the classic "space vs. speed" trade-off; you need a bit more space, but you get more speed out of it.

Oracle merge constants into single table

In Oracle, given a simple data table:
create table data (
id VARCHAR2(255),
key VARCHAR2(255),
value VARCHAR2(511));
suppose I want to "insert or update" a value. I have something like:
merge into data using dual on
(id='someid' and key='testKey')
when matched then
update set value = 'someValue'
when not matched then
insert (id, key, value) values ('someid', 'testKey', 'someValue');
Is there a better way than this? This command seems to have the following drawbacks:
Every literal needs to be typed twice (or added twice via parameter setting)
The "using dual" syntax seems hacky
If this is the best way, is there any way around having to set each parameter twice in JDBC?
I don't consider using dual to be a hack. To get rid of binding/typing twice, I would do something like:
merge into data
using (
select
'someid' id,
'testKey' key,
'someValue' value
from
dual
) val on (
data.id=val.id
and data.key=val.key
)
when matched then
update set data.value = val.value
when not matched then
insert (id, key, value) values (val.id, val.key, val.value);
I would hide the MERGE inside a PL/SQL API and then call that via JDBC:
data_pkg.merge_data ('someid', 'testKey', 'someValue');
As an alternative to MERGE, the API could do:
begin
insert into data (...) values (...);
exception
when dup_val_on_index then
update data
set ...
where ...;
end;
I prefer to try the update before the insert to save having to check for an exception.
update data set ...=... where ...=...;
if sql%notfound then
insert into data (...) values (...);
end if;
Even now we have the merge statement, I still tend to do single-row updates this way - just seems more a more natural syntax. Of course, merge really comes into its own when dealing with larger data sets.

Resources