Start and stop date fields vs. single date field for historical, hierarchical data - sql

In developing a historical and hierarchical SQL table, is it better to use start and stop date fields or a single date field for every date? There are pros and cons for each, but I'm looking for evidence as to which is more optimized, elegant, and takes into account corner cases most effectively.
Example -
-- Start/Stop
create table roster (
id bigint identity primary key,
start_date date not null,
stop_date date not null,
employee_id int not null references employee (id),
supervisor_id int not null references employee (id),
unique(start_date, stop_date, employee_id)
)
-- Single Date
create table roster (
id bigint identity primary key,
row_date date not null,
employee_id int not null references employee (id),
supervisor_id int not null references employee (id),
unique(row_date, employee_id)
)

Related

Сreating a calculated field from other tables

I want to create a calculated amount field in the sales table that will accept the total of the items related to this order, but I ran into a problem.
"subqueries cannot be used in the generated column expression."
Please tell me how you can do this, taking into account the fact that the architecture cannot be changed.
CREATE TABLE products (
id bigserial PRIMARY KEY,
name varchar(255) NOT NULL,
description varchar(255) NOT NULL,
price decimal NOT NULL
);
CREATE TABLE sales (
id bigserial PRIMARY KEY,
employee_id int NOT NULL,
created_at timestamp NOT NULL,
amount decimal GENERATED ALWAYS AS ( /* subqueris */ ) STORED
);
CREATE TABLE products_sales (
sales_id int NOT NULL,
product_id int NOT NULL,
PRIMARY KEY (sales_id, product_id)
);

When i insert value in the hire table it shows invalid identifier in the Vehicle_ID. There was no error while creating tables

-- Create a Database table to represent the "Vehicle" entity.
CREATE TABLE Vehicle(
Vehicle_ID INTEGER NOT NULL,
Purchase_Date DATE,
Vehicle_No_Plate VARCHAR(20),
Brand VARCHAR(20),
Vehicle_Type VARCHAR(20),
Model VARCHAR(20),
Color VARCHAR(20),
-- Specify the PRIMARY KEY constraint for table "Vehicle".
-- This indicates which attribute(s) uniquely identify each row of data.
CONSTRAINT pk_Vehicle PRIMARY KEY (Vehicle_ID)
);
-- Create a Database table to represent the "Hire" entity.
CREATE TABLE Hire(
Hire_ID INTEGER NOT NULL,
Hire_Date DATE,
Drop_In_Day DATE,
fk1_Customer_ID INTEGER NOT NULL REFERENCES Customer (Customer_ID),
fk2_Vehicle_ID INTEGER NOT NULL REFERENCES Vehicle (Vehicle_ID) ,
-- Specify the PRIMARY KEY constraint for table "Hire".
-- This indicates which attribute(s) uniquely identify each row of data.
CONSTRAINT pk_Hire PRIMARY KEY (Hire_ID)
);
INSERT INTO Hire
(Hire_ID, Hire_Date, Drop_In_Day, Customer_ID, Vehicle_ID)
VALUES (10, '8/3/2017', '8/7/2017', 101, 112);
ORA-00904: "VEHICLE_ID": invalid identifier
Try to examine this code snippet, it works for me.
CREATE TABLE Vehicle( Vehicle_ID INTEGER NOT NULL,
Purchase_Date DATE,
Vehicle_No_Plate VARCHAR(20),
Brand VARCHAR(20),
Vehicle_Type VARCHAR(20),
Model VARCHAR(20),
Color VARCHAR(20),
CONSTRAINT pk_Vehicle PRIMARY KEY (Vehicle_ID) );
CREATE TABLE Hire
(
Hire_ID NUMBER,
Hire_Date DATE,
Drop_In_Day DATE,
Customer_ID NUMBER,
Vehicle_ID NUMBER,
CONSTRAINT vei FOREIGN KEY (Vehicle_ID)
REFERENCES Vehicle (Vehicle_ID),
CONSTRAINT cust FOREIGN KEY (Customer_ID)
REFERENCES Customer (Customer_ID)
);
CREATE TABLE Customer(Customer_id NUMBER,
Name VARCHAR(20),
CONSTRAINT pk_Cust PRIMARY KEY (Customer_ID));
INSERT INTO Customer VALUES(100, 'Joe');
INSERT INTO vehicle VALUES(113, SYSDATE, 'PU-000-PU', 'FORD', null, null, null);
INSERT INTO Hire (Hire_ID, Hire_Date, Drop_In_Day, Customer_ID, Vehicle_ID)
VALUES (10, '8/3/2017', '8/7/2017', 100, 112);
Edit
In your case the INSERT should look as follow if you want to keep the fk1_* naming.
INSERT INTO Hire
(Hire_ID, Hire_Date, Drop_In_Day, fk1_Customer_ID, fk2_Vehicle_ID)
VALUES (12, '8/3/2017', '8/7/2017', 101, 112);
The dates should work if the format fit your NLS_DATE_FORMAT but it is better to use the TO_DATE function.
The table DDL and INSERT statement posted by you are:
-- Create a Database table to represent the "Hire" entity.
CREATE TABLE Hire(
Hire_ID INTEGER NOT NULL,
Hire_Date DATE,
Drop_In_Day DATE,
fk1_Customer_ID INTEGER NOT NULL REFERENCES Customer (Customer_ID),
fk2_Vehicle_ID INTEGER NOT NULL REFERENCES Vehicle (Vehicle_ID) ,
-- Specify the PRIMARY KEY constraint for table "Hire".
-- This indicates which attribute(s) uniquely identify each row of data.
CONSTRAINT pk_Hire PRIMARY KEY (Hire_ID)
);
INSERT INTO Hire
(Hire_ID, Hire_Date, Drop_In_Day, Customer_ID, Vehicle_ID)
VALUES (10, '8/3/2017', '8/7/2017', 101, 112);
These are couple of observations:
The column name "Vehicle_ID" used in INSERT INTO Hire statement doesn't exist in the HIRE table.
Your HIRE table should have the column to create the foreign key constraint to reference the primary key.
CREATE TABLE Hire
(
Hire_ID INTEGER NOT NULL,
Hire_Date DATE,
Drop_In_Day DATE,
Customer_ID INTEGER NOT NULL,
Vehicle_ID INTEGER NOT NULL,
CONSTRAINT fk1_Customer_ID FOREIGN KEY (Customer_ID)
REFERENCES Customer (Customer_ID),
CONSTRAINT fk2_Vehicle_ID FOREIGN KEY (Vehicle_ID)
REFERENCES Vehicle (Vehicle_ID)
);
So, you have Vehicle_ID column in HIRE table as foreign key referencing to Vehicle_ID column in VEHICLE table which is the primary key of that table. Same applies to Customer_ID.
'8/3/2017' is NOT a DATE, it is a STRING. Always use TO_DATE or ANSI DATE literal DATE 'YYYY-MM-DD' to explicitly convert a string in to date.
For example:
TO_DATE('8/3/2017', 'DD/MM/YYYY')
DATE '2017-03-08'

