Oracle SQL - Help putting a table together - oracle

part of my learning process, I am taking as much data I have on my computer and trying to use it to practice Oracle SQL. So I am in charge of keeping track of the Home Owner association money, I created a table with the following columns:
Name Null? Type
------------------ ----- ------------
OWNER_NAME VARCHAR2(20)
APPARTEMENT_NUMBER NUMBER(4)
TELEPHONE_NUMBER NUMBER(15)
JULY NUMBER(5)
AUGUST NUMBER(5)
SEPTEMBER NUMBER(5)
OCTOBER NUMBER(5)
NOVEMBER NUMBER(5)
DECEMBER NUMBER(5)
but I don't know how to do the following:
I need a way to track if the apt number paid its HOA fees, my idea is to have a check box and check it if the fee is paid and uncheck it if the fee is not paid. I'm just thinking out loud.
Please help
Thank you

Data model looks wrong. You shouldn't have months as column names - use only one DATE datatype column because - this one will be OK for this year. What about the next year? How will you know which "July" is it? Or, if that column contains only [month + year] info, make it VARCHAR2(6).
Phone number (and probably apartment number as well) should be strings because of leading zeros (in phone numbers) or letters in apartment numbers.
As of the "checkbox", there's no such datatype, but you can use NUMBER (1 - checkbox checked; 0 - not checked) or CHAR (Y / N) for that purpose.
Something like this:
create table hoa_fees
(owner_name varchar2(20),
apartment_number varchar2(4),
telephone_number varchar2(15),
month_year varchar2(6), -- e.g. 102020
fee number, -- money here
cb_paid number(1) default 0 not null -- e.g. 1 - paid
);

Related

is that possible to load data of various format in date column | Oracle

Table :
SQL> DESC EMO_SRC;
Name Null? Type
----------------------------------------------------- -------- ------------------------------------
EMPLOYEE_NAME VARCHAR2(30)
EMPLOYEE_NUMBER NUMBER
STATE VARCHAR2(10)
ZIP NUMBER
DOB DATE
AGE NUMBER
SEX VARCHAR2(7)
MARITALDESC VARCHAR2(15)
CITIZENDESC VARCHAR2(15)
HISPANIC_LATINO_RACEDESC VARCHAR2(15)
DATE_OF_HIRE DATE
DATE_OF_TERMINATION DATE
REASON_FOR_TERM VARCHAR2(50)
EMPLOYMENT_STATUS VARCHAR2(15)
DEPARTMENT VARCHAR2(30)
POSITION VARCHAR2(20)
PAY_RATE NUMBER(6,2)
MANAGER_NAME VARCHAR2(20)
EMPLOYEE_SOURCE VARCHAR2(30)
PERFORMANCE_SCORE VARCHAR2(40)
Table EMO_SRC has 3 "date" columns DOB,Date_of_hire and date_of _Termination
If
==========================================================
DOB | Date_of_hire | date_of_termination
============================================================
11/24/1987 10/27/2008 10/28/2016
4-26-1984 1-06-2014
02-26-1984 09/29/2014 4-15-2017
like above , the data has random date format for these 3 columns . Oracle not allowing to load '01-06-2014 ' format .
please let me know is there any way to load date value of different format or I need to convert data to '00/00/0000' format . Huge number of data mismatch is load . Then how, can I change and load the data in table .
SQL> show parameters nls_date_format;
NAME TYPE VALUE
------------------------------------ ---------- ------------------------------
nls_date_format string DD-MON-RR
Please let me know the solution .
You didn't mention which tool you use.
Anyway, you have a problem. "Date" formats are different within columns and within rows which makes it even worse.
I'd suggest you to create a function which will accept input values - "dates" (actually, strings) you find in source data and try to convert it to a valid DATE using TO_DATE function with different format masks: mm/dd/yyyy, dd-mm-yyyy, etc., whichever you find in source. Use inner BEGIN-EXCEPTION-END blocks so that the first failure wouldn't terminate function's execution. If you manage to find correct date value, fine - load it. If not, log the error and try to fix it by another TO_DATE's format mask. Optionally, you might use REGEXP_LIKE to verify input format.
Problem you can't solve is a string that looks like 10-08-20. Which is which? Is 10 day, month or year? The same goes for other values.
Also, calling a function for all those values - if source is large - will certainly take a lot of time.

