Oracle unique constraint or index - oracle

If I had the following table in an Oracle database:
CREATE TABLE TESTTABLE
(
"MYUNIQUEIDCOL" NUMBER(9,0) NOT NULL,
"VAN" NUMBER(9,0) NOT NULL,
"STATUS" VARCHAR2(30 BYTE) NOT NULL
)
I would like a van (of which there could be many) to only ever have one row with a status of "Active" - what kind of constraint would I need to ensure the illustration below does not happen (ie. rows 2 & 5 should not have been allowed)
MYUNIQUEIDCOL | VAN | STATUS
1 100 Active
2 100 Active
3 100 Cancelled
4 200 Active
5 200 Active
Thank you.

You can create unique index on mentioned column with the condition as following:
CREATE UNIQUE INDEX UQ_VAN_STATUS
ON TESTTABLE (VAN, CASE WHEN STATUS = 'ACTIVE' THEN STATUS END);
Example:
SQL> INSERT INTO TESTTABLE VALUES (1, 100, 'ACTIVE');
1 row created.
SQL> INSERT INTO TESTTABLE VALUES (1, 100, 'INACTIVE');
1 row created.
SQL> INSERT INTO TESTTABLE VALUES (1, 100, 'ACTIVE');
INSERT INTO TESTTABLE VALUES (1, 100, 'ACTIVE')
*
ERROR at line 1:
ORA-00001: unique constraint (TEJASH.UQ_VAN_STATUS) violated
SQL>
Cheers!!

Related

Creating List partition to an already Existing Table

I am trying to Create a list partition Based on the column "REFRESH_FLAG_Y" which has only Y and N as its Values, Below is the Alter Table used to Create the partition
ALTER TABLE "EDW"."LABOR_SCHEDULE_DAY_F" MODIFY
PARTITION BY LIST ("REFRESH_FLAG")
(PARTITION "REFRESH_FLAG_Y" VALUES ('Y') ,
PARTITION "REFRESH_FLAG_N" VALUES ('N')) ;
COMMIT;
But Whenever I execute the code I get an Error message
ERROR at line 1:
ORA-14400: inserted partition key does not map to any partition
You did tag the question with Oracle 11g tag; do you really use it?
This is a 12c example; it works if everything is OK:
SQL> create table labor_schedule_day_f as
2 select 1 id, 'Y' refresh_flag from dual union all
3 select 2 id, 'N' refresh_flag from dual;
Table created.
SQL> alter table labor_schedule_Day_f modify
2 partition by list (refresh_flag)
3 (partition refresh_flag_y values ('Y'),
4 partition refresh_flag_n values ('N')
5 );
Table altered.
Error you reported means this:
SQL> drop table labor_schedule_day_f;
Table dropped.
SQL> create table labor_schedule_day_f as
2 select 1 id, 'Y' refresh_flag from dual union all
3 select 2 id, 'N' refresh_flag from dual;
Table created.
Insert a row whose REFRESH_FLAG isn't Y nor N (so it violates the rule you specified):
SQL> insert into labor_schedule_day_f values (3, 'X');
1 row created.
Using the same ALTER TABLE statement as previously:
SQL> alter table labor_schedule_Day_f modify
2 partition by list (refresh_flag)
3 (partition refresh_flag_y values ('Y'),
4 partition refresh_flag_n values ('N')
5 );
alter table labor_schedule_Day_f modify
*
ERROR at line 1:
ORA-14400: inserted partition key does not map to any partition
SQL>
See? Error you got, which means that
which has only Y and N as its Values
isn't true.
P.S. You'd get the same result even if refresh_flag was NULL for some rows.

How to change column identify from sequence to GENERATED ALWAYS with data

as my title, I want to change my identity column by sequence to GENERATED ALWAYS.
For ex, I have a table like this:
CREATE SEQUENCE DPT.Deposit_SEQ
START WITH 1
INCREMENT BY 10
NOCACHE
NOCYCLE;
CREATE TABLE DPT.TEST(
Id NUMBER(10)DEFAULT DPT.Deposit_SEQ.nextval NOT NULL
,Code VARCHAR2(20),
CONSTRAINT PK_TEST PRIMARY KEY (ID)
);
Insert into DPT.TEST (ID, CODE) values (1,'ABC');
COMMIT;
Now, I want to change from sequence to GENERATED ALWAYS like this:
Id NUMBER(10) GENERATED ALWAYS AS IDENTITY START WITH 6
INCREMENT BY 10
NOCACHE
NOCYCLE;
I tried by create one more column and drop old column but failed. How can I do that?
Thanks!
"But failed" is not an Oracle error and is difficult to debug.
Anyway, it works for me:
Create table and a sequence, insert some rows:
SQL> CREATE SEQUENCE Deposit_SEQ START WITH 1 INCREMENT BY 10 NOCACHE NOCYCLE;
Sequence created.
SQL> CREATE TABLE TEST
2 (
3 Id NUMBER (10) DEFAULT Deposit_SEQ.NEXTVAL NOT NULL,
4 Code VARCHAR2 (20),
5 CONSTRAINT PK_TEST PRIMARY KEY (ID)
6 );
Table created.
SQL>
SQL> INSERT INTO TEST (ID, CODE)
2 VALUES (1, 'ABC');
1 row created.
SQL> INSERT INTO TEST (ID, CODE)
2 VALUES (3, 'DEF');
1 row created.
SQL> SELECT * FROM test;
ID CODE
---------- --------------------
1 ABC
3 DEF
Drop current primary key column (ID) and add a new, identity column:
SQL> ALTER TABLE test
2 DROP COLUMN id;
Table altered.
SQL> ALTER TABLE test
2 ADD id NUMBER GENERATED ALWAYS AS IDENTITY START WITH 6;
Table altered.
SQL> SELECT * FROM test;
CODE ID
-------------------- ----------
ABC 6
DEF 7
SQL> ALTER TABLE test ADD CONSTRAINT pk_test PRIMARY KEY (id);
Table altered.
SQL>
As you can see, no problem.

