Using existing Database Sequence and creating custom generator - oracle

I have created a sequence in my Database as follows:
CREATE SEQUENCE "SCOTT"."ATA_SEQ_USERID"
MINVALUE 1 MAXVALUE 9999999999999999999999999999
INCREMENT BY 1 START WITH 1000 CACHE 20 NOORDER NOCYCLE ;
Now, I want to append the first two letters of the name of the user to the number created by this sequence and generate a user id everytime a new user registers, using Hibernate. How can I do that?

You just need to use:
SUBSTR function
concatenation operator || .
For example,
SQL> CREATE SEQUENCE s;
Sequence created.
SQL>
SQL> SELECT substr(ename, 1, 2)||s.nextval custom_seq FROM emp;
CUSTOM_SEQ
------------------------------------------
SM1
AL2
WA3
JO4
MA5
BL6
CL7
SC8
KI9
TU10
AD11
JA12
FO13
MI14
14 rows selected.
SQL>

Finally found the way to do it.
String sql = "select MY_SEQ_ID.nextval from dual";
SQLQuery query = session.getCurrentSession().createSQLQuery(sql);
List idList=query.list();
BigDecimal number=(BigDecimal) idList.get(0);
System.out.println(number);
where MY_SEQ_ID is my sequence id.

Related

Using EXECUTE IMMEDIATE based on entries of table

I (using Oracle 12c, PL/SQL) need to update an existing table TABLE1 based on information stored in a table MAP. In a simplified version, MAP looks like this:
COLUMN_NAME
MODIFY
COLUMN1
N
COLUMN2
Y
COLUMN3
N
...
...
COLUMNn
Y
COLUMN1 to COLUMNn are column names in TABLE1 (but there are more columns, not just these). Now I need to update a column in TABLE1 if MODIFY in table MAP contains a 'Y' for that columns' name. There are other row conditions, so what I would need would be UPDATE statements of the form
UPDATE TABLE1
SET COLUMNi = value_i
WHERE OTHER_COLUMN = 'xyz_i';
where COLUMNi runs through all the columns of TABLE1 which are marked with MODIFY = 'Y' in MAP. value_i and xyz_i also depend on information stored in MAP (not displayed in the example).
The table MAP is not static but changes, so I do not know in advance which columns to update. What I did so far is to generate the UPDATE-statements I need in a query from MAP, i.e.
SELECT <Text of UPDATE-STATEMENT using row information from MAP> AS SQL_STMT
FROM MAP
WHERE MODIFY = 'Y';
Now I would like to execute these statements (possibly hundreds of rows). Of course I could just copy the contents of the query into code and execute, but is there a way to do this automatically, e.g. using EXECUTE IMMEDIATE? It could be something like
BEGIN
EXECUTE IMMEDIATE SQL_STMT USING 'xyz_i';
END;
only that SQL_STMT should run through all the rows of the previous query (and 'xyz_i' varies with the row as well). Any hints how to achieve this or how one should approach the task in general?
EDIT: As response to the comments, a bit more background how this problem emerges. I receive an empty n x m Matrix (empty except row and column names, think of them as first row and first column) quarterly and need to populate the empty fields from another process.
The structure of the initial matrix changes, i.e. there may be new/deleted columns/rows and existing columns/rows may change their position in the matrix. What I need to do is to take the old version of the matrix, where I already have filled the empty spaces, and translate this into the new version. Then, the populating process merely looks if entries have changed and if so, alters them.
The situation from the question arises after I have translated the old version into the new one, before doing the delta. The new matrix, populated with the old information, is TABLE1. The delta process, over which I have no control, gives me column names and information to be entered into the cells of the matrix (this is table MAP). So I need to find the column in the matrix labeled by the delta process and then to change values in rows (which ones is specified via other information provided by the delta process)
Dynamic SQL it is; here's an example, see if it helps.
This is a table whose contents should be modified:
SQL> select * from test order by id;
ID NAME SALARY
---------- ---------- ----------
1 Little 100
2 200
3 Foot 0
4 0
This is the map table:
SQL> select * from map;
COLUMN CB_MODIFY VALUE WHERE_CLAUSE
------ ---------- ----- -------------
NAME Y Scott where id <= 3
SALARY N 1000 where 1 = 1
Procedure loops through all columns that are set to be modified, composes the dynamic update statement and executes it:
SQL> declare
2 l_str varchar2(1000);
3 begin
4 for cur_r in (select m.column_name, m.value, m.where_clause
5 from map m
6 where m.cb_modify = 'Y'
7 )
8 loop
9 l_str := 'update test set ' ||
10 cur_r.column_name || ' = ' || chr(39) || cur_r.value || chr(39) || ' ' ||
11 cur_r.where_clause;
12 execute immediate l_str;
13 end loop;
14 end;
15 /
PL/SQL procedure successfully completed.
Result:
SQL> select * from test order by id;
ID NAME SALARY
---------- ---------- ----------
1 Scott 100
2 Scott 200
3 Scott 0
4 0
SQL>

