I have a problem with the grouping for this query - sql

I have a problem grouping a 4 join table.
Due to new government regulations, every private service vehicle must be periodically serviced and have proper training, RideWiki is required to report to the government with proof that each driver has the required documents to be eligible to be a private service driver.
List the drivers that have serviced their car within the last two months (After 16/4/2019)
and have had done their basic driver training.
Carservice>>Driver<
select Dname
from driver,carservice,dsession,training;
where driver.dnric = carservice.dnric
and driver.dnric = dsession.dnric
and dsession.tid = training.tid
where sysdate-servicedate < 60
group by dnric,tid,dname;
CREATE TABLE DRIVER
(
DNRIC CHAR(12) PRIMARY KEY,
DGrade CHAR(1),
DLicense NUMBER(8),
DStart DATE,
DIPlan CHAR(1),
DName VARCHAR(20),
DDOB DATE,
DGENDER CHAR(1),
DMOBILE NUMBER(11)
);
CREATE TABLE CARSERVICE
(
DCarID NUMBER(6) PRIMARY KEY,
CarType VARCHAR(20),
ServRem VARCHAR(250),
DNRIC CHAR(12),
CarServ CHAR(1),
FOREIGN KEY (DNRIC) references DRIVER(DNRIC)
);
CREATE TABLE DSESSION
(
SID NUMBER(7) PRIMARY KEY,
SDate DATE,
DNRIC CHAR(12),
TID NUMBER(6),
FOREIGN KEY (DNRIC) references DRIVER(DNRIC),
FOREIGN KEY (TID) references TRAINING(TID)
);
CREATE TABLE TRAINING
(
TID NUMBER(6) PRIMARY KEY,
TrainingPrg VARCHAR(50),
PrgSession VARCHAR2(10)
);

You referenced a wrong column name in servicedate where you mentioned as sdate while creating a table.
SELECT DISTINCT Dname
FROM driver d
INNER JOIN carservice car ON d.dnric = car.dnric
INNER JOIN dsession dses ON d.dnric = dses.dnric
INNER JOIN training train ON dses.tid = train.tid
WHERE sysdate-dses.sdate < 60
Few good practices to keep in mind:
Using table aliases d,car,dses,train of your choice to access data.
Use ANSI syntax (JOIN statements) rather than your alternate syntax for better readability of code.
Don't miss any syntax errors to hide your way.
Also, you should mention constraint variable properly if using ORACLE / SQL Server / MS Access
CONSTRAINT FK_DNRIC FOREIGN KEY (DNRIC) references DRIVER(DNRIC),
Hope this helps.

You have a wrong semicolon at the end of the from row.
Also, you have not used an aggregation function so you shoud not use group by.
Use distinct if you need to not repeat values.
select distinct Dname
from driver
INNER JOIN carservice ON driver.dnric = carservice.dnric
INNER JOIN dsession ON driver.dnric = dsession.dnric
INNER JOIN training ON dsession.tid = training.tid
Where sysdate-servicedate < 60
You should use the explict join syntax and avoid the old (from 1992) implicit join syntax based on the where clause.

Thanks alot guys!! I had alot of help just with querying with INNER JOIN.

Related

Delete a record based on multiple table choices SQL

