Creating Table with CC Exp Date - Oracle PL SQL - oracle

I'm trying to create a table with date constraint that will make the date value of MM/YY for credit card expiration date. When I try to create the below table I receive the error:
CONSTRAINT exp_check CHECK TO_CHAR(exp_date,'MM/YY'),
*
ERROR at line 19:
ORA-00906: missing left parenthesis
Create table Orders
(o_id int NOT NULL,
c_id int NOT NULL,
p_id int NOT NULL,
s_id int NOT NULL,
order_date date DEFAULT sysdate,
o_qty number NOT NULL,
order_total number NOT NULL,
card_type varchar2(50) NOT NULL,
cc_number varchar2(50) NOT NULL,
exp_date date NOT NULL,
shipping_date date,
shipping_status varchar2(50) DEFAULT 'Not Shipped Yet',
UNIQUE (o_ID, c_ID, p_ID),
CONSTRAINT order_ID PRIMARY KEY (O_ID),
CONSTRAINT fk_cust_id FOREIGN KEY (C_ID) REFERENCES customers(C_ID),
CONSTRAINT fk_ship_id FOREIGN KEY (S_ID) REFERENCES shipping(S_ID),
CONSTRAINT qty_check CHECK (o_qty >= 0),
CONSTRAINT exp_check CHECK TO_CHAR(exp_date,'MM/YY'),
CONSTRAINT s_check CHECK (shipping_status IN
('Not shipped yet', 'Shipped', 'Delivered'))
);
Once I'm able to create the table I will create a executed stored procedure that will execute the below:
SET SERVEROUTPUT ON;
DECLARE
i_result varchar2(100);
BEGIN
place_order(2200,1,'Regular','VISA','1111-1111-2222-3333',11/19,1040,i_result);
END;

A date always has a day. month, year, hour, minute, and second. You could store a date that is midnight on the first of the month and validate that the exp_date = trunc(exp_date, 'MM'). When you display the value to the user, you'd then use the to_char expression to display it in the format that you want.
Alternately, you could store a string in the format MM/YY and your check constraint could put various validations on that string (i.e. the first two characters are a number between 1 and 12, the fourth and fifth characters are a number between 15 and 25, etc.).

As others have said, a DATE value in Oracle always has the fields YEAR, MONTH, DAY, HOURS, MINUTES, and SECONDS. I think what you want to do here is to store the last day/hour/minute/second of the expiration date in your EXP_DATE column, e.g. if expiration shown on the card is '07/19' you'd want to store 31-JUL-2019 23:59:59, which is the last possible second that the card is valid, in the EXP_DATE field. Then when you want to display the expiration date in its usual MM/YY format you just have to format it with TO_CHAR, e.g. TO_CHAR(EXP_DATE, 'MM/YY').
Best of luck.

Related

Create ExpiryDate during table definition in Oracle

I'm trying to create a table named MEMBER. The datatype for REGISTERDATE is DATE and the default value is SYSDATE. There is another column named EXPIRYDATE, datatype is DATE and the default value is 1 year after SYSDATE. So how am I going to create for the column of EXPIRYDATE when creating the table definition?
I tried REGISTERDATE DATE DEFAULT SYSDATE,
EXPIRYDATE DATE + 365,
It showed error..
You're so close, you're just missing the default keyword and sysdate after expirydate date
-
create table MEMBER (
REGISTERDATE date default sysdate,
expirydate date default sysdate+365
)
test:
insert into MEMBER(REGISTERDATE) values (sysdate)
output:
Not all years have 365 days; on average, only 3 out of 4. But you can literally define an expression that expresses "1 year after":
create table member (
id number(*,0) not null primary key,
registerdate date default sysdate,
expirydate date default sysdate + interval '1' year
);
Remember that Oracle won't use the default value if you provide your own, even if it's null. You need to complete omit the field from the INSERT INTO statement.
Demo

Insert into not working in oracle when a single column has more characters

