Trying to make a database that allows for a course to have several sections, and a section to have several events/periods as to when they meet. Everything is linked properly, however I am having a problem with a PostgreSQL error which I realize is telling me that I need UNIQUE attributes in the "Sections" and "ClassEvent" Tables, but I can't have them be UNIQUE because it is information that should/can be repeated.
DROP TABLE IF EXISTS Stats;
DROP TABLE IF EXISTS ClassEvent;
DROP TABLE IF EXISTS Enrollment;
DROP TABLE IF EXISTS DegreeReq;
DROP TABLE IF EXISTS DegreeInstance;
DROP TABLE IF EXISTS Sections;
DROP TABLE IF EXISTS Students;
DROP TABLE IF EXISTS Degrees;
DROP TABLE IF EXISTS Professors;
DROP TABLE IF EXISTS People;
DROP TABLE IF EXISTS Courses;
-- HOLDS A SPECIFIC COURSE WITHOUT THE INSTANCES OF THE CLASS --
CREATE TABLE Courses (
courseID SERIAL UNIQUE NOT NULL,
department VARCHAR(4) NOT NULL,
courseNumber VARCHAR(5) 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 SERIAL UNIQUE NOT NULL,
status TEXT NOT NULL,
CHECK(status = 'Full-Time' OR status = 'Part-time'),
PRIMARY KEY(professorID)
);
-- HOLDS THE SPECIFIC INSTANCES OF THE CLASS DEPENDING ON THE YEAR AND TERM --
CREATE TABLE Sections (
crn INT UNIQUE NOT NULL,
courseID SERIAL REFERENCES Courses(courseID) NOT NULL,
year INT NOT NULL,
term TEXT NOT NULL,
sectionNumber INT NOT NULL,
startDate DATE NOT NULL,
endDate DATE NOT NULL,
professorID INT REFERENCES Professors(professorID) UNIQUE NOT NULL,
PRIMARY KEY(crn, 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 (
crn INT REFERENCES Sections(crn) NOT NULL,
year INT REFERENCES Sections(year) NOT NULL,
term TEXT REFERENCES Sections(term) NOT NULL,
professorID INT REFERENCES Professors(professorID) 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 = NULL),
PRIMARY KEY(crn, year, term)
);
-- 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 REFERENCES Students(studentID) UNIQUE NOT NULL,
crn INT REFERENCES Sections(crn) NOT NULL,
grade TEXT NOT NULL,
PRIMARY KEY(studentID, crn)
);
-- 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) UNIQUE 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 Stats (
professorID INT REFERENCES Professors(professorID) UNIQUE NOT NULL,
dateSubmitted TIMESTAMP UNIQUE NOT NULL,
rating FLOAT NOT NULL,
helpfulness FLOAT NOT NULL,
clarity FLOAT NOT NULL,
easiness FLOAT NOT NULL,
PRIMARY KEY(professorID, dateSubmitted)
);
INSERT INTO Courses(department, courseNumber, courseName, credits)
VALUES
('CMPT', '120L', 'Intro to Programming', 4),
('CMPT', '220L', 'Software Development I', 4),
('CMPT', '221L', 'Software Development II', 4),
('CMPT', '230L', 'Software Systems + Analysis', 4),
('CMPT', '306N', 'Data Communications', 4),
('CMPT', '308L', 'Database Management', 4),
('CMPT', '307N', 'Internetworking', 4),
('CMPT', '330L', 'System Design', 4),
('CMPT', '422L', 'Computer Organization and Architecture', 4),
('CMPT', '435L', 'Algorithm Analysis and Design', 4),
('CMPT', '424L', 'Operating Systems', 4),
('CMPT', '432L', 'Design of Compilers', 4),
('CMPT', '331L', 'Theory of Programming Languages', 4),
('CMPT', '440L', 'Formal Languages and Computability', 4),
('CMPT', '333L', 'Language Study', 4),
('CMPT', '475L', 'CS Project I', 4),
('CMPT', '476L', 'CS Project II', 4),
('BUS', '100N', 'Intro to Business & Management', 4),
('MATH', '130L', 'Intro to Statistics I', 3),
('MATH', '241L', 'Calculus I', 4),
('MATH', '242L', 'Calculus II', 4),
('FYS', '101L', 'First Year Seminar', 4),
('ENG', '120L', 'Writing for College', 3),
('PHIL', '101L', 'Philosophical Perspectives', 3),
('MUS', '120L', 'Theory of Music I', 3),
('ECON', '103L', 'Principles of Microeconomics', 3),
('ECON', '104L', 'Principles of Macroeconomics', 3),
('MATH', '343L', 'Calculus III', 4),
('MATH', '310L', 'Intro to Mathematics Reasoning', 3),
('CMPT', '416N', 'Intro to Cybersecurity', 4),
('CMPT', '446N', 'Computer Graphics', 4),
('CMPT', '404L', 'Artificial Intelligence', 4),
('CMPT', '305L', 'Technology, Ethics and Society', 3),
('CMPT', '192N', 'Competitive Programming', 1);
INSERT INTO People(fname, lname)
VALUES
('Marcos', 'Barbieri'),
('James', 'Crowley'),
('Kaylee', 'Pope'),
('Pablo', 'Rivas'),
('Matthew', 'Johnson'),
('Anne', 'Matheus'),
('Joe', 'Smith'),
('Mike', 'Emmet'),
('Michael', 'Jordan'),
('Alan', 'Labouseur');
INSERT INTO Professors(professorID, status)
VALUES
(4, 'Full-Time'),
(5, 'Full-Time'),
(6, 'Full-Time'),
(7, 'Full-Time'),
(10, 'Full-Time');
INSERT INTO Sections(crn, courseID, year, term, sectionNumber, startDate, endDate, professorID)
VALUES
(11111, 1, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 4),
(11112, 1, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 4),
(11113, 1, 2016, 'Fall', 113, '2016-08-29', '2016-12-15', 4),
(11121, 2, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 5),
(11122, 2, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 5),
(11123, 2, 2016, 'Fall', 113, '2016-08-29', '2016-12-15', 5),
(11211, 3, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 6),
(11212, 3, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 6),
(11213, 3, 2016, 'Fall', 113, '2016-08-29', '2016-12-15', 6),
(11214, 4, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 7),
(11215, 4, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 7),
(11216, 5, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 10),
(11217, 6, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 10),
(11118, 6, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 4),
(11119, 6, 2016, 'Fall', 113, '2016-08-29', '2016-12-15', 5),
(11120, 6, 2016, 'Fall', 114, '2016-08-29', '2016-12-15', 4),
(11200, 7, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 5),
(11201, 7, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 5),
(11202, 8, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 10),
(11203, 9, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 10),
(11204, 10, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 6),
(11205, 10, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 6),
(11206, 10, 2016, 'Fall', 113, '2016-08-29', '2016-12-15', 6),
(11207, 10, 2016, 'Fall', 114, '2016-08-29', '2016-12-15', 6),
(11208, 11, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 4),
(11209, 11, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 4),
(11222, 12, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 4),
(11333, 12, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 5),
(11445, 12, 2016, 'Fall', 113, '2016-08-29', '2016-12-15', 7),
(11111, 12, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 4),
(11678, 13, 2016, 'Fall', 111, '2016-08-29', '2016-12-15', 10),
(11679, 13, 2016, 'Fall', 112, '2016-08-29', '2016-12-15', 4);
SELECT * FROM Sections;
I try to do this and I get the following error:
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 do not need to have year and term as foreign keys in the class events table. This information is redundant as it can be looked up in sections table via the crn. I suggest changing your create statement for ClassEvents as follows:
CREATE TABLE ClassEvent (
crn INT REFERENCES Sections(crn) NOT NULL,
professorID INT REFERENCES Professors(professorID) NOT NULL,
day TEXT NOT NULL,
startTime TIME NOT NULL,
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 = NULL),
PRIMARY KEY(crn, day, startTime,professorID)
);
I have changed primary key to be a combination of course,date/time and professor - as a professor cannot be teaching more than course on any given point in time.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Like the title says, SQL query which outputs the number of athletes that voted for someone in the same athletePosition as himself.
I have 4 tables in my database right now, they consist of:
CREATE TABLE award(
awardId INT IDENTITY(1, 1),
awardName VARCHAR(30) NOT NULL,
awardSponsor VARCHAR(100),
CONSTRAINT pk_award_awardId PRIMARY KEY (awardId)
);
CREATE TABLE winner(
winnerId INT IDENTITY(1, 1),
winnerYear INT NOT NULL,
athleteId INT NOT NULL,
awardId INT NOT NULL,
CONSTRAINT pk_winner_winnerId PRIMARY KEY (winnerId),
CONSTRAINT fk_winner_athlete FOREIGN KEY (athleteId) REFERENCES athlete (athleteId),
CONSTRAINT fk_winner_award FOREIGN KEY (awardId) REFERENCES award (awardId)
);
CREATE TABLE athlete(
athleteId INT IDENTITY(1, 1),
athleteFirstName VARCHAR(20) NOT NULL,
athleteLastName VARCHAR(30) NOT NULL,
athleteDateOfBirth DATE,
athleteHeight SMALLINT,
athleteWeight TINYINT,
athletePosition CHAR(2) NOT NULL,
athleteBattingAvg DECIMAL(4, 3) DEFAULT 0.000,
athleteNationality VARCHAR(30),
teamId INT NOT NULL,
votesForId INT,
CONSTRAINT pk_athlete_athleteId PRIMARY KEY (athleteId),
CONSTRAINT fk_athlete_team FOREIGN KEY(teamId) REFERENCES team (teamId),
);
CREATE TABLE team(
teamId INT IDENTITY(1, 1),
teamName VARCHAR(50) NOT NULL,
teamCity VARCHAR(20) NOT NULL,
teamState CHAR(2),
teamCountry VARCHAR(6),
teamManager VARCHAR(50),
teamLeague CHAR(2) NOT NULL,
teamStadium VARCHAR(30),
CONSTRAINT pk_team_teamId PRIMARY KEY (teamId)
);
Here is some sample data for ATHLETE Table.
INSERT INTO athlete
VALUES
('Vladimir', 'Guererro Jr.', '1999-03-16', 188, 113, '3B', 0.272, 'Canada', 1),
('Bo', 'Bichette', '1998-03-05', 183, 83, 'SS', 0.311, 'USA', 1),
('Cavan', 'Biggio', '1995-04-11', 188, 90, '2B', 0.234, 'USA', 1),
('Travis', 'Shaw', '1990-04-16', 193, 104, '1B', 0.157, 'USA', 1),
('Danny', 'Jansen', '1995-04-15', 188, 104, 'C', 0.207, 'USA', 1),
('Randal', 'Grichuk', '1991-08-13', 188, 96, 'OF', 0.232, 'USA', 1),
('Teoscar', 'Hernandez', '1992-10-15', 188, 92, 'OF', 0.230, 'Dominican Republic', 1),
('Tim', 'Anderson', '1993-06-23', 185, 83, 'SS', 0.335, 'USA', 2),
('Jose', 'Abreu', '1987-01-29', 190, 115, '1B', 0.284, 'Cuba', 2),
('Kevin', 'Kiermaier', '1990-04-22', 185, 95, 'OF', 0.228, 'USA', 3),
('Nolan', 'Arenado', '1991-04-16', 188, 97, '3B', 0.315, 'USA', 4),
('Mike', 'Trout', '1991-08-07', 188, 106, 'OF', 0.291, 'USA', 5),
('Aaron', 'Judge', '1992-04-26', 201, 127, 'OF', 0.272, 'USA', 6),
('Giancarlo', 'Stanton', '1989-11-08', 198, 111, 'OF', 0.288, 'USA', 6),
('Joey', 'Votto', '1983-09-10', 188, 99, '1B', 0.261, 'Canada', 8);
(3B, SS, 2B, 1B, etc. being the positions)
Here is some sample data for the Team table.
INSERT INTO team
VALUES
('Toronto Blue Jays', 'Toronto', 'ON', 'Canada', 'Charlie Montoyo', 'AL', 'Rogers Centre'),
('Chicago White Sox', 'Chicago', 'IL', 'USA', 'Rick Renteria', 'AL', 'Guaranteed Rate Field'),
('Tampa Bay Rays', 'Tampa Bay', 'FL', 'USA', 'Kevin Cash', 'AL', 'Tropicana Field'),
('Colorado Rockies', 'Denver', 'CO', 'USA', 'Bud Black', 'NL', 'Coors Field'),
('Los Angeles Angels', 'Anaheim', 'CA', 'USA', 'Joe Maddon', 'AL', 'Angel Stadium of Anaheim'),
('New York Yankees', 'New York', 'NY', 'USA', 'Aaron Boone', 'AL', 'Yankee Stadium'),
('Pittsburgh Pirates', 'Pittsburgh', 'PA', 'USA', 'Derek Shelton', 'NL', 'PNC Park'),
('Cincinnati Reds', 'Cincinnati', 'OH', 'USA', 'David Bell', 'NL', 'Great American Ball Park');
My expected query result should be 2.
So that means that 2 athletes voted for someone who plays the same position as themselves.
I was thinking the query's top half should be something like:
SELECT COUNT(v.athleteId)
FROM athlete AS v
JOIN athlete AS a ON v.athleteID = a.votesforId
I am not sure what the WHERE would be.
Any help would be much appreciated.
You could accomplish this using an inner join with the same table. In the proposed solution, I aliased one voter to represent those who casted votes and the other nominated for those who votes were cast for. The inner join was done on the athletePosition on both table aliases and voter.votesForId= nominated.athleteId before finding the total records.
It was difficult to replicate with the shared schema and data however, I believe the StackOverflow community has shared some valuable insights on how to proceed with these in the comments.
I have shared a db-fiddle that replicates your problem and the proposed solution.
Setup
CREATE TABLE award(
awardId INT IDENTITY(1, 1),
awardName VARCHAR(30) NOT NULL,
awardSponsor VARCHAR(100),
CONSTRAINT pk_award_awardId PRIMARY KEY (awardId)
);
CREATE TABLE team(
teamId INT IDENTITY(1, 1),
teamName VARCHAR(50) NOT NULL,
teamCity VARCHAR(20) NOT NULL,
teamState CHAR(2),
teamCountry VARCHAR(6),
teamManager VARCHAR(50),
teamLeague CHAR(2) NOT NULL,
teamStadium VARCHAR(30),
CONSTRAINT pk_team_teamId PRIMARY KEY (teamId)
);
CREATE TABLE athlete(
athleteId INT IDENTITY(1, 1),
athleteFirstName VARCHAR(20) NOT NULL,
athleteLastName VARCHAR(30) NOT NULL,
athleteDateOfBirth DATE,
athleteHeight SMALLINT,
athleteWeight TINYINT,
athletePosition CHAR(2) NOT NULL,
athleteBattingAvg DECIMAL(4, 3) DEFAULT 0.000,
athleteNationality VARCHAR(30),
votesForId INT,
teamId INT NOT NULL,
CONSTRAINT pk_athlete_athleteId PRIMARY KEY (athleteId),
CONSTRAINT fk_athlete_team FOREIGN KEY(teamId) REFERENCES team (teamId)
);
CREATE TABLE winner(
winnerId INT IDENTITY(1, 1),
winnerYear INT NOT NULL,
athleteId INT NOT NULL,
awardId INT NOT NULL,
CONSTRAINT pk_winner_winnerId PRIMARY KEY (winnerId),
CONSTRAINT fk_winner_athlete FOREIGN KEY (athleteId) REFERENCES athlete (athleteId),
CONSTRAINT fk_winner_award FOREIGN KEY (awardId) REFERENCES award (awardId)
);
GO
INSERT INTO team
VALUES
('Toronto Blue Jays', 'Toronto', 'ON', 'Canada', 'Charlie Montoyo', 'AL', 'Rogers Centre'),
('Chicago White Sox', 'Chicago', 'IL', 'USA', 'Rick Renteria', 'AL', 'Guaranteed Rate Field'),
('Tampa Bay Rays', 'Tampa Bay', 'FL', 'USA', 'Kevin Cash', 'AL', 'Tropicana Field'),
('Colorado Rockies', 'Denver', 'CO', 'USA', 'Bud Black', 'NL', 'Coors Field'),
('Los Angeles Angels', 'Anaheim', 'CA', 'USA', 'Joe Maddon', 'AL', 'Angel Stadium of Anaheim'),
('New York Yankees', 'New York', 'NY', 'USA', 'Aaron Boone', 'AL', 'Yankee Stadium'),
('Pittsburgh Pirates', 'Pittsburgh', 'PA', 'USA', 'Derek Shelton', 'NL', 'PNC Park'),
('Cincinnati Reds', 'Cincinnati', 'OH', 'USA', 'David Bell', 'NL', 'Great American Ball Park');
INSERT INTO athlete (
athleteFirstName ,
athleteLastName ,
athleteDateOfBirth,
athleteHeight,
athleteWeight,
athletePosition,
athleteBattingAvg,
athleteNationality,
teamId,
votesForId
)
VALUES
('Vladimir', 'Guererro Jr.', '1999-03-16', 188, 113, '3B', 0.272, 'Canada', 1,2),
('Bo', 'Bichette', '1998-03-05', 183, 83, 'SS', 0.311, 'USA', 1,1),
('Cavan', 'Biggio', '1995-04-11', 188, 90, '2B', 0.234, 'USA', 1,3),
('Travis', 'Shaw', '1990-04-16', 193, 104, '1B', 0.157, 'USA', 1,1),
('Danny', 'Jansen', '1995-04-15', 188, 104, 'C', 0.207, 'USA', 1,2),
('Randal', 'Grichuk', '1991-08-13', 188, 96, 'OF', 0.232, 'USA', 1,3),
('Teoscar', 'Hernandez', '1992-10-15', 188, 92, 'OF', 0.230, 'Dominican Republic', 1,2),
('Tim', 'Anderson', '1993-06-23', 185, 83, 'SS', 0.335, 'USA', 2,1),
('Jose', 'Abreu', '1987-01-29', 190, 115, '1B', 0.284, 'Cuba', 2,1),
('Kevin', 'Kiermaier', '1990-04-22', 185, 95, 'OF', 0.228, 'USA', 3,1),
('Nolan', 'Arenado', '1991-04-16', 188, 97, '3B', 0.315, 'USA', 4,1),
('Mike', 'Trout', '1991-08-07', 188, 106, 'OF', 0.291, 'USA', 5,1),
('Aaron', 'Judge', '1992-04-26', 201, 127, 'OF', 0.272, 'USA', 6,1),
('Giancarlo', 'Stanton', '1989-11-08', 198, 111, 'OF', 0.288, 'USA', 6,1),
('Joey', 'Votto', '1983-09-10', 188, 99, '1B', 0.261, 'Canada', 8,1);
Proposed Solution
SELECT
SUM(1) as num_votes
FROM
athlete voter
INNER JOIN
athlete nominated ON voter.votesForId = nominated.athleteId AND
voter.athletePosition = nominated.athletePosition
Returns:
num_votes
2
db<>fiddle here
I think you just want to test whether each player voted for someone else who plays in the same position as them, and them sum it. But do you want count someone who votes for themselves? As in your first player?
with cte as (
select case when exists (select 1 from athlete A1 where A1.athleteId = A.votesForId and A1.athletePosition = A.athletePosition) then 1 else 0 end CountThisPlayer
from athlete A
)
select sum(CountThisPlayer) NumberPlayedVotedForSamePosition
from cte;
Note: If your table is called athlete, I highly recommend not prefixing all your column names with the table name, that just leads to a lot of unnecessary typing e.g. just use firstName not athleteFirstName.
Note: Its best practice to list the columns you are inserting into as part of your insert statement.
I have these tables below along with the definition. I want to find top 10 products sold in a year after finding counts and without using aggregation and in an optimized way. I want to know if aggregation is still needed or I can accomplish it without using aggregation. Below is the query. Can anyone suggest a better approach.
CREATE TABLE Customer (
id int not null,
first_name VARCHAR(30),
last_name VARCHAR(30),
Address VARCHAR(60),
State VARCHAR(30),
Phone text,
PRIMARY KEY(id)
);
CREATE TABLE Product (
ProductId int not null,
name VARCHAR(30),
unitprice int,
BrandID int,
Brandname varchar(30),
color VARCHAR(30),
PRIMARY KEY(ProductId)
);
Create Table Sales (
SalesId int not null,
Date date,
Customerid int,
Productid int,
Purchaseamount int,
PRIMARY KEY(SalesId),
FOREIGN KEY (Productid) REFERENCES Product(ProductId),
FOREIGN KEY (Customerid) REFERENCES Customer(id)
)
Sample Data:
insert into
Customer(id, first_name, last_name, address, state, phone)
values
(1111, 'andy', 'johnson', '123 Maryland Heights', 'MO', 3211451234),
(1112, 'john', 'smith', '237 Jackson Heights', 'TX', 3671456534),
(1113, 'sandy', 'fleming', '878 Jersey Heights', 'NJ', 2121456534),
(1114, 'tony', 'anderson', '789 Harrison Heights', 'CA', 6101456534)
insert into
Product(ProductId, name, unitprice, BrandId, Brandname)
values
(1, 'watch',200, 100, 'apple'),
(2, 'ipad', 429, 100, 'apple'),
(3, 'iphone', 799, 100, 'apple'),
(4, 'gear', 300, 110, 'samsung'),
(5, 'phone',1000, 110, 'samsung'),
(6, 'tab', 250, 110, 'samsung'),
(7, 'laptop', 1300, 120, 'hp'),
(8, 'mouse', 10, 120, 'hp'),
(9, 'monitor', 400, 130, 'dell'),
(10, 'keyboard', 40, 130, 'dell'),
(11, 'dvddrive', 100, 130, 'dell'),
(12, 'dvddrive', 90, 150, 'lg')
insert into
Sales(SalesId, Date, CustomerID, ProductID, Purchaseamount)
values (30, '01-10-2019', 1111, 1, 200),
(31, '02-10-2019', 1111, 3, 799),
(32, '03-10-2019', 1111, 2, 429),
(33, '04-10-2019', 1111, 4, 300),
(34, '05-10-2019', 1111, 5, 1000),
(35, '06-10-2019', 1112, 7, 1300),
(36, '07-10-2019', 1112, 9, 400),
(37, '08-10-2019', 1113, 5, 2000),
(38, '09-10-2019', 1113, 4, 300),
(39, '10-10-2019', 1113, 3, 799),
(40, '11-10-2019', 1113, 2, 858),
(41, '01-10-2020', 1111, 1, 400),
(42, '02-10-2020', 1111, 2, 429),
(43, '03-10-2020', 1112, 7, 1300),
(44, '04-10-2020', 1113, 7, 2600),
(45, '05-10-2020', 1114, 7, 1300),
(46, '06-10-2020', 1114, 7, 1300),
(47, '07-10-2020', 1114, 9, 800)
Tried this:
SELECT PCY.Name, PCY.Year, PCY.SEQNUM
FROM (SELECT P.Name AS Name, Extract('Year' from S.Date) AS YEAR, COUNT(P.Productid) AS CNT,
RANK() OVER (PARTITION BY Extract('Year' from S.Date) ORDER BY COUNT(P.Productid) DESC) AS RANK
FROM Sales S inner JOIN
Product P
ON S.Productid = P.Productid
) PCY
WHERE PCY.RANK <= 10;
I am seeing this error:
ERROR: column "p.name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 2: FROM (SELECT P.Name AS Name, Extract('Year' from S.Date) AS ...
^
SQL state: 42803
Character: 52
I don't understand why you don't want to use an aggregate function when you have to aggregate over your data. This query works fine, without any issues on the GROUP BY:
WITH stats AS (
SELECT EXTRACT
( YEAR FROM DATE ) AS y,
P.productid,
P.NAME,
COUNT ( * ) numbers_sold,
RANK ( ) OVER ( PARTITION BY EXTRACT ( YEAR FROM DATE ) ORDER BY COUNT ( * ) DESC ) r
FROM
product
P JOIN sales S ON S.Productid = P.Productid
GROUP BY
1,2
)
SELECT y
, name
, numbers_sold
FROM stats
WHERE r <= 10;
This works because the productid is the primary key that has a functional dependency to the product name.
By the way, tested on version 12, but it should work on older and newer versions as well.
I made this code for SQL Server to select how many times the rider "AsdoVolante" came first in the first semester of 2017. But it does not work. What could be wrong?
SELECT P.Data, Nm.Nome, epp.PosicaoFinal
FROM Prova P, Piloto Nm, EquipaParticipaProva epp
WHERE epp.PosicaoFinal = (SELECT PosicaoFinal FROM EquipaParticipaProva where PosicaoFinal = 1)
HAVING Nm.Nome ='AsdoVolante' AND P.Data BETWEEN '2017-01-01' AND '2017-06-30';
Tables created in SQL Server for the code:
CREATE TABLE Carro(
IdCarro INT NOT NULL,
Marca VARCHAR(20) NOT NULL,
Modelo VARCHAR(50),
PRIMARY KEY (IdCarro));
CREATE TABLE Piloto(
IdPiloto INT NOT NULL,
Nome VARCHAR(20) NOT NULL,
Morada VARCHAR(50),
Telefone INT,
PRIMARY KEY (IdPiloto));
CREATE TABLE Equipa(
IdEquipa INT NOT NULL,
Nome VARCHAR(20),
Morada VARCHAR(50),
Telefone INT,
PRIMARY KEY (IdEquipa));
CREATE TABLE Patrocinador(
IdPatrocinador INT NOT NULL,
Nome VARCHAR(20)NOT NULL,
Morada VARCHAR(50),
PRIMARY KEY (IdPatrocinador));
CREATE TABLE Prova(
IdProva INT NOT NULL,
Nome VARCHAR(20) NOT NULL,
Local VARCHAR(50) NOT NULL,
Data DATE NOT NULL,
NrVoltas INT NOT NULL,
MelhorTempo TIME,
PRIMARY KEY (IdProva));
CREATE TABLE EquipaParticipaProva(
IdInscricao INT NOT NULL,
IdEquipa INT NOT NULL,
IdCarro INT NOT NULL,
IdPiloto INT NOT NULL,
IdProva INT NOT NULL,
PosicaoFinal INT,
TempoFinal TIME,
FOREIGN KEY (IdProva) REFERENCES Prova(IdProva),
FOREIGN KEY (IdCarro) REFERENCES Carro(IdCarro),
FOREIGN KEY (IdPiloto) REFERENCES Piloto(IdPiloto),
FOREIGN KEY (IdEquipa) REFERENCES Equipa(IdEquipa),
PRIMARY KEY (IdInscricao));
CREATE TABLE Voltas(
IdVolta INT NOT NULL,
IdInscricao INT NOT NULL,
PosicaoRelativa INT NOT NULL,
TempoVolta TIME,
FOREIGN KEY (IdInscricao) REFERENCES EquipaParticipaProva(IdInscricao),
PRIMARY KEY (IdVolta, IdInscricao));
CREATE TABLE PatrocinadorOficial(
IdPatrocinador INT NOT NULL,
IdProva INT NOT NULL,
Valor MONEY NOT NULL,
FOREIGN KEY (IdProva) REFERENCES Prova(IdProva),
PRIMARY KEY (IdPatrocinador, IdProva));
CREATE TABLE PatrocinadorNaoOficial(
IdPatrocinador INT NOT NULL,
IdProva INT NOT NULL,
Valor MONEY NOT NULL,
FOREIGN KEY (IdProva) REFERENCES Prova(IdProva),
PRIMARY KEY (IdPatrocinador, IdProva));
CREATE TABLE Mecanico(
IdMecanico INT NOT NULL,
Nome VARCHAR(20),
Morada VARCHAR(50),
Telefone INT,
PRIMARY KEY (IdMecanico));
CREATE TABLE Afinacao(
IdAfinacao INT NOT NULL,
IdMecanico INT NOT NULL,
IdEquipa INT NOT NULL,
TipoAfinacao VARCHAR(20) NOT NULL,
TempoDespendido TIME,
Data DATE NOT NULL,
FOREIGN KEY (IdEquipa) REFERENCES Equipa(IdEquipa),
FOREIGN KEY (IdMecanico) REFERENCES Mecanico(IdMecanico),
PRIMARY KEY (IdAfinacao));
Inserts created in SQL Server:
INSERT INTO Carro
VALUES (1, 'Nissan', 'Skyline');
INSERT INTO Carro
VALUES (2, 'Subaru', 'Impreza');
INSERT INTO Carro
VALUES (3, 'Mitsubishi', 'Evolution');
INSERT INTO Piloto
VALUES (111, 'Piloto 1', 'Castelo Branco', 111111111);
INSERT INTO Piloto
VALUES (112, 'Piloto 2', 'Castelo Branco', 111111112);
INSERT INTO Piloto
VALUES (113, 'JaGanhou', 'Lisboa', 111111113);
INSERT INTO Piloto
VALUES (114, 'AsdoVolante', 'Lisboa', 111111114);
INSERT INTO Piloto
VALUES (115, 'AsdoPedal', 'Beja', 111111115);
INSERT INTO Piloto
VALUES (116, 'Pelo Nome', 'Santarém', 111111116);
INSERT INTO Equipa
VALUES (001, 'OsAtolados', 'Castelo Branco', 272722123);
INSERT INTO Equipa
VALUES (002, 'Sparco', 'Lisboa', 212312432);
INSERT INTO Equipa
VALUES (003, 'ESTeam', 'Castelo Branco', 272343573);
INSERT INTO Prova
VALUES (010, 'RallycrossCB', 'Castelo Branco', '2017-02-02', 4, '00:04:20');
INSERT INTO Prova
VALUES (11, 'RallyLels', 'Bells', '2017-03-04', 10, '00:10:00');
INSERT INTO Prova
VALUES (12, 'Rally Portugal', 'Fafe', '2017-05-15', 2, '00:15:00');
INSERT INTO Prova
VALUES (13, 'Rally CB', 'Castelo Branco', '2017-01-01', 2, '00:15:00');
INSERT INTO Prova
VALUES (14, 'Rally Norte', 'Porto', '2017-02-02', 2, '00:30:00');
INSERT INTO EquipaParticipaProva
VALUES (441, 002, 3, 113, 010, 1, '00:04:00');
INSERT INTO EquipaParticipaProva
VALUES (442, 1, 2, 111, 11, 1, '00:10:00');
INSERT INTO EquipaParticipaProva
VALUES (443, 3, 1, 112, 10, 1,'00:05:00' );
INSERT INTO EquipaParticipaProva
VALUES (444, 3, 1, 114, 12, 1,'00:15:00' );
INSERT INTO EquipaParticipaProva
VALUES (445, 3, 1, 114, 13, 1,'00:15:00' );
INSERT INTO EquipaParticipaProva
VALUES (446, 3, 2, 114, 14, 5,'01:00:00' );
INSERT INTO Voltas
VALUES (1, 443, 1, '00:01:15');
INSERT INTO Voltas
VALUES (2, 443, 1, '00:01:15');
INSERT INTO Voltas
VALUES (3, 443, 3, '00:01:15');
INSERT INTO Voltas
VALUES (1, 444, 1, '00:07:30');
INSERT INTO Voltas
VALUES (2, 444, 1, '00:07:30');
INSERT INTO Voltas
VALUES (1, 445, 1, '00:07:30');
INSERT INTO Voltas
VALUES (2, 445, 1, '00:07:30');
INSERT INTO Voltas
VALUES (1, 446, 5, '00:30:00');
INSERT INTO Voltas
VALUES (2, 446, 5, '00:30:00');
INSERT INTO Voltas
VALUES (4, 443, 3, '00:01:15');
INSERT INTO Voltas
VALUES (1, 441, 1, '00:01:00' );
INSERT INTO Voltas
VALUES (2, 441, 1, '00:01:20');
INSERT INTO Voltas
VALUES (3, 441, 1, '00:01:00');
INSERT INTO Voltas
VALUES (4, 441, 1, '00:01:00');
INSERT INTO Voltas
VALUES (5, 441, 1, '00:01:00');
INSERT INTO Voltas
VALUES (6, 441, 1, '00:01:00');
INSERT INTO Voltas
VALUES (7, 441, 1, '00:01:00');
INSERT INTO Voltas
VALUES (8, 441, 1, '00:01:20');
INSERT INTO Voltas
VALUES (9, 441, 1 ,'00:00:30');
INSERT INTO Voltas
VALUES (10, 441, 1, '00:01:30');
INSERT INTO Voltas
VALUES (1, 441, 10, 2, '00:00:45');
INSERT INTO Voltas
VALUES (2, 441, 10, 2, '00:01:00');
INSERT INTO Voltas
VALUES (3, 441, 10, 2, '00:01:00');
INSERT INTO Voltas
VALUES (4, 441, 10, 2, '00:01:15');
INSERT INTO PATROCINADOR
VALUES(921, 'IPCB', 'Av da Talagueira');
INSERT INTO PATROCINADOR
VALUES(922, 'Bells Bar', 'Praceta Qualquer Coisa');
INSERT INTO PATROCINADOR
VALUES(923, 'MonsterEnergy', 'USA');
INSERT INTO PATROCINADOR
VALUES(924, 'Sical', 'Lisboa');
INSERT INTO PATROCINADOROFICIAL
VALUES(923, 010, 10000);
INSERT INTO PATROCINADOROFICIAL
VALUES(921, 11, 8000);
INSERT INTO PATROCINADORNAOOFICIAL
VALUES(920, 010, 5000);
INSERT INTO PATROCINADORNAOOFICIAL
VALUES(922, 11, 3000);
INSERT INTO PATROCINADORNAOOFICIAL
VALUES(924, 10, 6000);
INSERT INTO MECANICO
VALUES(333, 'Zacarias','Leiria',933628487);
INSERT INTO MECANICO
VALUES(334, 'Zé', 'Bragança', 963628487);
INSERT INTO MECANICO
VALUES(335, 'Luís', 'Lisboa', 913628487);
INSERT INTO AFINACAO
VALUES(20, 333, 001, 'Travões', '1:00:00', '2017-02-03');
INSERT INTO AFINACAO
VALUES(21, 334, 002, 'Luzes', '00:15:00', '2017-02-03');
INSERT INTO AFINACAO
VALUES(22, 335, 003, 'Travoes', '1:00:00', '2017-02-01');
try this
SELECT P.Data, Nm.Nome, epp.PosicaoFinal
FROM Prova P, Piloto Nm, EquipaParticipaProva epp
WHERE epp.PosicaoFinal **IN** (SELECT PosicaoFinal FROM EquipaParticipaProva where PosicaoFinal = 1)
HAVING Nm.Nome ='AsdoVolante' AND P.Data BETWEEN '2017-01-01' AND '2017-06-30';
It will work for you
I'm trying to create a calculated column in SQL. Basically I need to get a set of distinct dates and determine how many customers there are in the population on that particular date. The result should be something like:
Date______| Customers
2016-01-01 | 1
2016-01-01 | 2
2016-01-05 | 3
2016-02-09 | 4
etc.
I created a sample database & data (using MySQL as I don't have permission to create tables in our Oracle dbs) with the following script:
create database customer_example;
use customer_example;
create table customers (
customer_id int not null primary key,
customer_name varchar(255) not null,
term_date DATE);
create table employee (
employee_id int not null primary key,
employee_name varchar(255) not null);
create table cust_emp (
ce_id int not null AUTO_INCREMENT,
emp_id int not null,
cust_id int not null,
start_date date,
end_date date,
deleted_yn boolean,
primary key (emp_id, cust_id, ce_id),
foreign key (cust_id) references customers(customer_id),
foreign key (emp_id) references employee(employee_id));
insert into customers (customer_id, customer_name)
values (1, 'Bobby Tables'), (2, 'Grover Cleveland'), (3, 'Chester Arthur'), (4, 'Jan Bush'), (5, 'Emanuel Porter'), (6, 'Darren King'), (7, 'Casey Mcguire'), (8, 'Robin Simpson'), (9, 'Robin Tables'), (10, 'Mitchell Arnold');
insert into customers (customer_id, customer_name, term_date)
values (11, 'Terrell Graves', '2017-01-01'), (12, 'Richard Wagner', '2016-10-31'), (13, 'Glenn Saunders', '2016-11-19'), (14, 'Bruce Irvin', '2016-03-11'), (15, 'Glenn Perry','2016-06-06'), (16, 'Hazel Freeman', '2016-07-10'),
(17, 'Martin Freeman', '2016-02-11'), (18, 'Morgan Freeman', '2017-02-01'), (19, 'Dirk Drake', '2017-01-12'), (20, 'Fraud Fraud', '2016-12-31');
insert into employee (employee_id, employee_name)
values (1000, 'Cedrick French'), (1001, 'Jane Phillips'), (1002, 'Brian Green'), (1003, 'Shawn Brooks'), (1004, 'Clarence Thomas');
insert into cust_emp (emp_id, cust_id, start_date, end_date)
values (1000, 1, '2016-01-01', '2016-02-01'), (1000, 1, '2016-02-01', '2016-02-01'), (1000, 2,'2016-01-05', '2016-01-16'),(1000, 3,'2016-02-09', '2016-03-14'),(1000, 4,'2016-03-20', '2016-04-23'),
(1000, 5,'2016-01-01', '2016-01-16'),(1000, 6,'2016-01-01', '2016-01-16'),(1004, 7, '2016-01-14', '206-01-16'),
(1004, 8, '2016-01-13', '2016-01-16'),(1004, 9, '2016-01-05', '2016-01-16'), (1003, 12, '2016-04-21', '2016-11-30');
insert into cust_emp (emp_id, cust_id, start_date, deleted_yn)
values (1002, 11, '2016-04-10', TRUE),(1003, 10, '2016-01-16', FALSE), (1004, 12, '2016-04-20', TRUE), (1004, 12, '2016-04-19', FALSE), (1003, 13, '2016-06-06', TRUE), (1002, 14, '2016-06-10', TRUE),
(1004, 15, '2016-03-25', TRUE), (1004, 17, '2016-01-02', TRUE), (1004, 18, '2017-01-01', TRUE), (1004, 19, '2016-11-13', TRUE), (1004, 20, '2016-03-10', TRUE), (1004, 16, '2016-05-13', TRUE);
insert into cust_emp (emp_id, cust_id, start_date)
values (1002, 1, '2016-02-01'), (1004, 2, '2016-01-16'),(1003, 3, '2016-03-14'),(1002, 4, '2016-04-23'),(1004, 5, '2016-01-16'),(1002, 6, '2016-01-16'),(1004, 7, '2016-01-16'),
(1004, 8, '2016-01-16'),(1002, 9, '2016-01-16'), (1004, 10, '2016-01-16');
The following SQL works fine in MySQL but when I try it in Oracle, I get an 'invalid identifier' on 'dates':
select distinct(ce.start_date) as dates,
(select count(distinct(c.customer_id))
from customers c
inner join cust_emp ce on c.customer_id = ce.cust_id
where ce.start_date < dates
and (ce.end_date > dates or (ce.deleted_yn = false or ce.deleted_yn is null))
and (c.term_date > dates or c.term_date is null)
)
from cust_emp as ce;
It seems as though this is because the dates is too far in a subquery. I've tried a CTE as well, but that seems to have the same issue as it gave the same error. How can I re-write this so that I can assess how many customers were there for each date in Oracle?
Huh?
Isn't this what you want?
select ce.dates as dates, count(distinct c.customer_id)
from cust_emp ce join
customers c
on c.customer_id = ce.cust_id
where ce.start_date < ce.dates and
(ce.end_date > ce.dates or ce.deleted_yn = false or ce.deleted_yn is null) and
(c.term_date > ce.dates or c.term_date is null)
group by ce.dates
order by ce.dates;
I don't really understand the use of the subquery with select distinct. The logic you describe is more easily understood as a simple aggregation.
I'm not sure where dates comes from. It is not in your data model, but it is in your sample query.
Good day, need your help on my Vehicle Inspection Database. You can see below the structure, you can see it also in here http://sqlfiddle.com/#!3/4ab7e . What I need from this is to extract The Number of Vehicles With Atleast One (1) Defect or Violation Per PROJECT. In the schema below The Total for Project 4 = two (2) vehicles AND Project 9 = 1 vehicle.
Columns Needed are [Project_Name],[Vehicle_Type],[yy],[mm],[Total]
-- Vehicle Inspection Database --
-- Vehicle_Type Table
CREATE TABLE VehicleType
([VehicleTypeId] int,
[Type] varchar (36));
INSERT INTO VehicleType ([VehicleTypeId],[Type])
VALUES (1, 'Light Vehicle'),
(2, 'Tanker'),
(3, 'Goods');
-- Car Table
CREATE TABLE Vehicle
([VehicleID] varchar(36),
[PlateNo] varchar(36),
[VehicleTypeId] int,
[Project] int);
INSERT INTO Vehicle ([VehicleID], [PlateNo],[VehicleTypeId], [Project])
VALUES('A57D4151-BD49-4B44-AF10-000F1C298E05', '8112AG', 1, 4),
('C7095628-AE88-4DD0-A4FD-00363EAB767F', '60070 AD2', 2, 9),
('E714CCD7-E56C-46A8-89D5-003CA5BF6094', '68823 AD1', 3, 9);
-- Event Table
CREATE TABLE Event
([EventID] int,
[VehicleID] varchar(36),
[EventTime] smalldatetime,
[TicketStatus] varchar (10)) ;
INSERT INTO Event([EventID], [VehicleID], [EventTime], TicketStatus)
VALUES (1, 'A57D4151-BD49-4B44-AF10-000F1C298E05', '20130701', 'Open'),
(2, 'A57D4151-BD49-4B44-AF10-000F1C298E05', '20130702', 'Close'),
(3, 'A57D4151-BD49-4B44-AF10-000F1C298E05', '20130703', 'Close'),
(4, 'C7095628-AE88-4DD0-A4FD-00363EAB767F','20130705', 'Open'),
(5, 'C7095628-AE88-4DD0-A4FD-00363EAB767F','20130710', 'Open');
-- Event_Defects Table
CREATE TABLE EventDefects
([EventDefectsID] int,
[EventID] int,
[Status] varchar(15),
[DefectID] int) ;
INSERT INTO EventDefects ([EventDefectsID], [EventID], [Status], [DefectID])
VALUES
-- 1st Inspection for PlateNo. 8112AG
(1, 1, 'YES', 1),
(2, 1, 'NO', 2),
(3, 1, 'YES',3),
(4, 1, 'N/A', 4),
(5, 1, 'N/A', 5),
-- 2nd Inspection for PlateNo. 8112AG
(6, 2, 'NO', 1),
(7, 2, 'NO', 2),
(8, 2, 'NO', 3),
(9, 2, 'N/A', 4),
(10,2, 'N/A', 5),
-- 3rd Inspection for PlateNo. 8112AG
(11, 3, 'NO', 1),
(12, 3, 'NO', 2),
(13, 3, 'NO', 3),
(14, 3, 'NO', 4),
(15, 3, 'NO', 5),
-- 1st Inspection for PlateNo. 60070 AD2
(16, 3, 'NO', 1),
(17, 3, 'NO', 2),
(18, 3, 'NO', 3),
(19, 3, 'N/A', 4),
(20, 3, 'N/A', 5);
-- Defects Table
CREATE TABLE Defects
([DefectID] int,
[DefectsName] varchar (36),
[DefectClassID] int) ;
INSERT INTO Defects ([DefectID], [DefectsName], [DefectClassID])
VALUES (1, 'TYRE', 1),
(2, 'BRAKING SYSTEM', 1),
(3, 'MIRRORS AND WINDSCREEN', 2),
(4, 'OVER SPEEDING', 3),
(5, 'NOT WEARING SEATBELTS', 3);
-- Defect_Class Table
CREATE TABLE DefectClass
([Description] varchar (15),
[DefectClassID] int) ;
INSERT INTO DefectClass ([DefectClassID], [Description])
VALUES (1, 'CATEGORY A'),
(2, 'CATEGORY B'),
(3, 'CATEGORY C');
Do all the joins as inner joins... and it'll eliminate records that are empty.
Can you check if this works for you?
SELECT Vehicle.VehicleID from Vehicle
INNER JOIN Event ON Vehicle.VehicleID = Event.VehicleID
INNER JOIN EventDefects ON EventDefects.EventID = Event.EventID
INNER JOIN Defects ON EventDefects.DefectID = Defects.DefectID
GROUP BY Vehicle.VehicleID;