I'm trying to wrap my head around how to accomplish this Delete query. The goal is I'm trying to delete a client record (main table) based on if they don't have an insurance policy (another table) and if their needs description is "transportation" and importance values is LESS than 5. The needs is another table. They are all connected with foreign keys and SSN as the connector and Delete cascade is working properly. The query is partially working as is. If there is no insurance policy, the Client is being deleted correctly. However, the need description and importance value factors are not currently working. It will still delete if I have no insurance policy, but my importance description is another value other than transportation.
It's almost like I need 2 subqueries compare both Needs table and Insurance_Policy table for deletion, but I don't know how to do that.
The database I'm using is Azure Data Studio
Here is my current Procedure code:
DROP PROCEDURE IF EXISTS Option17;
GO
CREATE PROCEDURE Option17
AS
BEGIN
DELETE FROM Client
WHERE Client.SSN NOT IN (SELECT I.SSN
FROM Insurance_Policy I, Needs N
WHERE Client.SSN = I.SSN
AND Client.SSN = N.SSN
AND N.need_description = 'transportation'
AND N.importance_value < 5)
END
Also, here are my table structures:
CREATE TABLE Client
(
SSN VARCHAR(9),
doctor_name VARCHAR(60),
doctor_phone_no VARCHAR(10),
lawyer_name VARCHAR(60),
lawyer_phone_no VARCHAR(10),
date_assigned DATE,
PRIMARY KEY (SSN),
FOREIGN KEY (SSN) REFERENCES Person
ON DELETE CASCADE
);
CREATE TABLE Insurance_Policy
(
policy_id VARCHAR(10),
provider_id VARCHAR(10),
provider_address VARCHAR(100),
insurance_type VARCHAR(10),
SSN VARCHAR(9),
PRIMARY KEY (policy_id),
FOREIGN KEY (SSN) REFERENCES Client,
);
CREATE TABLE Needs
(
SSN VARCHAR(9),
need_description VARCHAR(60),
importance_value INT CHECK(importance_value > 0 and importance_value <11),
PRIMARY KEY(SSN,need_description),
FOREIGN KEY(SSN) REFERENCES Client
ON DELETE CASCADE
);
Here is a screenshot if the formatting didn't hold up on procedure.
enter image description here
Based on your answers, I believe this is the code you are looking for. If this is not working, let me know.
To explain a little, using an INNER join will eliminate the need for a couple of those WHERE conditions. INNER JOIN only returns records where it exists in both tables. Also there is no need to link to the Client table from within the subquery.
Also you want where it does not have a description of transportation with an importance of less than 5. Since you are pulling a list to leave alone, you do not want to include these records.
DROP PROC IF EXISTS Option17;
GO
Create proc Option17
AS
BEGIN
DELETE FROM Client
WHERE SSN NOT IN (
SELECT
N.SSN
FROM Needs N
INNER JOIN Insurance_Policy I ON N.SSN = I.SSN
WHERE NOT (N.need_description = 'transportation' AND N.importance_value < 5)
);
END
GO
I think you want separate conditions on Needs and Insurance_Policy. And I recommend NOT EXISTS, because it better handles NULL values:
DELETE c
FROM Client c
WHERE NOT EXISTS (SELECT 1
FROM Insurance i
WHERE c.SSN = i.SSN
) AND
EXISTS (SELECT 1
FROM Needs n
WHERE c.SSN = n.SSN AND
n.need_description = 'transportation' AND
n.importance_value < 5
);

Computed column from different tables