I have created a table as:
CREATE TABLE SHOP.EMPLOYEES
(
EMPLOYEEID NUMBER(11) NOT NULL,
LASTNAME VARCHAR2(255 BYTE) DEFAULT NULL,
FIRSTNAME VARCHAR2(255 BYTE) DEFAULT NULL,
BIRTHDATE DATE DEFAULT NULL,
PHOTO VARCHAR2(255 BYTE) DEFAULT NULL,
NOTES VARCHAR2(100 BYTE) DEFAULT NULL
)
I have column notes which has more than 100 characters.So,I tried is:
INSERT INTO shop.employees (EmployeeID, LastName, FirstName, BirthDate, Photo, Notes)
VALUES (1, 'Davolio', 'Nancy', '1968-12-08', 'EmpID1.pic', 'Education includes a BA in psychology from Colorado State University. She also completed (The Art of the Cold Call). Nancy is a member of Toastmasters International.')
But I am getting an error:
Error at line 1
ORA-01861: literal does not match format string
What could be the best datatype for those long text in Oracle?
1968-12-08 is string and you need to insert date in your table.
Conversion of string to date is needed in whenever dates are used.
There are two ways to convert your string to date.
DATE '1968-12-08'
TO_DATE('1968-12-08', 'YYYY-MM-DD')
Cheers!!
BIRTHDATE is a DATE, not a varachar, so you need to convert it:
to_date('1968-12-08', 'yyyy-mm-dd')
Obviously, you can't expect to put something as long as 300 characters into something that accepts 100 characters, can you?
But, that's not your problem. Date is. The 4th column is birthdate, its datatype is date, but you are inserting a string into it, because '1968-12-08' is a string. You should have used a date literal instead, i.e. date '1968-12-08'.
Oh, yes - back to your original question (although a wrong one in this context): best datatype for a long text. You can create a column whose datatype is VARCHAR2(4000) and it'll happily accept that "long" string you used. Or, you can even choose a CLOB which accepts up to 4 giga of characters; more than enough for you, I presume.
Finally, your query:
SQL> CREATE TABLE EMPLOYEES
2 (
3 EMPLOYEEID NUMBER(11) NOT NULL,
4 LASTNAME VARCHAR2(255 BYTE) DEFAULT NULL,
5 FIRSTNAME VARCHAR2(255 BYTE) DEFAULT NULL,
6 BIRTHDATE DATE DEFAULT NULL,
7 PHOTO VARCHAR2(255 BYTE) DEFAULT NULL,
8 NOTES VARCHAR2(100 BYTE) DEFAULT null
9 );
Table created.
Note date literal in line #4 as well as substr function in line #5 (which restricted string length to 100).
SQL> INSERT INTO employees
2 (EmployeeID, LastName, FirstName, BirthDate, Photo, Notes)
3 VALUES
4 (1, 'Davolio', 'Nancy', date '1968-12-08', 'EmpID1.pic',
5 substr('Education includes a BA in psychology from Colorado State University. She also completed (The Art of the Cold Call). Nancy is a member
of Toastmasters International.', 1, 100))
6 ;
1 row created.
SQL>
In this case I suggest simply make the NOTES column larger:
ALTER TABLE SHOP.EMPLOYEES
MODIFY (NOTES VARCHAR2(4000));
dbfiddle here
If you need something larger than this you could use the CLOB data type.

Error converting varchar to numeric (but there's no number)

I have a table with several columns, like this:
CREATE TABLE CRM.INFO_ADICIONAL
(
ID_INFO_ADICIONAL NUMBER(10) NOT NULL,
NOMBRE VARCHAR2(100 BYTE) NOT NULL,
OBLIGATORIO NUMBER(1) NOT NULL,
TIPO_DATO VARCHAR2(2 BYTE) NOT NULL,
ACTIVO NUMBER(1) NOT NULL,
ID_TIPO_REQUERIMIENTO NUMBER(10) NOT NULL,
ID_USUARIO_AUDIT NUMBER(10) NOT NULL,
ORDEN NUMBER(3) DEFAULT 1,
RECHAZO_POR_NO NUMBER(1),
ID_TIPO_ARCHIVO_ADJUNTO NUMBER(10),
SOLICITAR_EN VARCHAR2(30 BYTE),
ID_CONSULTA NUMBER(10),
COMBO_ID VARCHAR2(40 BYTE),
APLICAR_COMO_VENC NUMBER(1),
MODIFICABLE NUMBER(1) DEFAULT 0,
ID_AREA_GESTION NUMBER(10),
ID_TAREA NUMBER(10)
)
The "COMBO_ID" column is the target. It is defined as VARCHAR, but when I'm trying to insert a row, TOAD displays
"ORA-06502: PL/SQL: error : error de conversión de carácter a número
numérico o de valor"
Or a 'numeric conversion error', in english.
This table have some pre-existing data, and I even found some rows including values at COMBO_ID column, all of them being VARCHAR, i.e.:
NACION (Nation), SEXO (Sex), etc
I tried a few simple SELECT statements
SELECT
ID_INFO_ADICIONAL,
NOMBRE,
OBLIGATORIO,
TIPO_DATO,
ACTIVO,
ID_TIPO_REQUERIMIENTO,
ID_USUARIO_AUDIT,
ORDEN,
RECHAZO_POR_NO,
ID_TIPO_ARCHIVO_ADJUNTO,
SOLICITAR_EN,
COMBO_ID,
APLICAR_COMO_VENC,
ID_CONSULTA,
MODIFICABLE,
ID_AREA_GESTION,
ID_TAREA
INTO
pRegistro
FROM
crm.info_adicional
where pRegistro is declared as
pRegistro INFO_ADICIONAL%ROWTYPE;
Again, I'm still getting this 'numeric conversion error'.
But, wait, if I hardcode the SELECT value in COMBO_ID column with a NUMBER:
SELECT
--other columns
123456 COMBO_ID,
--other columns
INTO
pRegistro
FROM
crm.info_adicional
It works, what the heck, it's defined as VARCHAR.
If I do the same but harcoding a string, it fails to execute again
Already tried in my DEV environment, and it's working fine.
I'm not a pro in Oracle, but I feel pretty lost.
Could it be that tables get "confused"?
Any clues?
That error can also be raised if you try to push a character string that is longer than your VARCHAR2's capacity (40 in your case).
Try to check if all the data you are trying to insert is correct :
SELECT
COMBO_ID
FROM
crm.info_adicional
ORDER BY length(COMBO_ID) desc;
That would also explain why it works fine on your DEV environment which, I suppose, has different data.
Okay, I already found the answer.
Quoting Oracle Documentation:
The %ROWTYPE attribute provides a record type that represents a row in a table or view. Columns in a row and corresponding fields in a record have the same names and datatypes.
So, basically, the SELECT statement needed to be in the same order as the table columns definition.
In my case, I had a few columns (including COMBO_ID) in a different order.
Tried, re-ordering, and works like a charm.
Thank you all for the support.

Oracle trigger insert to other table then modify the original table

I have theses two tables:
TABLE ASSET_ENTRY_NOTE (
ID NUMBER NOT NULL, --PK
ASSETMDL_ID NUMBER NOT NULL, --FK
DEPT_ID NUMBER NOT NULL, --FK
LOCATION NVARCHAR2(100) NOT NULL,
ASSET_ID NUMBER, --FK TO ASSETS
ACCOUNT_ID NUMBER NOT NULL, --FK
TOTAL_DPRC_DURATION FLOAT(126) NOT NULL,
TOTAL_PROD_HRS FLOAT(126),
AMORTIZATION_PRCNTG FLOAT(126),
ACQUIRE_DATE DATE NOT NULL,
DESCRIPTION NVARCHAR2(200) NOT NULL,
APPRFLAG NUMBER DEFAULT 0 NOT NULL,
WRK_HRS FLOAT(126),
)
TABLE ASSETS (
ID NUMBER NOT NULL, --PK
ASSETMDL_ID NUMBER NOT NULL, --FK
DEPT_ID NUMBER NOT NULL,
LOCATION NVARCHAR2(100) NOT NULL, --FK
ACCOUNT_ID NUMBER NOT NULL,
ACQUIRE_DATE DATE NOT NULL,
TOTAL_DPRC_DURATION FLOAT(126),
BALANCE_CLOSING_DATE DATE,
SELL_VAL FLOAT(126),
RPLCMNT_DISCOUNT FLOAT(126),
DESCRIPTION NVARCHAR2(200) NOT NULL,
)
Note that there's a one to one relationship between the two tables (i.e. ASSET_ENTRY_NOTE.ASSET_ID is Unique.
When the ASSETS_ENTRY_NOTE.APPRFLAG is updated to 1 I have this trigger that:
gets a new primary key sequence for the ASSETS table.
insert data from ASSETS_ENTRY_NOTE to ASSETS.
updates the column ASSETS_ENTRY_NOTE.ASSET_ID to the same value as the primary key value on the sequence.
This is the latest try for my trigger:
CREATE OR REPLACE TRIGGER ENTRYNT_ASSET_TRIG
after UPDATE OF APPRFLAG ON ASSET_ENTRY_NOTE
for each row
when (new.apprflag = 1)
declare
v_asset_id number;
BEGIN
SELECT assets_PK_SEQ.NEXTVAL INTO v_asset_id
FROM DUAL d;
insert into assets (ID,
assets.assetmdl_id,
assets.dept_id,
assets.location,
assets.account_id,
assets.acquire_date,
assets.total_dprc_duration,
assets.description
)
values (v_asset_id,
assetmdl_id,
dept_id,
location,
account_id,
acquire_date,
total_dprc_duration,
description
);
update ASSET_ENTRY_NOTE set asset_id = v_asset_id where ;
END;
The thing is, I know that ASSET_ENTRY_NOTE is a mutating table and the last UPDATE statement is not allowed here, But nothing else is working for me.
What I've already tried:
creating a statement-level trigger to update one value only.
using before instead of after but that's incorrect because I need the values just to insert into the ASSETS.
using a cursor to go through each value changed but I had exact fetch error.
creating a procedure that handles inserting and updating.
Any help would be appreciated.
The design seems quite strange to me, but to answer the question about the trigger:
To change the asset_entry_note row in the trigger, you need a before update trigger. In there you can just assign the value to the asset_id column.
Your insert statement is also wrong. You can table-qualify column names in the column list of an insert statement. And the values clause needs to use the values from the inserted row. You are referencing the target table's columns which is not allowed).
You also don't need a select statement to obtain the sequence value.
Putting all that together, your trigger should look something like this:
CREATE OR REPLACE TRIGGER ENTRYNT_ASSET_TRIG
BEFORE UPDATE OF APPRFLAG ON ASSET_ENTRY_NOTE
for each row
when (new.apprflag = 1)
declare
v_asset_id number;
BEGIN
v_asset_id := assets_PK_SEQ.NEXTVAL;
insert into assets
(ID,
assetmdl_id,
dept_id,
location,
account_id,
acquire_date,
total_dprc_duration,
description)
values
(v_asset_id,
new.assetmdl_id, -- reference the inserted row here!
new.dept_id,
new.location,
new.account_id,
new.acquire_date,
new.total_dprc_duration,
new.description);
new.asset_id := v_asset_id;
END;
/
You have to change the design of the application to have only one table with sign to indicate the membership of a particular entity.
Another way is to create 'after statement' trigger to update all affected rows in ASSET_ENTRY_NOTE with proper values. These rows is to be collected in, for example, package collection in row-level trigger.
I fixed it and it worked:
changed to before.
edited the update statement to an assignment of new so that the last line would become :new.asset_id := v_asset_id ;

Missing parentheses in CREATE TABLE instruction

CREATE TABLE MAJEST_PROD_2015(
PRODUCT_ID CHAR(10) NOT NULL,
DESCRIPTION_PROD CHAR(30),
SEW_DATE DATE,
HARVEST_DATE DATE,
QUANTITY INT,
PROD_RATING INT(1),
PRIMARY KEY (PRODUCT_ID)
);
Error report -
SQL Error: ORA-00907: missing right parenthesis
00907. 00000 - "missing right parenthesis"
*Cause:
*Action:
Oracle is not MySQL so there is no INT(1) type:
CREATE TABLE MAJEST_PROD_2015(
PRODUCT_ID CHAR(10) NOT NULL,
DESCRIPTION_PROD CHAR(30),
SEW_DATE DATE,
HARVEST_DATE DATE,
QUANTITY INT,
PROD_RATING INT, -- here
PRIMARY KEY (PRODUCT_ID)
);
SqlFiddleDemo
If you don't need constant size of string, consider using VARCHAR2(30).
EDIT:
but i need those values to be between 1-5
So add check constraint:
CONSTRAINT chk_PROD_RATING CHECK (PROD_RATING BETWEEN 1 AND 5),
SqlFiddleDemo2
As already noted INT does not take a length constraint in Oracle - instead you could use NUMBER(1,0) which would restrict it to a single digit (-9 .. +9) and then you can further restrict it using a CHECK constraint.
CHAR(n) will also right pad the value with space (CHR(32)) characters so that it always contains the maximum number of characters. If you did not intend this then you should be using VARCHAR2(n) instead.
You also do not need a NOT NULL constraint on a column that is the PRIMARY KEY.
CREATE TABLE MAJEST_PROD_2015(
PRODUCT_ID VARCHAR2(10) CONSTRAINT MAJEST_PROD_2015__PROD_ID__PK PRIMARY KEY,
DESCRIPTION_PROD VARCHAR2(30),
SEW_DATE DATE,
HARVEST_DATE DATE,
QUANTITY INT,
PROD_RATING NUMBER(1,0) CONSTRAINT MAJEST_PROD_2015__PROD_RAT__CK CHECK ( PROD_RATING BETWEEN 1 AND 5 )
);
(also, should it be SEW_DATE or SOW_DATE? Since the next line talks about harvest then I would have thought "sow" was more apt.)

Resources