ROWNUM truncating output recordset

This query
select id from TABLE where id=1234 or id like '234%'
returns 11 rows, as expected. But when i try this
select rownum as rnum, id from TABLE where id=1234 or id like '234%'
or even this
select * from (
select id from TABLE where id=1234 or id like '234%'
) where rownum < 22
I have only 10 rows (id=1234 is missing in the output recordset). Why is that?
DDL for Table TABLE
CREATE TABLE "TABLE"
( "ID" NUMBER(28,0),
"SPOT_LCK" NUMBER(28,0),
"STATUS" NUMBER(*,0),
"CARRIER_YN" CHAR(1 BYTE),
...
"DRIVER" NUMBER(38,0) DEFAULT 0
);
Constraints for Table TABLE
ALTER TABLE "SCHEMA"."TABLE" ADD CONSTRAINT "PK_TBL" PRIMARY KEY ("ID")
Oracle 12c Release 12.1.0.2.0 - 64bit
Double-check your results, you must have made a mistake. Minimal example:
create table testrn ( id number primary key, c1 number );
insert into testrn values (1234, 1);
insert into testrn values (2341, 2);
insert into testrn values (2342, 3);
insert into testrn values (2343, 4);
insert into testrn values (2344, 5);
insert into testrn values (2345, 6);
insert into testrn values (2346, 7);
insert into testrn values (2347, 8);
insert into testrn values (2348, 9);
insert into testrn values (2349, 10);
insert into testrn values (23410, 11);
commit;
select id, rownum from testrn where id=1234 or id like '234%';
This returns 11 rows as expected. And I assume that you meant 1234 is missing as 123 is not used in the SQL?
There is no solution found as of now: oracle says latest patch required, app vendor says they don't support it. so we're leaving as it is.

Merge statement

I am looking into merge statements, but I can not figure out the syntax.
Let's say I have these tables
CREATE TABLE employee (
employee_id NUMBER(5),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
dept_no NUMBER(2),
salary NUMBER(10));
INSERT INTO employee VALUES (1, 'Dan', 'Morgan', 10, 100000);
INSERT INTO employee VALUES (2, 'Helen', 'Lofstrom', 20, 100000);
INSERT INTO employee VALUES (3, 'Akiko', 'Toyota', 20, 50000);
INSERT INTO employee VALUES (4, 'Jackie', 'Stough', 20, 40000);
INSERT INTO employee VALUES (5, 'Richard', 'Foote', 20, 70000);
INSERT INTO employee VALUES (6, 'Joe', 'Johnson', 20, 30000);
INSERT INTO employee VALUES (7, 'Clark', 'Urling', 20, 90000);
CREATE TABLE bonuses (
employee_id NUMBER, bonus NUMBER DEFAULT 100);
INSERT INTO bonuses (employee_id) VALUES (1);
INSERT INTO bonuses (employee_id) VALUES (2);
INSERT INTO bonuses (employee_id) VALUES (4);
INSERT INTO bonuses (employee_id) VALUES (6);
INSERT INTO bonuses (employee_id) VALUES (7);
COMMIT;
and just for the sake of an example I want to update all entries of bonuses with 200 * employee_id. Here is my statement. What's wrong with it?
merge into bonuses b
using
(select employee_id id, 200 bonus from employees) test
on (test.id = b.employee_id)
when matched then update set
b.bonus = test.bonus * test.employee_id
Thanks!
P.S. See also my sqlfiddle here: http://sqlfiddle.com/#!4/ff425/14
merge into bonuses b
using
(select employee_id id, 200 bonus from employee) test
on (test.id = b.employee_id)
when matched then update set
b.bonus = test.bonus * test.id;
Two minor mistakes:
1) employee instead of employees
2) test.id instead of test.employee_id

(Yet another) "Missing Right Parenthesis"

