I don't know that is this a silly question or not but I need to solve this. I have search with goggle but no result to satisfy me. The question is > I am inserting some value into a table. I am using oracle as database and grails 2.1.1. when it is inserting value in the table the row id does not begin with 1 but I need to start that particular table to start with 1. Cause There will be only four row in that table and I need to insert them by the id like 1,2,3,4 so that i can get them in various part of application. But it is giving other id and after then I changed them to 1,2,3,4. Is there any way to do this in domain level in grails ?
You need to create an oracle sequence.
http://www.techonthenet.com/oracle/sequences.php
CREATE SEQUENCE sequence_name
MINVALUE value
MAXVALUE value
START WITH value
INCREMENT BY value
CACHE value;
CREATE SEQUENCE my_seq
MINVALUE 1
MAXVALUE 4
START WITH 1
INCREMENT BY 1
CACHE 1;
Then in the domain specify the sequence
class MyDomain {
...
static mapping = {
id generator:'sequence', params:[sequence:'my_seq']
}
}
EDITED:
If you are using liquibase migration then use add a new changeset and then add it to you changelog.groovy.
To create a sequence add a changeSet into your grails-app/migrations
sequence.groovy
changeSet(author: "me", id: "add-sequence") {
createSequence(sequenceName: "my_seq")
}
changelog.groovy
include file: 'sequence.groovy'
For more options on creating sequences using liquibase look here: http://www.liquibase.org/documentation/changes/create_sequence.html
instead of this create your own id field in table and use sequences to generate any id you like, for example : create sequence id_seq start with 1 increment by 1 and use it while inserting : insert int TABLE_NAME values (id_seq.nextval, ...);. I would recommend you not to depend on oracle's row_id, because it's controlled by db and is genereted for it's needs (see also oracle ref).
Related
I have a question for all of you. I'm quite new in SQL and searched for more than 2 hours and didn't find exactly what I need.
I'm having a table in SQL named Courses. Here is the constructor:
CREATE TABLE Courses
(sign VARCHAR2(6) NOT NULL,
title VARCHAR(50) NOT NULL,
credits INTEGER NOT NULL,
CONSTRAINT PrimaryKeyCourses PRIMARY KEY (sign)
);
I have to add a new column, which I did with :
ALTER TABLE Courses ADD frequency INTEGER;
I want to create a trigger which will increment every time a new courses is added.
I tried to do this :
CREATE TRIGGER fq
AFTER INSERT ON Courses
FOR EACH ROW
UPDATE frequency SET frequency = frequency + 1;
But it doesn't seems to work properly :( I don't know what to do.
No need to use an UPDATE statement, use a SELECT statement with max(value)+1. And to be able to change a :new. value, need to convert trigger to BEFORE type.
So, you can use the one as below
CREATE OR REPLACE TRIGGER fq
BEFORE INSERT ON Courses
FOR EACH ROW
DECLARE
BEGIN
select nvl(max(frequency),0)+1
into :new.frequency
from Courses;
END;
Of course you need a commit after a DML statement, I think it's better to include only one commit outside of this trigger after INSERT statement applied on Courses table, because of providing transaction integrity rule.
P.S. I know you're restricted to use a trigger, but Using a sequence for the value of column frequency is a better, practical alternative as #nikhil sugandh suggested. In this case a trigger is not needed. If you're using DB version 12c, you can add that sequence as default for the column frequency as frequency INTEGER GENERATED ALWAYS AS IDENTITY during the table creation.
use sequence :
CREATE SEQUENCE Courses_frequency
MINVALUE 1
MAXVALUE 999999999999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 20;
and do insert like:
INSERT INTO Courses
(sign,title,credits,frequency)
VALUES
(value1,value2,value3,Courses_frequency.NEXTVAL);
Using Oracle DB
Trying to create logic where when inserting a new row the logic checks if there is an existing numerical value. If there is a value then the logic would perform a max(value)+1. If there is no value then INSERT '1'.
I would suggest that you use a sequence instead of looking for the max value + 1.
A sequence would take care of the incrementing for you. http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_6015.htm
Example:
CREATE SEQUENCE MY_SEQ START WITH 1 INCREMENT BY 1;
Insert like
INSERT INTO MY_TABLE (ID, WIDGET) VALUES (NEXTVAL FOR MY_SEQ, 'asdf');
I have an existing Oracle database that sets the primary key for an insert via a trigger.
TRIGGER SET_schedtemplate_id_template
BEFORE INSERT
ON schedtemplate
FOR EACH ROW
BEGIN
SELECT schedtemplate_id_template_SEQ.NEXTVAL
INTO :NEW.id_template
FROM DUAL;
END;
We have other applications that depend on this approach for this database
I want to be able to map this database in GORM in my domain object
static mapping = {
autoTimestamp true
table 'schedtemplate'
version false
id column: 'id_template', generator: 'sequence', params: [sequence: 'SCHEDTEMPLATE_ID_TEMPLATE_SEQ']
}
The problem with this approach is that GORM increments the sequence to say 12 but then on insert the sequence gets incremented again to 13. This means other objects in the object graph violate foreign key constraints as they are using GORM's 12 instead of the trigger's 13.
It appears the hibernate setting hibernate.jdbc.use_get_generated_keys = true was developed for this purpose.
How do I configure GORM/Grails to use this setting?
The trigger assigned identity column in Hibernate was discussed here hibernate and DB triggers
Now there is a question, how to configure it in GORM.
Try to use the custom identity generator described above like this :
static mapping = {
...
id column: 'id_template', generator: 'jpl.hibernate.util.TriggerAssignedIdentityGenerator'
}
Am developing an application which helps people plan there schedule.
Lets say i have a table called 'Plan_Table' in which there are columns like
id,user_name, timestamp,place,event,plan_number.
For each day, a person can insert many records depending on his activities. I want 'plan_number' column to be populated by a trigger.
Suppose an user inserts five records at a time(in a batch). I want the plan_number field to be inserted as
plan_1
plan_1
plan_1
plan_1
plan_1
if he comes up with another plan.. and does few inserts, lets say 3 this time... I want the plan_number field to be inserted as
plan_2
plan_2
plan_2
How to achieve this using trigger and sequence?
Thanks in advance.
I think you can use the combination of the before statement level trigger for that table along with the global package variables and then use them in the Row Level trigger for that table.
Hope it gives you a heads up with the above logic
var_plan_number number := 0;
begin
if :new.plan_number is null then
select max(plan_number) into var_plan_number from plan_table where timestamp < CURRENT_TIMESTAMP - 5 --*some_treshold - ie 5 seconds*
and timestamp > CURRENT_TIMESTAMP and timestamp > trunc(sysdate) and user_name = :new.user_name;
--idea is to select max plan_number for current day and increment it by 1
--treshold should be set to time, your script is able to process batch records
var_plan_number := var_plan_number + 1;
:new.plan_number := var_plan_number;
end if;
that should do the trick...
Please consider this as a pseudo code, how your trigger should look like. There is no need for sequences.
The problem lies in the definition of "at a time (in a batch)". It will be difficult to tell the trigger when one batch ends and when a new one begins. It is possible with package variables, but the most competent place is your application.
I'd create a sequence to generate the ids, but pick up the ids in your application and feed them directly to the INSERT statement:
CREATE SEQUENCE myids;
CREATE TABLE plan_table(id int, user_name varchar2(30), mytimestamp, ...);
And in your code:
SELECT myids.nextval INTO myplanid FROM DUAL;
INSERT INTO plan_table(myplanid, myuser_name, SYSTIMESTAMP, place1 ...);
INSERT INTO plan_table(myplanid, myuser_name, SYSTIMESTAMP, place2 ...);
INSERT INTO plan_table(myplanid, myuser_name, SYSTIMESTAMP, place3 ...);
COMMIT;
Thanks for the answers you provided me. You really let me think in a purely db perspective.
As a web application developer, I thought, its a much better approach to use sequence/trigger to help me out with this problem. However, I found the solution from business logic of Application itself.
I am using Hibernate ORM for managing db tables. Hence i pulled out the max value of plan number using the following pieces of code.
Session session = getSessionFactory().openSession();
session.beginTransaction();
Criteria criteria = session.createCriteria(Mwwp_Plan.class).setProjection(Projections.max("plan_number"));
Integer maxPlanNumber = (Integer) criteria.uniqueResult();
session.getTransaction().commit();
System.out.println(maxPlanNumber);
if(maxPlanNumber==null)
{
System.out.println("maxPlanNumber is null");
maxPlanNumber = 0;
}
else
{
}
System.out.println("maxPlanNumber:"+maxPlanNumber);
return maxPlanNumber;
This is inside a function which my app uses to get the max(plan_number). If there is no plan_number in the table. It will give a default of 1.
Note: Mwwp_Plan is the name of table i used in my application.
Hence I achieved what i wanted.
Thanks for your help.
I have that query :
INSERT INTO GOST (ASSORTMENTID, ROZMIAR, GOST)
VALUES ( 54,'S','MjgwMzktODkgMTc0LTk2')
I want insert new row in table GOST, but I don't want to specify column with primary key - GOSTID. I want that database set next id value.
When I run this code I have that error:
validation error for column GOSTID, value "* null *"
I understand that I should set GOSTID column in INSERT query, yes ?
It is possible to run this without this parameter ?
I think a sample script worths more than 1000 words:
Go to a shell interface in the firebird server machine, cd to a folder where you have read/write permissions, start isql or isql-fb (depends on your system and firebird version) and run this script:
create database 'netmajor.fdb' user 'sysdba' password 'masterkey';
set autoddl off;
create table netmajor_example (
netmajor_id integer not null
, str_data varchar(200)
, int_data integer
, constraint pk_netmajor_example
primary key (netmajor_id)
);
create generator netmajor_gen;
set term ^;
create trigger netmajor_pkassign
for netmajor_example
active before insert position 1
AS
begin
if (new.netmajor_id is null) then
new.netmajor_id = gen_id(netmajor_gen, 1);
end
^
commit work^
set term ; ^
insert into netmajor_example (str_data, int_data) values ('one', 1);
insert into netmajor_example (str_data, int_data) values ('twenty', 20);
commit work;
select * from netmajor_example;
Take a look at the results, which in my machine are:
; NETMAJOR_ID STR_DATA INT_DATA
;============ ============================ ============
; 1 one 1
; 2 twenty 20
IF you have questions, don't hesitate to contact. Best regards.
Obviously, your primary key is a NOT NULL column, which means, it's always required. You cannot insert a row without giving a value for the primary key (unless it were an "auto-number" column which gets automatically set by the database system).
Use "before insert" trigger to set value for primary key. Firebird doesn't have "auto-increment" field type, so you need take care of it by yourself.
See http://www.firebirdfaq.org/faq29/ for tutorial how to do this. Some DB applications (eg Database Workbench) can create the trigger and generator automatically.