Does anyone know if it's possible to configure an Oracle session or connection so that every string that gets persisted is automatically uppercased?
For example, if I invoke a SQL like this: "INSERT INTO STUDENT (name) VALUES ('john doe')"
The information in my table would be persisted like this:
STUDENT
--------------------
ID | 1
NAME | JOHN DOE
I've checked this entry but couldn't find anything like this: http://docs.oracle.com/cd/B19306_01/server.102/b14225/ch3globenv.htm#sthref186
Thanks!
There is no session-level configuration parameter for that, no.
You could write a trigger on the STUDENT table that would automatically store the data in uppercase but you'd need to do that for every table.
CREATE TRIGGER trg_student
BEFORE INSERT ON student
FOR EACH ROW
BEGIN
:new.name := upper( :new.name );
END;
Depending on the problem you are trying to solve, you could potentially set your session's NLS settings to ignore case sensitivity so that the string 'John Doeis considered to be equal to the stringJOHN DOE`. The options, limitations, and downsides to this will vary with the specific version of Oracle.
Related
How to generate and assign a unique value (sequence) to a user every time a user logs in? If two users login in at the same time simultaneously, I should be able to avoid assigning same value to both.
And it is not a specific requirement. It can be any operation for which a sequence is required to be generated and assigned. I am trying to understand how the situation can be handled if the operation happens at the same time. I require a solution for Oracle 11g specifically.
You named it - use a sequence.
create sequence myseq;
Fetch value from it using
select myseq.nextval from dual;
Assingn it to that user. Though, I'm not sure I understand what that actually is; what would you assign it to, really? I hope you know.
Without understanding what exactly what you want to accomplish with the unique value, as you are not explaining it, you might do something like this:
Create a Sequence for creating an incremental sequential number
SQL> create sequence my_seq start with xxx increment by yyy cache zzz;
Where
xxx is the number where the sequence should start
yyy is the increment value of the sequence ( normally 1 )
As you plan to use it each time the user logs in, it might be a good idea to cache some values for faster access. zzz represents the number of values of the sequence you want to cache.
Assign the values to each user which logs in
A way to assign this value to a user each time logs in is through a logon trigger and related it to the properties of the session, using the advantages provided by the default context SYS_CONTEXT. Of course, for that you need a DBA user to install the trigger in an admin schema ( as sys or system )
An example to store those values in a custom audit table:
SQL> CREATE TRIGGER AFT_LOG_DBT
AFTER LOGON ON DATABASE
DECLARE
-- declare variables
v_db_user varchar2(100);
v_os_user varchar2(100);
v_seq number;
BEGIN
SELECT sys_context('userenv','session_id') , -- the session id
sys_context('userenv','osuser') , -- the os user
my_seq.nextval -- the sequence next val
INTO
v_db_user,
v_os_user,
v_seq
FROM DUAL;
-- insert those values into an audit table
insert into your_schema.log_audit ( logon_time , db_user, os_user, seq_val )
values ( sysdate , v_db_user, v_os_user, v_seq );
commit;
END;
As you were not explaining what you wanted to do with the unique sequence value, I tried to provide you with an example of a use case.
I have never gotten duplicate sequence numbers from a sequence generator unless it has wrapped the max value or is set to cycle.
I am very new to oracle's sql developer (since we've studied mysql) as well as in programming. I've searched in this website the answer to my question but I really can't understand the solutions provided.
What I want is to return the ID generated after inserting an object from java into the database. I'm using mybatis and oracle 10g database. I've already created the table and its columns.
Here's my code for the mapper
<insert id="addUser" parameterType="User" statementType="CALLABLE">
{ CALL addUserSP(
#{user.surname, javaType=String, jdbcType=VARCHAR, mode=IN},
#{user.firstName, javaType=String, jdbcType=VARCHAR, mode=IN},
#{userId, javaType=Integer, jdbcType=NUMBER, mode=OUT}
)}
</insert>
Here's my stored procedure (and I've already create a package named 'CREATEUSER')
PROCEDURE ADDUSERSP
( surname IN VARCHAR2,
firstName IN VARCHAR2,
userId OUT NUMBER
) AS
BEGIN
INSERT INTO users("surname", "first_name")
VALUES (surname, firstName);
RETURNING user_id INTO userId;
END ADDUSERSP;
According to what I've found here, it seems that I need to create a trigger(?) and sequence(?) to make the user_id auto increment whenever I add new data into the table. However, I have no idea how to do it.
Here are my questions:
Is my stored procedure right? Are the codes incomplete? I mean, I have not declared the package in the mapper and I've seen that it is needed (?), something like this { CALL [CreateUser].[addUserSP]( blah blah.... Should I write a sequence and trigger or there is an easy way to make the primary key user_id to be auto incremented? Kindly also check the syntax. I have a lot of problems in syntax.
Thank you so much!
To emulate MySQL AUTO_INCREMENT in Oracle, that pattern (as you found) does use a SEQUENCE object and a BEFORE INSERT trigger.
As a demonstration, something like this for the sequence object:
CREATE SEQUENCE myseq START WITH 1 INCREMENT BY 1 ;
And something like this for the before insert trigger:
CREATE TRIGGER users_bi
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
SELECT myseq.NEXTVAL INTO :NEW.id FROM DUAL;
END IF;
END
As far as the procedure, I'm not a big fan of extra PL/SQL blocks that wrap a SQL INSERT statement.
It looks like you have an extra semicolon, before RETURNING. That clause is part of the INSERT statement, not a separate statement.
One big gotcha to be aware of is that SQL statements within a PL/SQL block can reference both columns and PL/SQL variables. When variables have the same names as columns, you will likely encounter behavior you didn't expect.
Typically PL/SQL author use a naming convention for variables that reduces the likelihood of name collisions. We frequently see variables with names like v_surname. (Personally, I use a slightly different convention, but the variable names "look like" variable names, not column references. And I don't name columns following the pattern I use for variables.)
The double quotes around the identifiers are acceptable, but this does make the identifiers case sensitive. When identifiers aren't enclosed in double quotes, Oracle treats them as if they were UPPER CASE. Just make sure that your table was defined with lower case column names.
I am developing a Online Registration System using JSP and Oracle where I need to give every successful registrant a unique registration number sequentially. For this I want to adopt the NEXTVAL facility of Oracle, but I am in a dilemma for which policy I would adopt.
Policy 1: First I will store the NEXTVAL of a sequence in the following way.
select seq_form.nextval slno from dual;
Then I will store the slno into a variable say
int slno;
Now I will use the slno for in the insert query when the user finally submits the form, like
insert into members(registration_no, name,...) values(slno, name, ...);
Here the registration_no is primary key.
Policy 2: In my second policy, I will run the insert the query first
insert into members(registration_no, name,...) values(seq_form.nextval, name, ...);
fetch the last inserted ID like
select seq_form.currval slno from dual;
And then store the same in some variable say
int slno;
And use the same to show it to the registrant. Now I can't come to a conclusion which is better in terms of safety and efficiency. Here, I must make it clear that, in both the cases, my intension is to give the user a unique sequential number after successful submission of the form and by safety I meant to say that the user should get the ID respect to his/her own web session. Please help me.
I suggest you do it slightly differently:
Create a BEFORE INSERT trigger on your MEMBERS table. Set REGISTRATION_NO column to SEQ_FORM.NEXTVAL in the trigger:
CREATE OR REPLACE TRIGGER MEMBERS_BI
BEFORE INSERT ON MEMBERS
FOR EACH ROW
BEGIN
:NEW.REGISTRATION_NO := SEQ_FORM.NEXTVAL;
END MEMBERS_BI;
Do NOT put REGISTRATION_NO into the column list in your INSERT statement - it will be set by the trigger so there's no need to supply any value for it:
Use the RETURNING clause as part of the INSERT statement to get back the value put into REGISTRATION_NO by the trigger:
INSERT INTO MEMBERS (NAME, ...)
VALUES ('Fred', ...)
RETURNING REGISTRATION_NO INTO some_parameter
If you are using oracle 12, you can use identity column.
Then use RETURNING to get auto-generated value back.
Go with the policy 2. Because you cant always be sure that the insert query will be successful. If the insert fails, your oracle sequence has been rolled forward and you lose a sequence.
it is a better idea to insert and then later fetch it into a variable.
Trying to implement a friendship table ..
To explain wat i have done till now
my DDL
<!-- WORKING -- "relationship" - This table used to store the relationship between users -->
create table relationship(
relation_id number(8),
FromUserName varchar2(30),
ToUserName varchar2(30),
StatusId number,
SentTime timestamp,
constraint relationship_pk primary key(relation_id),
foreign key (FromUserName) references users(username),
foreign key (ToUserName) references users(username)
);
<!--WORKING add the unique key to 'relationship' table so that a user can send request at time to user only oncle -->
ALTER TABLE relationship
ADD CONSTRAINT relation_unique UNIQUE (FromUserName, ToUserName);
Here is an image to explain the problem
My problem
have a look at last two rows . .. the users kamlesh1 send request to jitu1 and again jitu1 sends request to kamlesh1 and when i kamlesh1 accepts the request the statusid changes to 1 similar case for kamlesh to jitu when jitu accepts the request.
I want to prevent this kind of duplication i.e
once a user has sent u a request u cannot sent a request to him just accept his request or reject it.
I just could'nt think of proper question title ...if u could help with that too.
Please help
You could create a unique function-based index for this:
CREATE UNIQUE INDEX relation_unique ON relationship ( LEAST(FromUserName, ToUserName), GREATEST(FromUserName, ToUserName) );
A couple of side notes: You don't need a NUMBER (38 digits of precision) to store a value that is either 0 or 1. NUMBER(1) should suffice. Also, you probably don't need the granularity of TIMESTAMP for SentTime - a DATE should do the trick, and might make arithmetic a bit easier (DATE arithmetic is expressed in days, TIMESTAMP arithmetic in intervals). Last, using CamelCase for column names in Oracle isn't a good idea since Oracle object names aren't case-sensitive unless you enclose them in double quotes. If you were to inspect the data dictionary you would see your columns like this: FROMUSERNAME, TOUSERNAME. Much better to use column names like FROM_USERNAME and TO_USERNAME (or USERNAME_FROM and USERNAME_TO).
You should order the persons. Say, add
alter table relationship
add constraint relation_order_chk
check (fromusername < tousername);
Then, when inserting, do something like
create or replace procedure AddRelationship(p_from varchar2, p_to varchar2 ...) is
begin
insert into relationship (fromusername, tousername, ...)
values(least(p_from, p_to), greatest(p_from, p_to), ...);
end;
I am working on a rather large SQL script to be used with Oracle, but I'm running into an issue. First, let me outline how the script operates.
Declare variables`CUSTOMERID NUMBER;``SERVERID NUMBER;`
Create a customer if it doesn't exist
`SELECT ID INTO CUSTOMERID FROM CUSTOMER WHERE NAME = 'The Customer I just Inserted';`
Create the server if it doesn't exist, using the `CUSTOMERID` value to relate the server to the customer.
`SELECT ID INTO SERVERID WHERE HOSTNAME = 'the.server.i.just.created';`
For each service belonging to this server, insert the service using the `SERVERID` value to relate the service to the server.
Go to 2
Now this process seems to work well for just one customer with 15 servers, each having 6 services. But as soon as the next customer is introduced, I receive prompts for variable substitution. The way I'm using the variables on my insert is pretty straightforward:
INSERT INTO SERVERS(CUSTOMER_ID, HOSTNAME)
SELECT CUSTOMERID, 'the.server.i.just.created' FROM DUAL
WHERE NOT EXISTS (
SELECT *
FROM SERVERS
WHERE HOSTNAME = 'the.server.i.just.created'
);
I have also attempted using the DECLARE ... BEGIN ... END; method, but I receive the same general results. Some examples I've seen suggest to use the :CUSTOMERID style variables, but those don't seem to work at all, where they are ending up with null values, which shouldn't be happening given the previous queries.
What I am needing help with is in understanding how to achieve this. I have very limited access to the production environment, so anything I do needs to be kept basic (e.g., no new functions, types, or procedures).
I actually stumbled across the answer after beating my head on the desk repeatedly.
Basically, what was happening was some of the customer names had ampersands in them, and the word immediately following the ampersand was attempting to bind as a variable. The solution was to SET DEFINE OFF; and all was well after that.
Thank you all for your time and consideration.
You can avoid some of the requerying using a RETURNING clause. For example:
SQL> var v number
SQL> print v
v
---------
SQL> insert into demo1 (col1) values (12345) returning col1 into :v;
1 row inserted
SQL> print v
v
---------
12345
This tends to be cleaner and more controllable in PL/SQL than in in a series of standalone statements called from a script.