I am using 10g, and am trying to do some simple calculation and then save the result in a column. The actual tables have many more columns, but here are the what I am using in my query:
CREATE TABLE "VACCINE_LOT"
(
"VACCINE_LOT_ID" NUMBER(10,0) NOT NULL ENABLE,
"DOSE" NUMBER(6,3),
"QUANTITY_ON_HAND" NUMBER(12,2) NOT NULL ENABLE
)
CREATE TABLE "IMMUNIZATION"
(
"VACCINE_LOT_ID" NUMBER(10,0),
"DOSE_MAGNITUDE" NUMBER(4,2)
)
CREATE TABLE "VACCINE_LOT_TRANSACTION"
(
"VACCINE_LOT_ID" NUMBER(10,0) NOT NULL ENABLE,
"QUANTITY" NUMBER(12,2) NOT NULL ENABLE
)
INSERT INTO vaccine_lot VALUES (100, 0.2, 120);
INSERT INTO immunization VALUES (100, 0.2);
INSERT INTO immunization VALUES (100, 0.3);
INSERT INTO vaccine_lot_transaction VALUES (100, 150);
Immunization shots are taken from a vaccine lot. 'Dose_magnitude' is how much a particular immunization shot uses from a lot. The 'Dose' column in vaccine_lot tells how much to use for a standard immunization shot. So a standard shot may be 0.1cc. But one immunization shot may actually use 0.2cc or even 0.05cc. The 'Quantity' column in vaccine_lot_transaction records originally how many standard immunization shots a vaccine lot contains.
What I am trying to do here is to calculate the correct 'Quantity_on_hand' for vaccine lots (that is, how many standard immunization shots are still left for vaccine lots).
Here is an example using the data we just inserted. We have a vaccine lot (lot ID is '100'), and it starts off with 150 standard shots (that is, it contains 150 0.2cc shots). There are two immunization shots from this lot already, one 0.2cc, the other 0.3cc). And the current quantity of 120 is obviously wrong, and we need to recalculate and update it.
Here is my query:
UPDATE vaccine_lot V SET quantity_on_hand =
(
(
(SELECT T.quantity * V.dose FROM vaccine_lot_transaction T WHERE V.vaccine_lot_id = T.vaccine_lot_id) -
(SELECT SUM(I.dose_magnitude) FROM immunization I WHERE I.vaccine_lot_id = V.vaccine_lot_id)
) / dose
);
And sure enough, Oracle starts to complain about "missing right parenthesis". Looks like it thinks there is something syntactically wrong.
Can anyone help take a look at this query and see what's wrong with it? Thanks!
This is what I get when I run it through SQL*PLUS:
SQL> run
1 UPDATE vaccine_lot V SET quantity_on_hand =
2 (
3 (
4 (SELECT T.quantity * V.dose FROM vaccine_lot_transaction T
5 WHERE V.vaccine_lot_id = T.vaccine_lot_id) -
6 (SELECT SUM(I.dose_magnitude) FROM immunization I
7 WHERE I.vaccine_lot_id = V.vaccine_lot_id)
8 ) / dose
9* );
WHERE V.vaccine_lot_id = T.vaccine_lot_id) -
*
ERROR at line 5:
ORA-00907: missing right parenthesis
By the way, I am using version 10.2.0.1.0 of SQL*Plus. I get the same result when using SQL Developer (version 3.0.04).
Can anyone help take a look at this issue? Thanks!
I cut and pasted your code and it seems to work for me (I believe the end result of 147.5 is correct). Are you sure that you didn't accidentally simplify the problem too far?
SQL> CREATE TABLE "VACCINE_LOT"
2 (
3 "VACCINE_LOT_ID" NUMBER(10,0) NOT NULL ENABLE,
4 "DOSE" NUMBER(6,3),
5 "QUANTITY_ON_HAND" NUMBER(12,2) NOT NULL ENABLE
6 );
Table created.
SQL> CREATE TABLE "IMMUNIZATION"
2 (
3 "VACCINE_LOT_ID" NUMBER(10,0),
4 "DOSE_MAGNITUDE" NUMBER(4,2)
5 );
Table created.
SQL> CREATE TABLE "VACCINE_LOT_TRANSACTION"
2 (
3 "VACCINE_LOT_ID" NUMBER(10,0) NOT NULL ENABLE,
4 "QUANTITY" NUMBER(12,2) NOT NULL ENABLE
5 );
Table created.
SQL> INSERT INTO vaccine_lot VALUES (100, 0.2, 120);
1 row created.
SQL> INSERT INTO immunization VALUES (100, 0.2);
1 row created.
SQL> INSERT INTO immunization VALUES (100, 0.3);
1 row created.
SQL> INSERT INTO vaccine_lot_transaction VALUES (100, 150);
1 row created.
SQL> commit;
Commit complete.
SQL> UPDATE vaccine_lot V SET quantity_on_hand =
2 (
3 (
4 (SELECT T.quantity * V.dose FROM vaccine_lot_transaction T WHERE V.vacci
ne_lot_id = T.vaccine_lot_id) -
5 (SELECT SUM(I.dose_magnitude) FROM immunization I WHERE I.vaccine_lot_id
= V.vaccine_lot_id)
6 ) / dose
7 );
1 row updated.
SQL> select * from vaccine_lot;
VACCINE_LOT_ID DOSE QUANTITY_ON_HAND
-------------- ---------- ----------------
100 .2 147.5

Resources