Bill Calculation using SQL - sql

I've having some problems as I'm trying to calculate the total amount for a consumption.
so for example:
for the first 20 watt is charged at 0.40
for the next 20 watt is charged at 0.80
and 0.90 for each watt in excess of 20 watt
I've tried doing something on my own but the calculation is wrong and is there any way to optimize the query as i do not wish to do the calculation at the main select statement. is subquery a better option?
I'm using Oracle as DB engine
SELECT CustomerName, previousRead, newRead, newRead-previousRead AS Consumption,
(((newRead-previousRead-100)*FR)+((newRead-previousRead-200)*SR)+((newRead-previousRead-200)/200)*TR)as TotalBill
FROM (
SELECT C.firstName||''||C.lastName as CustomerName, R.newReading previousRead,
lead(R.newReading) OVER (PARTITION BY R.meterID ORDER BY R.dateVisited) AS newRead, B.firstconsumptionRate as FR,
B.secondconsumptionRate as SR, B.firstconsumptionRate as TR
FROM reading R, serviceaddress S, electricmeter W, customer C, rate A, nonresidentialrate B
WHERE W.meterID = S.meterID
AND R.meterID = W.meterID
AND A.rateID = S.rateID
AND B.rateID = A.rateID
AND C.custID = S.custID
AND C.custType = 'Non-residential'
AND r.datevisited >= TO_DATE('01-06-2014','DD-MM-YYYY')
AND r.datevisited < TO_DATE('31-07-2014','DD-MM-YYYY')
)where newRead is not null;
Table
CREATE TABLE Customer(
custID INTEGER NOT NULL,
firstName CHAR(25) NOT NULL,
lastName CHAR(25) NOT NULL,
NRIC CHAR(9) NOT NULL,
custType CHAR(25) NOT NULL,
badStatus CHAR(25) Default 'Good',
CONSTRAINT cust_Pkey PRIMARY KEY (custID),
CONSTRAINT cust_type CHECK (custType IN ('Residential', 'Non-residential')),
CONSTRAINT custBadStatus_type CHECK (badStatus IN ('Late Payment', 'Non Payment', 'Good'))
);
CREATE TABLE Reading (
readingID INTEGER NOT NULL,
meterID INTEGER NOT NULL,
dateVisited DATE NOT NULL,
newReading NUMBER(10,0) NOT NULL,
CONSTRAINT reading_Pkey PRIMARY KEY (readingID),
CONSTRAINT reading_AltKey UNIQUE (meterID, dateVisited),
CONSTRAINT reading_meterID_Fkey FOREIGN KEY (meterID) REFERENCES Meter (meterID),
CONSTRAINT checkReading CHECK (newReading > 0)
);
CREATE TABLE Rate (
rateID INTEGER NOT NULL,
rateApprDate DATE NOT NULL,
rateEffDate DATE NOT NULL,
rateType CHAR(25) NOT NULL,
CONSTRAINT rate_Pkey PRIMARY KEY (rateID),
CONSTRAINT rateType CHECK (rateType IN ('Residential', 'Non-residential')),
CONSTRAINT validDate CHECK (rateApprDate < rateEffDate),
);
CREATE TABLE NonResidentialRate (
rateID INTEGER NOT NULL,
firstconsumptionRate NUMBER(5,2) NOT NULL,
secondconsumptionRate NUMBER(5,2) NOT NULL,
thirdconsumptionRate NUMBER(5,2) NOT NULL,
CONSTRAINT nonResidentialRate_Pkey PRIMARY KEY (rateID),
CONSTRAINT nonResidentialRate_rateID_FK FOREIGN KEY (rateID) REFERENCES Rate (rateID)
);
CREATE TABLE ServiceAddress (
svcAddID INTEGER NOT NULL,
meterID INTEGER NOT NULL,
custID INTEGER NOT NULL,
rateID INTEGER NOT NULL,
street CHAR(30) NOT NULL,
city CHAR(35) NULL,
state CHAR(2) NULL,
zipPostalCode CHAR(9) NOT NULL,
CONSTRAINT serviceAddress_Pkey PRIMARY KEY (svcAddID),
CONSTRAINT serviceAddress_meterID_Fkey FOREIGN KEY (meterID) REFERENCES Meter (meterID),
CONSTRAINT serviceAddress_custID_Fkey FOREIGN KEY (custID) REFERENCES Customer (custID),
CONSTRAINT serviceAddress_rateID_Fkey FOREIGN KEY (rateID) REFERENCES Rate (rateID),
);
CREATE TABLE Meter (
meterID INTEGER NOT NULL,
SerialNum CHAR(30) NOT NULL,
installationDate DATE NOT NULL,
CONSTRAINT waterMeter_Pkey PRIMARY KEY (meterID),
CONSTRAINT waterMeter_Altkey UNIQUE (SerialNum)
);
The customer can be both of residential and non-residential and each of them has a service address. The meter is unique to each service address and the reading is stored in a different table.
There are 2 kinds of rates as well, their are different kind of rates for residential and nonresidential.
As for the reading, I did not create a new attribute for previous reading because it can be obtained tru the previous month reading
hope this makes my question clearer.