I have Broadcasts, Agents and Advert tables:
CREATE TABLE Broadcasts (
Broadcast_code INT IDENTITY(1,1)PRIMARY KEY,
Minute_cost SMALLMONEY NOT NULL
);
CREATE TABLE Agents (
Agent_code INT IDENTITY(1,1)PRIMARY KEY,
Agent_percent FLOAT NOT NULL,
);
CREATE TABLE Advert (
Advert_code INT IDENTITY(1,1)PRIMARY KEY,
Agent_commission AS ((Minute_cost * Duration_in_minutes) / Agent_percent),
Broadcast_code INT FOREIGN KEY REFERENCES Broadcasts (Broadcast_code) NOT NULL,
Agent_code INT FOREIGN KEY REFERENCES Agents (Agent_code) NOT NULL
);
I want to calculate a computed column:
Agent_commission AS (((Minute_cost * Duration_in_minutes) / Agent_percent)
I tried to use VIEWS, TRIGGERS and UDF. But I can't do it.
I need the easiest way because this is a training project.
Thanks.
A computed column cannot directly reference columns in other tables. One option is to write a user-defined scalar function to calculate the commission.
You have two other options:
Use a view instead of a table.
Use a user-defined table function.
Which is best depends on how the commission will be used. I would advise you to start with a view with the logic you want. You may find that you want columns from several tables.
You can follow below steps
Create table
CREATE TABLE Advert (
Advert_code INT IDENTITY(1,1)PRIMARY KEY,
Agent_commission INT,
Broadcast_code INT FOREIGN KEY REFERENCES Broadcasts (Broadcast_code) NOT NULL,
Agent_code INT FOREIGN KEY REFERENCES Agents (Agent_code) NOT NULL
);
Select required columns
SELECT
NULL AS Advert_code,
((B.Minute_cost * Duration_in_minutes) / A.Agent_percent),
B.Broadcast_code,
A.Agent_code
FROM Broadcasts B
INNER JOIN Agents A
ON (B.Broadcast_code = A.Agent_code );
Using the select query, you can insert into new tables
INSERT INTO Advert
SELECT
NULL AS Advert_code,
((B.Minute_cost * Duration_in_minutes) / A.Agent_percent),
B.Broadcast_code,
A.Agent_code
FROM Broadcasts B
INNER JOIN Agents A
ON (B.Broadcast_code = A.Agent_code );
Little clarification,
* From where you are getting Duration_in_minutes
* What is Advert_code, right now am selecting null, if required you can use oracle sequence or select from another table.
You can also use same select query to create views

invalid identifier when executing select in oracle

I am trying to execute a select in oracle that uses 3 tables, nba_player, nba_team, and nba_team_roster. nba_player includes player data with a player_id and nba_team includes team information with a team_id. nba_team_roster is an associative entity and includes a player_id and team_id to associate the two. I want this query to return the first and last name of each player on team 'OKC' but for some reason it gives me the error below. I am not sure why this isn't executing properly. Any help would be greatly appreciated.
select nba_player.first_name, nba_player.last_name
from nba_player,nba_team
join nba_team_roster
on nba_team_roster.player_id=nba_player.player_id
where nba_team_roster.team_id= nba_team.team_id
and nba_team.team_name='OKC';
on nba_player.player_id=nba_team_roster.player_id
*
ERROR at line 4:
ORA-00904: "NBA_PLAYER"."PLAYER_ID": invalid identifier
CREATE TABLE NBA_Team(
team_id number primary key,
team_name varchar(5)
);
CREATE TABLE NBA_Player(
player_id number primary key,
first_name varchar(10),
last_name varchar (11),
position varchar(3),
salary number,
points_per_game number
);
CREATE TABLE NBA_Team_Roster(
roster_ID number primary key,
team_id number,
player_id number unique,
foreign key (team_id) references NBA_Team(team_id),
foreign key (player_id) references NBA_Player(player_id)
);
Simple rule: Never use commas in the FROM clause. Always use proper, explicit JOIN syntax. That will solve your problem and make the query easier to understand:
select p.first_name, p.last_name
from nba_player p join
nba_team_roster r
on r.player_id = p.player_id join
nba_team t
on r.team_id = t.team_id
where t.team_name = 'OKC';
Note that I also introduced table aliases. These make the query easier to write and to read.

SQL Join - Query error

So I would like to display the most experience player, at first I was going to display all players and experiencepoints then try and only display the max. so heres the code for both tables and the query itself
CREATE TABLE Player
(
Player_ID INTEGER CONSTRAINT pk_player PRIMARY KEY,
Pname VARCHAR(60),
DOB VARCHAR(10),
Heightcm NUMBER(10),
Weightkg NUMBER(10),
Position VARCHAR(20),
Team_ID INTEGER CONSTRAINT fk_player REFERENCES Team(Team_ID)
)
CREATE TABLE PlayerCareer_Performance
(
Player_Performance_ID INTEGER CONSTRAINT pk_PP PRIMARY KEY,
Player_ID INTEGER,
total_points NUMBER(10),
total_fouls NUMBER(10),
ExperiencePoints NUMBER(10),
CONSTRAINT fk_Pp FOREIGN KEY (Player_ID) REFERENCES Player(Player_ID)
)
Thats the table code, below is the query:
SELECT PLAYER.PLAYER_ID,PLAYER.PNAME,PLAYERCAREER_PERFORMANCE.EXPERIENCEPOINTS
FROM PLAYER
JOIN PLAYERCAREER_PERFOMANCE
ON PLAYERPERFROMANCE.PLAYER_ID = PLAYER.PLAYER_ID;
Player is underlined on yellow and it says "Is disconnected from the rest of join graph"
Any ideas, anyone? I cant see a fix for it :(
At first sight, you are joining the table PLAYERCAREER_PERFORMANCE but joining on a field of table called PLAYERPERFROMANCE (sic). Is that a typo?
This:
SELECT Player.Player_ID, Player.Pname, PlayerCareer_Performance.ExperiencePoints
FROM Player
JOIN PlayerCareer_Performance
ON PlayerCareer_Performance.Player_ID = Player.Player_ID
Seems to work fine (just corrected the typo): check it at sqlfiddle.
As a general suggestion, keep your code consistent... you are using different column formats (e.g.: ExperiencePoints vs total_points), and are putting all SQL query code in caps, which just makes it difficult to read and find typos
Use an inner join (updated to reflect popular demand):
select p.player_id, p.pname, pcp.experiencepoiuts
from Player p
inner join PlayerCareer_Performance pcp on pcp.player_id = p.player_id

How can I get this query to print a record that only exists in one table?

I am trying to create a query that will accept a date from the user and display information from two tables based on this date. This works for all of my tests except my last test. My last test, I enter a date that should return a record that only exists in the expmast table and does not exist in the expbycc table. When I enter the date to try and get this record to be returned, it tells me no records have been found. I know this is because in my where, i have an AND that checks if M.ExpNum = C.ExpNUm which isn;t true for this record because it only exists in one table. I can not figure out how to get this query to work. Any help/advice is greatly appreciated. Below is my script, followed by the table structures used for this query, thank you.
Script:
ACCEPT Date PROMPT 'Enter a date:';
SELECT M.ExpNum, EDate, IsCash, StoreCode, CashAmt, CType, CCNum, Amt
FROM ExpMast M, ExpByCc C
WHERE EDate = to_date('&Date','mm-dd-yy')
AND M.ExpNum = C.ExpNum;
Tables:
CREATE TABLE EXPMAST
(ExpNum NUMBER(2,0) NOT NULL PRIMARY KEY,
EDate DATE,
IsCash VARCHAR2(1),
StoreCode VARCHAR2(4),
CONSTRAINT fk_STORE_EXPMAST FOREIGN KEY (StoreCode)
REFERENCES STORE (Code)
);
CREATE TABLE ExpByCC
(ExpNum NUMBER(2,0) NOT NULL,
CType VARCHAR2(1) NOT NULL,
CCNum VARCHAR2(16) NOT NULL,
Amt DECIMAL(5,2),
CONSTRAINT fk_CRCARD_ExpByCC FOREIGN KEY (CType, CCNum)
REFERENCES CRCARD (CType, CCNum),
CONSTRAINT fk_EXPMAST_ExpByCC FOREIGN KEY (ExpNum)
REFERENCES EXPMAST (ExpNum),
CONSTRAINT pk_ExpByCC PRIMARY KEY (ExpNum, CType, CCNum)
);
You need a left outer join. And you can't express an outer join using your implicit join syntax. You want to use explicit joins in the from clause.
A simple rule: NEVER use commas in the from clause.
Now, it is easy:
SELECT M.ExpNum, EDate, IsCash, StoreCode, CashAmt, CType, CCNum, Amt
FROM ExpMast M LEFT OUTER JOIN
ExpByCc C
ON M.ExpNum = C.ExpNum AND
WHERE M.EDate = to_date('&Date','mm-dd-yy') AND
C.ExpNum IS NULL;