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}
Related
Is it possible to set a trigger to set the new row's value to be the result of a select statement? My current syntax is as follows and it's just not working:
CREATE TRIGGER "BRAND_NEW_TRIGGER"
BEFORE INSERT ON my_table
FOR EACH ROW
BEGIN
:NEW.column_one := (SELECT details_col FROM other_table WHERE property_id = :NEW.property_id);
END;
/
I've fudged the details of the code above to protect my company's security, I know the code above doesn't make too much sense but there is a valid reason I need to pull and organise the data this way.
You can do a select into
select ot.details_col
into :new.column_one
from other_table ot
where ot.property_id = :new.property_id;
Of course, I'd strongly question the data model if this makes sense. That strongly implies that you've got a data model in need of some normalization.
I have 3 tables, TBL_A, TBL_B and TBL_C.
TBL_A has an ID (lets call it ID_A) thats PK of A, and FK of B and C. ID_A have a trigger with an autoincrement before insert.
The problem:
I need to make an Insert All that looks kinda like this
INSERT ALL
INTO TBL_A(FIELD1, FIELD2) VALUES('VALUE1', 'VALUE2')--like i said before, the trigger autoinsert the id with the NEXTVAL in MY_SEQ sequence.
INTO TBL_B(ID_A, FIELD) VALUES (MY_SEQ.CURRVAL, 'VALUE')
INTO TBL_C(ID_A, FIELD) VALUE (MY_SEQ.CURRVAL, 'VALUE')
SELECT * FROM DUAL
But, for some reason it says that sequence MY_SEQ.CURRVAL is not yet defined in this session . What can i do to solve it? Cant find a way to do it.
I need to keep the trigger because that insert can be huge.
PLZ help me and srry about my english btw ^^
This have worked fine for me:
INSERT ALL INTO TBL_A(FIELD1, FIELD2) VALUES('VALUE1', 'VALUE2')
INTO TBL_B(ID_A, FIELD) VALUES (MY_SEQ.CURRVAL, 'VALUE')
INTO TBL_C(ID_A, FIELD) VALUES (MY_SEQ.CURRVAL, 'VALUE')
SELECT * FROM DUAL;
Indeed this really works when I call at least once MY_SEQ.NEXTVAL. In all other runs this is working fine without call NEXTVAL. I think the sequence must be properly initialized
INSERT ALL
INTO TBL_A(ID, FIELD1, FIELD2) VALUES(id, val1, val2)
INTO TBL_B(ID_A, FIELD) VALUES(id, val)
INTO TBL_C(ID_A, FIELD) VALUES(id, val)
SELECT
MY_SEQ.NEXTVAL as id, 'VALUE' as val, 'VALUE1' val1, 'VALUE2' val2
FROM DUAL
You can't use a sequence in the subquery of a multi-table insert and you shouldn't use it in the values clause like that because it can give unpredictable results.
You might consider populating the data into a global temporary table with the sequence and then doing your multitable insert using the global temporary table. Of course this would require modifying the trigger.
This is so simple it has probably already been asked, but I couldn't find it (if that's the case I'm sorry for asking).
I would like to insert an empty row on a table so I can pick up its ID (primary key, generated by an insert trigger) through an ExecuteScalar. Data is added to it at a later time in my code.
My question is this: is there a specific insert syntax to create an empty record? or must I go with the regular insert syntax such as "INSERT INTO table (list all the columns) values (null for every column)"?
Thanks for the answer.
UPDATE: In Oracle, ExecuteScalar on INSERT only returns 0. The final answer is a combination of what was posted below. First you need to declare a parameter, and pick up it up with RETURNING.
INSERT INTO TABLENAME (ID) VALUES (DEFAULT) RETURNING ID INTO :parameterName
Check this out link for more info.
You would not have to specify every single column, but you may not be able to create an "empty" record. Check for NOT NULL constraints on the table. If none (not including the Primary Key constraint), then you would only need to supply one column. Like this:
insert into my_table ( some_column )
values ( null );
Do you know about the RETURNING clause? You can return that PK back to your calling application when you do the INSERT.
insert into my_table ( some_column )
values ( 'blah' )
returning my_table_id into <your_variable>;
I would question the approach though. Why create an empty row? That would/could mean there are no constraints on that table, a bad thing if you want good, clean, data.
Basically, in order to insert a row where values for all columns are NULL except primary
key column's value you could execute a simple insert statement:
insert into your_table(PK_col_name)
values(1); -- 1 for instance or null
The before insert trigger, which is responsible for populating primary key column will
override the value in the values clause of the insert statement leaving you with an
empty record except PK value.
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.
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.