Here you go, you can give it a try..
SELECT CustomerName, previousRead, newRead, newRead-previousRead AS Consumption,
CASE WHEN newRead-previousRead <= 100
THEN (newRead-previousRead)*FR
WHEN newRead-previousRead <= 200
THEN 100*FR + (newRead-previousRead-100)*SR
WHEN newRead-previousRead > 200
THEN 100*FR + 100*SR + ((newRead-previousRead)-200)*TR
END as TotalBill
FROM (
SELECT C.firstName||''||C.lastName as CustomerName, R.newReading previousRead,
lead(R.newReading) OVER (PARTITION BY R.meterID ORDER BY R.dateVisited) AS newRead, B.firstconsumptionRate as FR,
B.secondconsumptionRate as SR, B.thirdconsumptionRate as TR
FROM reading R, serviceaddress S, meter W, customer C, rate A, nonresidentialrate B
WHERE W.meterID = S.meterID
AND R.meterID = W.meterID
AND A.rateID = S.rateID
AND B.rateID = A.rateID
AND C.custID = S.custID
AND C.custType = 'Non-residential'
AND r.datevisited >= TO_DATE('01-06-2014','DD-MM-YYYY')
AND r.datevisited < TO_DATE('31-07-2014','DD-MM-YYYY')
)where newRead is not null;

Were it me, I'd probably use a CASE statement and structure the code for clarity rather than trying to eke out every last cycle of performance (unless you're really in an environment where you need every last cycle)
(CASE WHEN newRead-previousRead <= 20
THEN (newRead-previousRead)*0.40
WHEN newRead-previousRead <= 40
THEN 20*0.40 + (newRead-previousRead-20)*0.80
WHEN newRead-previousRead > 40
THEN 20*0.40 + 20*0.80 + (newRead-previousRead-40)*0.90
END)
Now, obviously, there are ways to optimize this (by, for example, computing newRead-previousRead in the inner query once rather than potentially needing to compute it 4 times in the CASE statement). And this is not a particularly flexible option if you want to be able to change the billing structure frequently (in which case the tiers and rates would need to be in a separate table that you read). But it's hopefully a relatively clear expression of the computation.

Related

How to get the highest appearance value in one table, from another table?