plsql - can anyone help me out how do we reset a sequence in oracle 11 g database at two particular times in one single day?

Let me explain you the scenario of hospital management tool.
In every hospital, we have n no. of doctors, n no. of admins, n no. of security, etc departments respectively. Each and every hospital we have an out-patient consultations in the morning time approximately around 8:00 am to 10:00 am, from 10:00 am to evening 5:00 pm doctors will undertake operations and treatments for In-patients in "Intensive care unit" (ICU). So now after 5:00 pm again the doctors will have an out-patients consultation in the hospital from 18:00 pm to 20:00 pm.
Now, let me explain the same in technical terminology to you.
When the out-patients come ask a token number of so and so doctor. The admin will then select particular department in the UI and select particular doctor as per patient's problem. For this, i'm maintaining a each doctor's tables in the database which doctor name itself..
example :
1)Neurology Department
i) Dr. Sarath Kumar
ii) Dr. anil kumar
2)Cardiology Department
i) Dr. Madhu
ii) Dr. Anji Reddy
3)Orthopedics Department
i) Dr. Murali
ii) Dr. Sirisha
etc...
Creation of a doctor table :
create table sarath_Kumar(token_no not null primary key,
patient_name char(50) not null ,
patient_age number(3) not null ,
patient_phonenumber number(12) not null unique ,
patient_email varchar2(50) not null unique,
patient_gender char(1) not null,
patient_location varchar2(50) not null,
patient_dateofappointment date not null,
CONSTRAINT sk_token_no CHECK (token_no<=20);
Note:
if we think generally admin doesn't know which token number is going on for each and every doctor.
As we have the same table structure for each and every doctor by their name. But now the thing is the first column in each doctor table has to generate automatically from 1, to do this i created a sequence and a procedure to execute the sequence before an insertion happens by the admin.
let's take morning session of out-patients consultation from 8:00 am to 10:00 am. Each doctor will only have a 20 patients for consultation.
Sequence Creation :
create sequence appointment_sequence
start with 1
increment by 1
minvalue 1
maxvalue 20
cache 5
;
Procedure Creation :
create or replace trigger appointment_sequence before insert on sarath_kumar for each row
begin
:new.token_no := appointment_sequence.NEXTVAL;
end;
/
what i need from you is :
After reaching 20 patients for any doctor during consultation i.e., the token number reached it's maximum level between 8:00 am to 10:00 am. If any person asks for a appointment for that particular doctor. The admin shouldn't able to provide any kind of appointment for that doctor and insist the patient to come in evening time consultation which is from 18:00 pm to 20:00pm .
I need a procedure or function in which the doctor table should get truncated and the sequence should get reset back to minvalue at 10:00 am and in the evening after 20:00 pm respectively.
First of all, You should have the patient_appoint table instead of a separate table with the doctor's name and just pass the doctor's ID in that table.
create table patient_appoint(token_no not null primary key,
doctor_id number not null,
patient_name char(50) not null ,
patient_age number(3) not null ,
patient_phonenumber number(12) not null unique ,
patient_email varchar2(50) not null unique,
patient_gender char(1) not null,
patient_location varchar2(50) not null,
patient_dateofappointment date not null,
CONSTRAINT sk_token_no CHECK (token_no<=20);
For resetting the sequence to 1, Use CYCLE property of sequence. Use below code to generate the sequence -
create sequence appointment_sequence
start with 1
increment by 1
minvalue 1
maxvalue 20
cycle
cache 5
;
For restricting to only 20 patients per day, you may use below trigger -
CREATE OR REPLACE TRIGGER TR_PATIENT_APPOINT
AFTER INSERT ON PATIENT_APPOINT
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_count
FROM PATIENT_APPOINT
WHERE TRUNC(patient_dateofappointment) = TRUNC(SYSDATE);
IF (v_count > 20) THEN
raise_application_error(-20000, 'Maximum 20 appointments allowed per day.');
END IF;
END TR_PATIENT_APPOINT;
As others have pointed out or at lest hinted at this will be a maintenance nightmare, with each doctor having their own table and their own sequence. Consider what happens when a patient cancels. You don't get that sequence value back, so that doctor can only see 19 patients. And that is an easy situation to handle. There is an easier way: don't use sequences.
If you break it down each patent is essentially given a 6min time slot (120min/20slots). With his you generate a skeleton schedule for each doctor that does not have patient information initially. Admins then fill in patient information when needed, and can actually view the available time for each doctor. The following shows how to generate such a schedule. (Note it assumes you have normalized you doctor table (1 table containing all doctors) and created a patient table (1 table containing all patients).
--- prior Setup
create table doctors(doc_id integer, name varchar2(50), ..., constraint doc_pk primary key (doc_id));
create table patients(pat_id integer, name varchar2(50), ..., constraint pat_pk primary key (pat_id));
--- Daily Out patient Schedule.
create table out_patient_schedule (
ops_id integer
, doc_id integer not null
, pat_id integer
, apt_schedule date
, constraint ops_pk primary key (ops_id)
, constraint ops2doc_fk foreign key (doc_id) references doctors(doc_id)
, constraint ops2pat_fk foreign key (pat_id) references patients(pat_id)
);
--- Generate skeleton schedule
create or replace procedure gen_outpatient_skeleton_schedule
as
begin
insert into out_patient_schedule( doc_id, apt_schedule)
with apt_times as
( select trunc(sysdate, 'day') + 8/24 + (120/20)*(level-1)/(60*24) apt_time from dual connect by level <= 20
union all
select trunc(sysdate, 'day') + 18/24 + (120/20)*(level-1)/(60*24) from dual connect by level <= 20
)
select doc_id, apt_time from doctors, apt_times;
end gen_outpatient_skeleton_schedule;
Now create an Oracle Job, or an entry for what ever job schedule you have, that executes the above procedure between midnight and 8:00.
There is a race condition you need to handle, but doing so would be much easier that trying it with sequences.
Good Luck either way.

00904 When Creating Table

Here is the code I'm using in Oracle SQL Developer :
CREATE TABLE ORDER_ITEMS(
ITEM_NO NUMBER(10),
ITEM_DESCRIPTION VARCHAR(50),
SIZE VARCHAR(5),
COST NUMBER(8,2),
QUANTITY NUMBER(10),
TOTAL NUMBER(8,2),
ITEM_ORDER_NO NUMBER(10),
CONSTRAINT ITM_NO_PK PRIMARY KEY (ITEM_NO));
The error has to do with the SIZE and COST tables, if I change the names on those two tables (for example put an A at the end of them (SIZEA COSTA)) then the code works. Why are these table names invalid ?
I think you mean column where you're writing table. Also SIZE is a reserved word in Oracle SQL, as is NUMBER.
https://docs.oracle.com/cd/B19306_01/server.102/b14200/ap_keywd.htm

Creating Table with CC Exp Date - Oracle PL SQL

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.

Oracle trigger that update record after insert

I want update book ant set amount-1, when after insert record to sell table.
create table book (
id number(3) not null,
name varchar(20),
author varchar(12),
amount number(3) not null,
constraint book_pk primary key(id)
);
create table sell (
id number(3) not null,
date varchar(20),
book_id number(3),
constraint sell_pk primary key(id)
);
I want after insert to table sell record update book table amount-1;
CREATE OR REPLACE TRIGER changes_amount_trigger
AFTER INSERT ON sell
FOR EACH ROW
BEGIN
UPDATE BOOK SET amount = amount-1 WHERE id = book_id
END;
I not know how to get inserted record book id, to update this record in book table.
Try like this,
CREATE OR REPLACE TRIGGER changes_amount_trigger
AFTER INSERT ON sell
FOR EACH ROW
BEGIN
UPDATE BOOK SET amount = amount-1 WHERE id = :new.book_id;
END;
/
Data Model Assumptions:
I am assuming you will register transactions by changing the data in the SELL table through INSERT DML SQL operations. This is also supported by your set up of a DML trigger on SELL to pass its changes as SALES information to the BOOK table. This is workable.
By accident, I tried setting up the trigger a little differently and I'd like to suggest a different approach:
Consider possibly working in the opposite direction: Change book quantities directly on the BOOK table, so a single purchase of book_id = 5 would handle queries that could:
UPDATE book SET amount = amount -1
WHERE id = 5; COMMIT;
Restocking would mean increasing the quantity of available books
by incrementing the AMOUNT value instead.
There are a few additional changes that might tighten up this two-table design and protect the integrity of the data within them for the longer term:
CREATE TABLE book (
id number(3) not null,
name varchar(20),
author varchar(12),
amount number(3) not null,
CONSTRAINT book_pk PRIMARY KEY(id)
);
ALTER TABLE book
ADD CONSTRAINT book_amt_ck CHECK (amount > 0);
ALTER TABLE book
ENABLE CONSTRAINT book_amt_ck;
To prevent negative book amount (quantity) values, a TABLE CHECK CONSTRAINT would prevent the entry of values by means of arithmetic errors in DML operations such as:
UPDATE book SET amount := amount - 1
In the example above, there is no control over decrementing the book inventory even if the quantity on hand has reached 0. Check out a few references on TABLE CHECK CONSTRAINTS to get a better understanding of what it can do for specific design situations.
Here are some design suggestions for the trigger:
Changes in book quantities should be the only triggering data element that affects the SELL table.
The trigger should account for changes in book quantities > 1.
CREATE OR REPLACE TRIGGER orders_after_update
AFTER UPDATE
ON book
FOR EACH ROW
DECLARE
v_amount number;
BEGIN
IF (:new.amount < :old.amount ) THEN
FOR v_amount in 1 .. (:old.amount - :new.amount)
LOOP
INSERT INTO sell (id, date, book_id)
VALUES (sell_seq.nextval, sysdate, :new.id);
COMMIT;
END LOOP;
END IF;
END;
For more information on triggers and their design, check a few instances to get a better understanding of how they are designed and set up.
CREATE SEQUENCE sell_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1
CACHE 20;
We needed a sequence to populate the primary key/index of the SELL table. Oracle Sequences are useful for this purpose.
By watching the table changes with a trigger on the BOOK table, you can use the built in references which already exist when a table trigger fires. For example, BOOK.ID does not require an additional query because a trigger automatically is made aware of the beginning and ending value of each trigger monitored record.
Some useful discussions on triggers are discussed in more detail through an Internet search.
Setting Up a Foreign Key Relationship
Although the trigger will probably keep this relation clean, a Foreign Key relation between elements BOOK.ID and SELL.BOOK_ID would be good, otherwise queries on Sales transactions may yield book sales without any descriptive production information. The following is a reference on Foreign Keys and their use.
CREATE TABLE sell (
id number(3) not null,
date varchar(20),
book_id number(3)
);
ALTER TABLE table_name
ADD CONSTRAINT sell_fk
FOREIGN KEY (book_id)
REFERENCES book(id);
Do you already have records in sell table and want to update the amount in book table ?
if this is your case you can update your book.amount as following:
update book b
set b.amount = b.amount - (select count(*) from sell s where b.id = s.book_id);

Resources