How to organize tables to stare statistic of two entities?

For now I have only two tables
CREATE TABLE IF NOT EXISTS company (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250) NOT NULL
);
CREATE TABLE IF NOT EXISTS employee (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250),
company_id INT,
FOREIGN KEY (company_id) REFERENCES Company (id)
);
I need to create one or two tables to store employees and companies statistic. For employee statistic I need to remember all previous companies of this employee and of cause hire dates and resign dates. For company statistic I need to remember all resigned employees. What is the best way to organize DB structure in my case?
Since you have many-to-many relationship, you need an aggregate table company_employee that will have combined primary key, so you need:
CREATE TABLE IF NOT EXISTS company (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250) NOT NULL
);
CREATE TABLE IF NOT EXISTS employee (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250)
);
CREATE TABLE IF NOT EXISTS company_employee (
company_id INT NOT NULL,
employee_id INT NOT NULL,
hire_date DATE,
resign_date DATE,
FOREIGN KEY (company_id) REFERENCES Company (id),
FOREIGN KEY (employee_id) REFERENCES Employee (id)
);
So, if you want anything from aggregate table, just use JOIN on key of appropriate table.

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.

Fact table not populating with data

I'm trying to create and populate three dimensions and a fact tables with data. The dimensions work just fine but i'm unable to get any data into my fact table. If anyone will be so kind to point out what i'm doing wrong - i will be grateful.
Thank you all very much.
create table Customer
(
CUID integer identity(1,1) primary key,
Name varchar (25)
)
insert into Customer select distinct customer from [Data]
create table Agent
(
AID integer identity(1,1) primary key,
Agent varchar (25)
)
insert into Agent select distinct Seller from [Data]
create table Time
(
TID integer identity(1,1) primary key,
Week varchar (25),
Month varchar (25),
Year int
)
insert into Time
(Week,Month,Year)
select distinct Day,Month,Year from [Data]
Create Table Fact
(
CUID integer,
AID integer,
TID integer,
Sale money,
constraint pk_Fact primary key (CUID, AID, TID),
constraint fk1_Fact foreign key (CUID)
references Customer (CUID),
constraint fk2_Fact foreign key (AID)
references Agent (AID),
constraint fk3_Fact foreign key (TID)
references Time (TID),
)
insert into Fact
(CUID, AID, TID, Sale)
SELECT CUID, AID, TID, Sale
FROM Customer,
Agent,
Time,
[Data]
You need to process the cubes. Open it in a Visual Studio 2008 and process it. After that the data will be visible. Did you see the Dimension's mapping with the measures are correct?