Trigger to monitor is value acceptable or not

I have Oracle 11g and a table called CODES and there is column ID and CODESA as follow:
ID CODESA
1 9999
1 8889
2 77777
2 99999
3 1234
3 4321
4 565656
etc.
Then I need to update another table CODES2 and column CODESB based on ID in CODES table
I need a trigger to monitor this.
Let´s say I monitoring ID = 2 with this trigger and all different CODESA´s under that ID,
you can see that only these are possible to update in CODESB
2 77777
2 99999
How to make a trigger to launch if user is trying to enter some code in CODESB
which is for example from ID = 3 ?
Appreciate your help. Thanks,
Some_user
#APC is correct. We can use foreign key but lets say OP dont want those columns to be primary or unique, in that case trigger is the solution.
Create or replace trigger codes2_trg
Before insert or update On codes2
For each row
Declare
Cnt number;
Begin
Select count(1) into cnt
From codes where (id, codesa) = (:new.id, :new.codesb);
If cnt = 0 then
Raise_application_error('-20001', 'these balues are not allowed.');
End if;
End;
/
Cheers!!

Can a sequence guarantee the given order?

Using this Oracle sequence definition:
CREATE SEQUENCE MY_SPECIAL_COUNTER
START WITH 100
INCREMENT BY -1
MAXVALUE 100
MINVALUE 0
NOCYCLE
NOCACHE
ORDER
;
Is it guaranteed, that this sequence will ALWAYS return
each number once from 100 to 0
in the given order from 100 to 0 and
no single number will be obmitted and
independent of multiple concurrent session in the very moment of the request
the correct number?
Yes, the sequence will return each number once, starting with 100, progressively down to 0.
Yes, it will return them in order from 100 down to 0.
Correct, it will not skip any numbers.
Multiple sessions? That depends.
Consider the following:
create table junk ( id number );
CREATE SEQUENCE MY_SPECIAL_COUNTER
START WITH 100
INCREMENT BY -1
MAXVALUE 100
MINVALUE 0
NOCYCLE
NOCACHE
ORDER
;
-- in session 1 do the following:
insert into junk
select my_special_counter.nextval from dual;
insert into junk
select my_special_counter.nextval from dual;
SQL> select * from junk;
ID
----------
100
99
SQL>
-- in session 2 do the following:
insert into junk
select my_special_counter.nextval from dual;
SQL> select * from junk;
ID
----------
98
SQL> commit;
-- in session 1 do the following:
rollback;
-- in session 3 do the following:
SQL> select * from junk;
ID
----------
98
SQL>
As you can see once you introduce multiple sessions, all kinds of fun things can happen. Numbers can be "lost" or "skipped" .. note that it is NOT the sequence doing it, but rather the session or whoever pulled the sequence value then subsequently drops it (ie job abends, and rollsback, logic error, etc.)
Also, if session 1 pulls sequence first, but session 2 commits first, others will "think" session 2 inserted a number "out of order" .. so to understand what you're after, we really need to understand your requirements in detail to advise further.
However, that should help you understand sequences properly. :)
Good luck!

Update or Insert on a Table based on a column value