So I have 3 tables referencing cars, assurance and accident.
I want to know the brand of vehicles who had the most accidents, compared to others.
I have tried a lot of ways to that, but mostly i only get or all the brands returned or the brand of the car that was registered the most, not the one that had most accidents
These are my tables
create table car(
n_veic bigint not null,
matric varchar(15) not null,
pais_matric text not null,
n_pess bigint not null,
tipo text not null,
cor text not null,
brand text not null,
modelo varchar(15),
primary key(n_veic),
unique(matric),
foreign key (n_pess) references pessoa(n_pess)
);
create table ensurance(
apolice bigint not null,
segurado bigint not null,
car bigint not null,
datai date not null,
dataf date not null,
cobertura numeric(10,2) not null,
primary key(apolice),
unique(segurado, veiculo),
foreign key (segurado) references pessoa(n_pess),
foreign key (car) references car(n_veic)
);
create table accident(
n_acid bigint not null,
pess_segura bigint not null,
veic_seguro bigint not null,
data date not null,
local varchar(255) not null,
descr text not null,
primary key(n_acid),
unique(n_acid, veic_seguro),
foreign key (pess_segura,veic_seguro) references ensurance(segurado, car)
This is what i tried
SELECT marca
FROM veiculo NATURAL JOIN acidente
GROUP BY marca
HAVING count (distinct n_veic)>=ALL
(SELECT count (distinct n_veic)
FROM veiculo NATURAL JOIN acidente
GROUP BY marca);
I think the logic is:
select c.marca, count(*) as num_acidentes
from acidente a join
car c
on a.veic_seguro = c.n_veic
group by c.marca
order by num_acidentes desc;
You can use fetch first 1 row only -- or whatever is appropriate for your database -- to get only one row.
Try this-
Note:
1. Try to avoid NATURAL JOIN and use specific column reference.
2. Rethink DISTINCT for count is really necessary or not.
SELECT TOP 1 marca, COUNT(DISTINCT n_veic)
FROM veiculo
NATURAL JOIN acidente
GROUP BY marca
ORDER BY COUNT(DISTINCT n_veic) DESC

Oracle SQL Average query

I need to do an average median with Oracle. I have this:
SELECT V.Id_Aeropuerto_Destino AS Id_Aeropuerto, C.Nombre AS Ciudad_Destino, A.nombre AS Aeropuerto,
(SELECT SUM((TO_NUMBER(V.Retraso_Salida,'99999999D99','nls_numeric_characters=''.,''')) +
(TO_NUMBER(V.Retraso_Llegada,'99999999D99','nls_numeric_characters=''.,''')))
FROM Vuelo V
WHERE V.Id_Aeropuerto_Destino=Id_Aeropuerto) Retraso_Total
FROM Ciudad C, Aeropuerto A, Vuelo V
WHERE V.Id_Aeropuerto_Destino=A.Id_Aeropuerto AND A.Ciudad = C.Id_Ciudad;
This calculates the total delay of a number of flights ("Retraso_Total"). Now I need to do an AVG from "Retraso_Total", to get ("Retraso_Total" / number of flights) -> Retraso_Medio, something like this:
SELECT V.Id_Aeropuerto_Destino AS Id_Aeropuerto, C.Nombre AS Ciudad_Destino, A.nombre AS Aeropuerto,
(SELECT AVG SUBQUERY) Retraso_Medio,
(SELECT SUM((TO_NUMBER(V.Retraso_Salida,'99999999D99','nls_numeric_characters=''.,''')) +
(TO_NUMBER(V.Retraso_Llegada,'99999999D99','nls_numeric_characters=''.,''')))
FROM Vuelo V
WHERE V.Id_Aeropuerto_Destino=Id_Aeropuerto) Retraso_Total
FROM Ciudad C, Aeropuerto A, Vuelo V
WHERE V.Id_Aeropuerto_Destino=A.Id_Aeropuerto AND A.Ciudad = C.Id_Ciudad;
I try with this:
SELECT AVG(SUM((TO_NUMBER(V.Retraso_Salida,'99999999D99','nls_numeric_characters=''.,''')) +
(TO_NUMBER(V.Retraso_Llegada,'99999999D99','nls_numeric_characters=''.,'''))))
FROM Vuelo V
WHERE V.Id_Aeropuerto_Destino=Id_Aeropuerto
GROUP BY V.Id_Aeropuerto_Destino) Retraso_Medio
But this subquery doesn't work.
How I can do that (all in the same query)?
Thanks!!
Table Vuelo (Flight) has (id_plane, id_origin_airport, id_destiny_airport, id_company, departure hour, arrival hour, departure delay, arrival delay, date, canceled, passengers, milles:
CREATE TABLE Vuelo(
Id_Avion number(4),
Id_Aeropuerto_Origen number(5),
Id_Aeropuerto_Destino number(5),
Id_Aerolinea varchar(2),
Hora_Salida number(4),
Hora_Llegada number(4),
Retraso_Salida varchar(5),
Retraso_Llegada varchar(5),
Fecha varchar(10),
Cancelado varchar(3) NOT NULL,
Pasajeros varchar(10) NOT NULL,
Distancia varchar(10) NOT NULL,
CONSTRAINT pk_Vuelo PRIMARY KEY(Id_Avion, Id_Aeropuerto_Origen, Fecha, Hora_salida),
CONSTRAINT fk_Avion FOREIGN KEY(Id_Avion) REFERENCES Avion(Id_Avion),
CONSTRAINT fk_Aeropuerto_Origen FOREIGN KEY(Id_Aeropuerto_Origen) REFERENCES Aeropuerto(Id_Aeropuerto),
CONSTRAINT fk_Aeropuerto_Destino FOREIGN KEY(Id_Aeropuerto_Destino) REFERENCES Aeropuerto(Id_Aeropuerto),
CONSTRAINT fk_Aerolinea FOREIGN KEY(Id_Aerolinea) REFERENCES Aerolinea(Id_Aerolinea),
CONSTRAINT fk_Fecha FOREIGN KEY(Fecha) REFERENCES Fecha(Id_Fecha)
);
Table Ciudad (City) has id_city, name, latitude, longitude, population, timezone:
CREATE TABLE Ciudad(
Id_Ciudad number(7),
Nombre varchar(80) NOT NULL,
Latitud varchar(15) NOT NULL,
Longitud varchar(15) NOT NULL,
Habitantes number(10) NOT NULL,
Timezone varchar(80) NOT NULL,
CONSTRAINT pk_Ciudad PRIMARY KEY(Id_Ciudad)
);
Table Aeropuerto (Airport) has id_airport, name, code, id_city, state, state_code:
CREATE TABLE Aeropuerto(
Id_Aeropuerto number(5),
Nombre varchar(80) NOT NULL,
Codigo varchar(4) NOT NULL,
Ciudad number(5) NOT NULL,
Estado varchar(80) NOT NULL,
Codigo_Estado varchar(4) NOT NULL,
CONSTRAINT pk_Aeropuerto PRIMARY KEY(Id_Aeropuerto),
CONSTRAINT fk_Ciudad FOREIGN KEY(Ciudad) REFERENCES Ciudad(Id_Ciudad)
);
From your comments it seems you want to calculate a MEAN rather than a MEDIAN as your question's opening line says.
This is quite simple. The Oracle AVG() function calculates the mean for us, without the need to derive totals and counts. Obviously it's still messy, due to the casting because table uses strings to store numeric values.
An average is an aggregate function, so we need to group by the non-aggregate columns. In your example that means the destination airport ID, City and Name. So this should work for you:
SELECT V.Id_Aeropuerto_Destino AS Id_Aeropuerto
, C.Nombre AS Ciudad_Destino
, A.nombre AS Aeropuerto
, AVG((TO_NUMBER(V.Retraso_Salida,'99999999D99','nls_numeric_characters=''.,''')) +
(TO_NUMBER(V.Retraso_Llegada,'99999999D99','nls_numeric_characters=''.,''')))
as "Retraso_Total"
FROM Vuelo V
join Aeropuerto A
on V.Id_Aeropuerto_Destino=A.Id_Aeropuerto
join Ciudad C
on A.Ciudad = C.Id_Ciudad
group by V.Id_Aeropuerto_Destino
, C.Nombre
, A.nombre
/

SQL NEWBIE, LIKE CLAUSE

I'm new to SQL could someone correct me this query ?!
CREATE TABLE AVION
(
AV int IDENTITY(100, 1) PRIMARY KEY,
AVMARQUE varchar(30) NOT NULL,
AVTYPE varchar(30) NOT NULL,
CAP int CHECK (CAP BETWEEN 100 AND 600),
LOC varchar(30)
)
CREATE TABLE PILOTE
(
PIL int IDENTITY(1,1) PRIMARY KEY,
PILNOM varchar(30) NOT NULL,
ADR varchar(30)
)
CREATE TABLE VOLE
(
VOL varchar(5) PRIMARY KEY CHECK(VOL LIKE 'IT'[1,9][0,9][0,9]),
PIL int FOREIGN KEY REFERENCES PILOTE(PIL),
AV int FOREIGN KEY REFERENCES AVION(AV),
VD varchar(30) NOT NULL,
VA varchar(30) NOT NULL,
HD TIME CHECK (HD BETWEEN '00:00' AND '23:59'),
HA TIME CHECK (HA BETWEEN '00:00' AND '23:59')
)
VOL is a string with 5 characters that start with 'IT' and the rest are numbers first number is different then 0
PIL FOREIGN KEY FROM PILOTE TABLE
AV FOREIGN KEY FROM AVION TABLE
VD is the departure city
VA is the destination city
HD is the departure time
HV is the arrival time
It might be as simple as moving the quotes. Try:
LIKE 'IT[1,9][0,9][0,9]'

PostgreSQL Error: there is not unique constraint matching given keys for referenced table

I am making a database for registration of classes and I am having trouble with the "Enrollment" table. I need to pass all the primary keys from sections into enrollment, but I also want to pass an additional key ("sectionNumber"). However, I do not want to make "sectionNumber" part of the primary key for "Sections", because I don't want to be passing sectionNumber into every table that I have a foreign key in that is from "Sections." Anyone got any suggestions on how to fix this? I keep getting the error below.
-- HOLDS A SPECIFIC COURSE WITHOUT THE INSTANCES OF THE CLASS --
CREATE TABLE Courses (
courseID SERIAL UNIQUE NOT NULL,
department TEXT NOT NULL,
courseNumber VARCHAR(10) NOT NULL,
courseName TEXT UNIQUE NOT NULL,
credits INT NOT NULL,
PRIMARY KEY(courseID)
);
-- PEOPLE SUPERTYPE --
CREATE TABLE People (
pid SERIAL UNIQUE NOT NULL,
fname TEXT NOT NULL,
lname TEXT NOT NULL,
PRIMARY KEY(pid)
);
-- HOLDS THE DIFFERENT PROFESSORS TEACHING AT THE SCHOOL --
-- SUBTYPE OF PEOPLE --
CREATE TABLE Professors (
professorID INT UNIQUE NOT NULL,
status TEXT NOT NULL,
CHECK(status = 'Full-Time' OR status = 'Part-time'),
PRIMARY KEY(professorID),
FOREIGN KEY(professorID) REFERENCES People(pid)
);
-- HOLDS THE SPECIFIC INSTANCES OF THE CLASS DEPENDING ON THE YEAR AND TERM --
CREATE TABLE Sections (
courseID INT NOT NULL,
year INT NOT NULL,
term TEXT NOT NULL,
sectionNumber INT NOT NULL,
startDate DATE NOT NULL,
endDate DATE NOT NULL,
crn INT NOT NULL,
CHECK(term = 'Fall' OR term = 'Winter' OR term = 'Spring' OR term = 'Summer'),
PRIMARY KEY(courseID, year, term),
FOREIGN KEY(courseID) REFERENCES Courses(courseID)
);
-- HOLDS THE EVENT OF THE CLASS --
-- A CLASS MAY HAVE DIFFERENT DAYS ON WHICH --
-- THEY MEET ON, SO THIS ALLOWS A CERTAIN --
-- SECTION TO HAVE SEVERAL DAYS WITHOUT CONFLICT --
CREATE TABLE ClassEvent (
professorID INT UNIQUE NOT NULL,
courseID INT NOT NULL,
year INT NOT NULL,
term TEXT NOT NULL,
day TEXT,
startTime TIME,
endTime TIME,
location TEXT,
campus TEXT,
CHECK(day = 'Monday' OR day = 'Tuesday' OR day = 'Wednesday' OR day = 'Thursday' OR day = 'Friday' OR day = 'Saturday' OR day = 'Sunday' OR day IS NULL),
CHECK(term = 'Fall' OR term = 'Winter' OR term = 'Spring' OR term = 'Summer'),
PRIMARY KEY(professorID, courseID, year, term, day, startTime, endTime),
FOREIGN KEY(professorID) REFERENCES Professors(professorID),
FOREIGN KEY(courseID, year, term) REFERENCES Sections(courseID, year, term)
);
-- GENERATES THE PREREQUESITES --
CREATE TABLE Prerequisites (
courseID INT NOT NULL,
year INT NOT NULL,
term TEXT NOT NULL,
prereqID INT NOT NULL,
CHECK(term = 'Fall' OR term = 'Winter' OR term = 'Spring' OR term = 'Summer'),
PRIMARY KEY(courseID, year, term, prereqID),
FOREIGN KEY(courseID, year, term) REFERENCES Sections(courseID, year, term),
FOREIGN KEY(prereqID) REFERENCES Courses(courseID)
);
-- HOLDS THE STUDENTS THAT WILL BE TAKING THE CLASSES --
-- SUBTYPE OF PEOPLE --
CREATE TABLE Students (
studentID INT REFERENCES People(pid) UNIQUE NOT NULL,
studentName TEXT NOT NULL,
gradYear DATE UNIQUE NOT NULL,
PRIMARY KEY(studentID)
);
-- HOLDS A CLASS RECORD FOR STUDENTS (AND POSSIBLY PROFESSORS) --
CREATE TABLE Enrollment (
studentID INT UNIQUE NOT NULL,
courseID INT NOT NULL,
year INT NOT NULL,
term TEXT NOT NULL,
sectionNumber INT NOT NULL,
grade TEXT,
CHECK(grade = 'A' OR grade = 'A-' OR grade = 'B+' OR grade = 'B' OR grade = 'B-' OR grade = 'C+' OR grade = 'C' OR grade = 'C-' OR grade = 'D+' OR grade = 'D' OR grade = 'D-' OR grade = 'F' OR grade = 'P/F'),
CHECK(term = 'Fall' OR term = 'Winter' OR term = 'Spring' OR term = 'Summer'),
PRIMARY KEY(studentID, courseID, year, term, sectionNumber),
FOREIGN KEY(studentID) REFERENCES Students(studentID),
FOREIGN KEY(courseID, year, term) REFERENCES Sections(courseID, year, term),
FOREIGN KEY(sectionNumber) REFERENCES Sections(sectionNumber)
);
-- HOLDS THE DIFFERENT DEGREES THAT CAN BE ATTAINED AT THE COLLEGE/UNIVERSITY --
CREATE TABLE Degrees (
degreeID SERIAL UNIQUE NOT NULL,
degreeName TEXT NOT NULL,
degreeType TEXT NOT NULL,
degDepartment VARCHAR(4) NOT NULL,
CHECK(degreeType = 'Major' OR degreeType = 'Minor' OR degreeType = 'Masters'),
PRIMARY KEY(degreeID)
);
-- HOLDS THE CLASSES THAT WILL MAKE UP A DEGREE --
CREATE TABLE DegreeReq (
degreeID INT REFERENCES Degrees(degreeID) UNIQUE NOT NULL,
courseID INT REFERENCES Courses(courseID) NOT NULL,
PRIMARY KEY(degreeID, courseID)
);
-- HOLDS THE INSTANCE OF A DEGREE FOR A CERTAIN STUDENT --
-- FOR EXAMPLE: A STUDENT CAN HAVE A MAJOR AND A MINOR --
-- SO HE/SHE CAN STORE THEM SEPARATELY --
CREATE TABLE DegreeInstance (
degreeID INT REFERENCES Degrees(degreeID) UNIQUE NOT NULL,
studentID INT REFERENCES Students(studentID) UNIQUE NOT NULL,
startDate DATE NOT NULL,
endDate DATE NOT NULL,
creditsRequired INT NOT NULL,
PRIMARY KEY(degreeID, studentID)
);
-- HOLDS ALL THE RATE MY PROFESSOR STATS --
CREATE TABLE Rating (
professorID INT UNIQUE NOT NULL,
rmpID BIGINT UNIQUE NOT NULL,
avgRating FLOAT NOT NULL,
avgHelpfulness FLOAT NOT NULL,
avgClarity FLOAT NOT NULL,
avgEasiness FLOAT NOT NULL,
PRIMARY KEY(professorID, rmpID),
FOREIGN KEY(professorID) REFERENCES Professors(professorID)
);
ERROR: there is no unique constraint matching given keys for referenced table "sections"
********** Error **********
ERROR: there is no unique constraint matching given keys for referenced table "sections"
SQL state: 42830
You have this relationship declared:
FOREIGN KEY(sectionNumber) REFERENCES Sections(sectionNumber)
sectionnumber is not declared to be unique. You need to fix the data structure or use the primary key.

SQL Logic and Aggregate Issue

I have the following problem to solve in SQL :
d) A query that provides management information on take up of the various types of activities on offer. For each type of activity, the query should show the total number of individuals who took that type of activity and the average number of individuals taking each type of activity.
Here are my tables :
CREATE TABLE accommodations
(
chalet_number int PRIMARY KEY,
chalet_name varchar(40) NOT NULL,
no_it_sleeps number(2) NOT NULL,
indivppw number(4) NOT NULL
)
CREATE TABLE supervisors
(
supervisor_number int PRIMARY KEY,
supervisor_forename varchar(30) NOT NULL,
supervisor_surname varchar(30) NOT NULL,
mobile_number varchar(11) NOT NULL
)
CREATE TABLE visitors
(
visitor_ID int PRIMARY KEY,
group_ID int NOT NULL,
forename varchar(20) NOT NULL,
surname varchar(20) NOT NULL,
dob date NOT NULL,
gender varchar(1) NOT NULL
)
CREATE TABLE activities
(
activity_code varchar(10) PRIMARY KEY,
activity_title varchar(20) NOT NULL,
"type" varchar(20) NOT NULL
)
CREATE TABLE "groups"
(
group_ID int PRIMARY KEY,
group_leader varchar(20) NOT NULL,
group_name varchar(30)
number_in_group number(2) NOT NULL
)
CREATE TABLE bookings
(
group_ID int NOT NULL,
start_date date NOT NULL,
chalet_number int NOT NULL,
no_in_chalet number(2) NOT NULL,
start_date date NOT NULL,
end_date date NOT NULL,
CONSTRAINT bookings_pk PRIMARY KEY(group_ID, chalet_number));
CREATE TABLE schedule
(
schedule_ID int PRIMARY KEY,
activity_code varchar(10) NOT NULL,
time_of_activity number(4,2) NOT NULL,
am_pm varchar(2) NOT NULL,
"date" date NOT NULL
)
CREATE TABLE activity_bookings
(
visitor_ID int NOT NULL,
schedule_ID int NOT NULL,
supervisor_number int NOT NULL,
comments varchar(200),
CONSTRAINT event_booking_pk PRIMARY KEY(visitor_ID, schedule_ID));
ALTER TABLE visitors
ADD FOREIGN KEY (group_ID)
REFERENCES "groups"(group_ID)
ALTER TABLE Schedule
ADD FOREIGN KEY (activity_code)
REFERENCES activities(activity_code)
ALTER TABLE bookings
ADD FOREIGN KEY (group_ID)
REFERENCES "groups"(group_ID)
ALTER TABLE bookings
ADD FOREIGN KEY (chalet_number)
REFERENCES accommodations(chalet_number)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (visitor_ID)
REFERENCES visitors(visitor_ID)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (schedule_ID)
REFERENCES schedule(schedule_ID)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (supervisor_number)
REFERENCES supervisors(supervisor_number)
I have the following solution:
SELECT activities."type", 'overalltotal' AS OT, ('overalltotal' / 'activities') AS AVG
FROM activities, schedule
WHERE 'overalltotal' = (SELECT SUM(COUNT(schedule_ID))
FROM activities, schedule
WHERE schedule.activity_code = activities.activity_code
GROUP BY activities."type"
)
AND 'activities' = (SELECT COUNT(DISTINCT activities."type")
FROM activities
)
AND schedule.activity_code = activities.activity_code
GROUP BY activities."type";
I have implemented sample data and code to check the variables above:
SELECT SUM(COUNT(schedule_ID))
FROM activities, schedule
WHERE schedule.activity_code = activities.activity_code
GROUP BY activities."type";
Result : 20
SELECT COUNT(DISTINCT activities."type")
FROM activities;
Result : 5
However when running the code :
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause:
*Action:
EDIT:
Using Dave's Code i have the following output:
Snowboarding 15
sledding 19
Snowmobiling 6
Ice Skating 5
Skiing 24
How would i do the final part of the question?
and the average number of individuals taking each type of activity.
You must use double quotes around column names in Oracle, not single quotes. For example, "overalltotal". Single quotes are for text strings, which is why you're getting an invalid number error.
EDIT: This is probably the type of query you want to use:
SELECT activities."type", COUNT(*) AS total, COUNT(*)/(COUNT(*) OVER ()) AS "avg"
FROM activities a
JOIN schedule s ON a.activity_code=s.activity_code
JOIN activity_bookings ab ON s.schedule_ID=ab.schedule_ID
GROUP BY activities."type";
Basically, because each activity booking has one visitor id, we want to get all the activity bookings for each activity. We have to go through schedule to do that. They we group the rows by the activity type and count how many activity bookings we have for each type.