I have two tables BASE and DAILY as shown below:
BASE
Cust ID IP address
1 10.5.5.5
2 10.5.5.50
3 10.5.5.6
DAILY
Cust ID IP address
1 10.5.5.5
2 10.5.5.70
4 10.5.5.67
The table DAILY is periodically refreshed every 24 hours. Now for every Cust Id in BASE I have to check if the IP address is modified in DAILY. If yes then update the row in BASE.
All the new entries in DAILY have to be inserted into BASE.
I have tried this using a Cursor comparing and then updating and then another cursor for insertion.
But it is taking lot of time.
What is the best possible way to do this?
You could also use MERGE depending on your database system.
SQL Server syntax would be
MERGE INTO BASE B
USING DAILY D
ON D.CustId = B.CustId
WHEN NOT MATCHED THEN
INSERT (CustId, Ip) VALUES (D.CustId, D.Ip)
WHEN MATCHED AND D.Ip <> B.Ip THEN
UPDATE SET B.Ip = D.Ip;
Oracle PL/SQL syntax seems to be much the same, take a look here
If you just want to update all your BASE table, use an UPDATE to update all the rows in your BASE table.
UPDATE `BASE`
SET `IP address` = (SELECT `IP address`
FROM DAILY
WHERE DAILY.`Cust ID` = `BASE`.`Cust ID`);
Then, use this INSERT INTO query to insert new values that not exists in your table BASE.
INSERT INTO `BASE`
SELECT `Cust ID`, `IP address`
FROM DAILY
WHERE DAILY.`Cust ID` NOT IN (SELECT `Cust ID` FROM BASE);
SQL>
declare
begin
for i in (select * from daily where ip_add not in (select ip_add from base))
loop
update base set ip_add=i.ip_add where custid=i.custid;
end loop;
end;
PL/SQL procedure successfully completed.
SQL> select * from base;
CUSTID IP_ADD
---------- ----------
1 10..5.5.5
2 10..5.5.20 -- updated value from base where ip_add is different
3 10..5.5.6
SQL> select * from base ;
CUSTID IP_ADD
---------- ----------
1 10..5.5.5
2 10..5.5.20
4 10..5.5.62
SQL>

How to create a user entered query search

I am trying to create a report that produces rentals for tools, as its required to be interactive, i'd like the user to be able to enter the partial name of a tool or full name to bring up all the rentals for that tool.
TTITLE CENTER ==================== SKIP 1-
CENTER 'U T O O L' skip 1-
CENTER ==================== SKIP 1 -
LEFT 'Rental Report ' SKIP 1 -
LEFT ============ SKIP 2-
RIGHT 'Page:' -
FORMAT 999 SQL.PNO SKIP 2
set pagesize 50
column MEMBERNAME HEADING 'Member Name' format a20
column TOTAL HEADING 'Total Cost' format L9,999.99
compute sum label 'Total Cost: ' of TOTAL on MEMBERNAME
Break on Rental_ID on Member_ID on MEMBERNAME on Member_ID on Tel SKIP 1
select Member.Member_ID, SUBSTR(Member.FName,0,10) || SUBSTR(' ',0,10) ||
SUBSTR(Member.SName,0,15) as MEMBERNAME, Member.Tel,
Rental.Rental_ID,
Tool.Name,
Rental.DateOut,
Rental.DateIn,
Rental_Line.Qty,
Rental_Line.Price,
Rental_Line.Qty*Rental_Line.Price as TOTAL
from Rental_Line
INNER JOIN Rental
on Rental.Rental_ID = Rental_Line.Rental_ID
INNER JOIN Member
on Rental.Member_ID = Member.Member_ID
INNER JOIN Tool_Instance
on Rental_Line.Tool_Instance_ID = Tool_Instance.Tool_Instance_ID
INNER JOIN Tool
on Tool_Instance.Tool_ID = Tool.Tool_ID
where Tool.Name = '%&_%';
You could create a stored procedure that takes in a parameter, something like:
CREATE PROCEDURE rentalReport(toolName IN varchar)
AS
--your query here
where Tool.Name = toolName
not sure about the exact syntax, haven't used Oracle db..
More info:
http://www.ics.com/files/docs/dx/tut6.html
You should use ACCEPT command - it enables user to interact with your script. Like this:
09:26:55 SYSTEM#dwal> create table t (key number primary key, value varchar2(10));
Table created.
09:27:15 SYSTEM#dwal> insert into t values (1, 'abcdef');
1 row created.
09:27:20 SYSTEM#dwal> insert into t values (2, 'ghijkl');
1 row created.
09:27:32 SYSTEM#dwal> commit;
Commit complete.
09:28:48 SYSTEM#dwal> accept search_str char prompt "enter parameter > ";
enter parameter > def
09:30:01 SYSTEM#dwal> select * from t where value like '%&search_str.%';
KEY VALUE
---------- ----------
1 abcdef

Resources