Restricting values in a table used in a FULL OUTER JOIN - sql

This concerns Oracle SQL.
Considering the following 3 tables:
TRIP_SEGMENT:
CREATE TABLE TRIP_SEGMENT(
SEG_ID NUMBER(6) NOT NULL,
DIRECTION VARCHAR(8) NOT NULL,
DEPARTURE_LOCATION VARCHAR(50) NOT NULL,
DESTINATION VARCHAR(50) NOT NULL,
SEGMENT_PRICE NUMBER(5,2) NULL,
TRIP_ID NUMBER(6) NOT NULL,
CONSTRAINT chk_SEG_DIRECTION CHECK (DIRECTION IN ('Outbound','Inbound')),
CONSTRAINT pk_SEGMENT PRIMARY KEY (SEG_ID),
CONSTRAINT fk_TRIP_ID FOREIGN KEY (TRIP_ID) REFERENCES TRIP(TRIP_ID)
);
TRANSPORTATION:
CREATE TABLE TRANSPORTATION(
TRANSP_BOOK_ID NUMBER(6) NOT NULL,
TRANSP_PRICE NUMBER(5,2) NULL,
DEPARTURE_DATE DATE NULL,
ARRIVAL_DATE DATE NULL,
EXT_BOOK_ID NUMBER(6) NULL,
SEG_ID NUMBER(6) NOT NULL,
SERV_TYPE_ID NUMBER(3) NOT NULL,
PARTNER_ID NUMBER(3) NULL,
CONSTRAINT pk_TRANSP_BOOK_ID PRIMARY KEY (TRANSP_BOOK_ID),
CONSTRAINT fk_TRANSP_SEG_ID FOREIGN KEY (SEG_ID) REFERENCES TRIP_SEGMENT(SEG_ID),
CONSTRAINT fk_TRANSP_SERV_ID FOREIGN KEY (SERV_TYPE_ID) REFERENCES SERVICE_TYPE(SERV_TYPE_ID),
CONSTRAINT fk_TRANSP_PARTNER_ID FOREIGN KEY (PARTNER_ID) REFERENCES PARTNER(PARTNER_ID)
);
PARTNER:
CREATE TABLE PARTNER(
PARTNER_ID NUMBER(3) NOT NULL,
PARTNER_NAME VARCHAR(50) NOT NULL,
CONTACT_FNAME VARCHAR(20) NOT NULL,
CONTACT_LNAME VARCHAR(20) NOT NULL,
ADDRESS VARCHAR(100) NULL,
PHONE_NO NUMBER(20) NOT NULL,
EMAIL VARCHAR(50) NULL,
SERV_TYPE_ID NUMBER(3) NOT NULL,
CONSTRAINT pk_PARTNER_ID PRIMARY KEY (PARTNER_ID),
CONSTRAINT fk_PART_SERV_ID FOREIGN KEY (SERV_TYPE_ID) REFERENCES SERVICE_TYPE(SERV_TYPE_ID)
);
I wanted to create a FULL OUTER JOIN like this:
SELECT TS.SEG_ID, TS.DEPARTURE_LOCATION, TS.DESTINATION, P.PARTNER_NAME
FROM TRIP_SEGMENT TS
FULL OUTER JOIN TRANSPORTATION T
ON TS.SEG_ID = T.SEG_ID
FULL OUTER JOIN PARTNER P
ON T.PARTNER_ID = P.PARTNER_ID;
...but have it restricted to PARTNER.PARTNER_ID < 6. If I just add a WHERE clause at the end of the JOIN, this will restrict all the values to those where there is an association with PARTNER.PARTNER_ID < 6, therefore defeating the purpose of the FULL OUTER JOIN.
So far, I've come up with this solution:
First, create a table that only contains PARTNER.PARTNER_ID < 6 :
CREATE TABLE TRANSPORTATION_PARTNER AS SELECT * FROM PARTNER WHERE PARTNER_ID < 6;
Then, use that table in the FULL OUTER JOIN instead:
SELECT TS.SEG_ID, TS.DEPARTURE_LOCATION, TS.DESTINATION, TP.PARTNER_NAME
FROM TRIP_SEGMENT TS
FULL OUTER JOIN TRANSPORTATION T
ON TS.SEG_ID = T.SEG_ID
FULL OUTER JOIN TRANSPORTATION_PARTNER TP
ON T.PARTNER_ID = TP.PARTNER_ID;
This works fine and it demonstrates what I'm trying to achieve, however I was wondering if there is a way of doing in one single query AND using a subquery.
Thank you!

YES, just do something like :
SELECT TS.SEG_ID, TS.DEPARTURE_LOCATION, TS.DESTINATION, P.PARTNER_NAME
FROM TRIP_SEGMENT TS
FULL OUTER JOIN TRANSPORTATION T
ON TS.SEG_ID = T.SEG_ID
FULL OUTER JOIN (SELECT *
FROM PARTNER
WHERE PARTNER.PARTNER_ID < 6) P
ON T.PARTNER_ID = P.PARTNER_ID;

You are placing restrictions on the rows to be selected so you can use LEFT JOIN instead of the FULL OUTER JOIN. Try something like
SELECT TS.SEG_ID, TS.DEPARTURE_LOCATION, TS.DESTINATION, P.PARTNER_NAME
FROM TRIP_SEGMENT TS
FULL OUTER JOIN TRANSPORTATION T
ON TS.SEG_ID = T.SEG_ID
LEFT OUTER JOIN PARTNER P
ON T.PARTNER_ID = P.PARTNER_ID AND P.Partner_ID = 6;

Related

SQL Select Query Giving me duplicate columns

I am trying to write a query to display information, but when I use INNER JOIN I am getting duplicate ID fields. My tables and query are below. I am getting duplicate columns for wrestlerID. could it be my PK constraints?
CREATE TABLE WRESTLER
(
WrestlerID CHAR(6) NOT NULL,
WrestlerFirst VARCHAR2(15) NOT NULL,
WrestlerLast VARCHAR2(25) NOT NULL,
WrestlerStyle CHAR(2) NOT NULL,
WrestleKilos NUMERIC(3,0) NOT NULL,
WrestleMeters NUMERIC(3,2),
WrestleCity VARCHAR2(40) NOT NULL,
WrestlerState CHAR(2) NOT NULL,
WrestlerBirthdate Date,
CONSTRAINT WRESTLER_PK PRIMARY KEY (WrestlerID)
);
CREATE TABLE CLUB
(
ClubID CHAR(5) NOT NULL,
Club VARCHAR2(35) NOT NULL,
WrestlerID CHAR(6) NOT NULL,
CONSTRAINT CLUB_PK PRIMARY KEY (ClubID, WrestlerID),
CONSTRAINT CLUB_FK
FOREIGN KEY (WrestlerID) REFERENCES WRESTLER(WrestlerID)
);
CREATE TABLE SCHOOL
(
SchoolID VARCHAR2(10) NOT NULL,
School VARCHAR2(35) NOT NULL,
WrestlerID CHAR(6) NOT NULL,
CONSTRAINT SCHOOL_PK PRIMARY KEY (SchoolID, WrestlerID),
CONSTRAINT SCHOOL_FK
FOREIGN KEY (WrestlerID) REFERENCES WRESTLER(WrestlerID)
);
CREATE TABLE MEDAL
(
WrestlerID CHAR(6) NOT NULL,
WorldMedal NUMERIC(4,0),
CONSTRAINT MEDAL_PK PRIMARY KEY (WrestlerID, WorldMedal),
CONSTRAINT MEDAL_FK
FOREIGN KEY (WrestlerID) REFERENCES WRESTLER(WrestlerID)
);
SELECT
t1.WrestlerID, t1.WrestlerFirst, t1.WrestlerLast,
t2.WrestlerID, t2.School,
t2.WrestlerID, t3.Club
FROM
WRESTLER t1
INNER JOIN
SCHOOL t2 ON t1.WrestlerID = t2.WrestlerID
INNER JOIN
CLUB t3 ON t1.WrestlerID = t3.WrestlerID;
Fixing my query worked
SELECT
t1.WrestlerID, t1.WrestlerFirst, t1.WrestlerLast,
t2.School,
t3.Club FROM
WRESTLER t1 INNER JOIN
SCHOOL t2 on t1.WrestlerID = t2.WrestlerID INNER JOIN
CLUB t3 on t1.WrestlerID = t3.WrestlerID;

Groupby Count Query On Two Tables Filtered by Condition on Third Table

I have three tables: Category, Mail and Classification. The relationship between the tables is outlined in this SQLFiddle with some sample data: http://sqlfiddle.com/#!9/118b24/3/0
CREATE TABLE `Category` (
`id` int(6) unsigned NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE `Mail` (
`id` int(6) unsigned NOT NULL,
`content` varchar(500) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE `Classification` (
`id` int(6) unsigned NOT NULL,
`mail_id` int(6) unsigned NOT NULL,
`category_id` int(6) unsigned NOT NULL,
FOREIGN KEY (mail_id) REFERENCES Mail(id),
FOREIGN KEY (category_id) REFERENCES Category(id),
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
I first run a query to get the count of emails assigned to each category:
SELECT Category.name, count(Classification.category_id) FROM Category LEFT OUTER JOIN Classification ON Classification.category_id = Category.id GROUP BY Category.name
Which works fine.
But I would now like to add a filter based on the date that is in the Email collection. If I had a join with a filter collection:
SELECT Category.name, count(Classification.category_id) FROM Category JOIN Mail ON Mail.date < '2019-03-24' LEFT OUTER JOIN Classification ON Classification.category_id = Category.id GROUP BY Category.name
But now the count only doubles and it seems the filter isn't even applied. Why isn't the filter working and what should I do to fix it?
You need a JOIN condition between Classification and Mail:
SELECT ca.name, count(cl.category_id)
FROM Category LEFT JOIN
Classification cl
ON cl.category_id = c.id LEFT JOIN
Mail m
ON m.id = cl.mail_id AND -- your JOIN key goes here
m.date < '2019-03-24'
GROUP BY c.name ;

Creating a view in Sql with connected tables

I am trying to create a view off of two different tables. Basically I have 2 tables
(MatchStats- Holds all of the fixture information)
(Team - Holds all of the team information)
Here is the code for both tables
Team
CREATE TABLE TEAM
(
TeamID int NOT NULL,
TeamName varchar(30) NOT NULL,
Teamlocale varchar(30) NOT NULL,
CONSTRAINT pkTeamID PRIMARY KEY (TeamID),
)
MatchStats
CREATE TABLE MATCHSTATS
(
MatchStatsID int NOT NULL,
Team1ID int NOT NULL,
Team1Goals int NOT NULL,
Team2ID int NOT NULL,
Team2Goals int NOT NULL,
RefereeID int NOT NULL,
PitchID int NOT NULL,
sessionTime varchar(20) NOT NULL,
sessionDate varchar(20) NOT NULL,
CONSTRAINT pkMatchStatsID PRIMARY KEY (MatchStatsID),
CONSTRAINT fkTeam1ID FOREIGN KEY (Team1ID) REFERENCES TEAM(TeamID),
CONSTRAINT fkTeam2ID FOREIGN KEY (Team2ID) REFERENCES TEAM(TeamID),
CONSTRAINT fkReferee FOREIGN KEY (RefereeID) REFERENCES REFEREE(RefereeID),
CONSTRAINT fkpitchID FOREIGN KEY (PitchID) REFERENCES Pitch(pitchID),
)
I am trying to create a view that will display the fixture information but use the team name instead of ID. I have been researching and looking at previous questions online and I just cant seem to understand how to do it
This is what I have managed to come up with
CREATE VIEW FIXTUREHSITORY AS
SELECT m.Team1ID, m.Team1Goals, m.Team2ID, m.Team2Goals, T.TeamName
from MATCHSTATS as m
JOIN TEAM as t ON t.TeamID on
Overall I am trying to create a report that looks like this
Team 1 Name | Goals | Team 2 Name | Goals
Sorry if I seem vague and thanks in advance
A solution to your problem:
MSSQL
CREATE VIEW FIXTUREHISTORY AS
SELECT t1.TeamName Team1Name,
m.Team1Goals Team1Goals,
t2.TeamName Team2Name,
m.Team2Goals Team2Goals
from MATCHSTATS as m
INNER JOIN TEAM as t1 ON t1.TeamID = m.Team1ID
INNER JOIN TEAM as t2 ON t2.TeamID = m.Team1ID
Demo Link:
http://sqlfiddle.com/#!18/34883/1

Problems with a query PostgreSQL

I have some problems with a Query that I can not get out, the structure of the tables is as follows:
child
CREATE TABLE CHILD(
child_id SMALLINT,
child_name VARCHAR(255) NOT NULL,
birth_date DATE NOT NULL,
gender VARCHAR(255) NOT NULL,
address VARCHAR(255),
city VARCHAR(255),
CONSTRAINT PK_CHILD PRIMARY KEY(child_id)
letter
CREATE TABLE LETTER(
letter_id SMALLINT,
arrival_date DATE NOT NULL,
number_toys INTEGER NOT NULL,
delivery_mode VARCHAR(255) NOT NULL,
child_id SMALLINT,
CONSTRAINT PK_LETTER PRIMARY KEY(letter_id),
CONSTRAINT CHILD_FK FOREIGN KEY (child_id) REFERENCES CHILD(child_id)
);
wished_toy
CREATE TABLE WISHED_TOY(
letter_id SMALLINT,
toy_id SMALLINT,
CONSTRAINT PK_WISHED_TOY PRIMARY KEY(letter_id, toy_id),
CONSTRAINT LETTER_FK FOREIGN KEY (letter_id) REFERENCES LETTER(letter_id)
CONSTRAINT LETTER_FK FOREIGN KEY (toy_id) REFERENCES TOY(toy_id)
);
toy
CREATE TABLE TOY(
toy_id SMALLINT,
toy_name VARCHAR (255) NOT NULL,
price DECIMAL NOT NULL,
toy_type VARCHAR(255) NOT NULL,
manufacturer VARCHAR(255) NOT NULL,
CONSTRAINT PK_TOY PRIMARY KEY(toy_id),
);
I have to design a query that allows to obtain for each girl born before 2010 the
total number of toys you have ordered. The result must also include
those girls who have not written any letters. Specifically we want the
identifier of the girl, her name and city and the total number of toys ordered
(such as Total_number).
in the gender column of the child table can only be "m" of masculine or "f" of feminine
Do I have to use join?
the part that I have is this
select c.child_id,c.child_name,c.city
from letter l
join child c
on c.child_id=l.child_id
where c.gender='m' and c.birth_date between <='2010/01/01';
select c.child_id,c.child_name,c.city, coalesce( number_toys,0) counted
from
Child c
left outer join letter l
on c.child_id=l.child_id
where c.gender='m' and c.birth_date between <='2010/01/01';
Or
select c.child_id,c.child_name,c.city, count(wt.letter_id) actualToys
from
Child c
left outer join letter l
on c.child_id=l.child_id
left outer join wished_toy wt on l.letter_id=wt.letter_id
where c.gender='m' and c.birth_date between <='2010/01/01'
Group by
c.child_id,c.child_name,c.city
To count the toys referenced by database rows rather than the pre defined count

SQL Outer Join -- Join requires 3 tables

I'm using SQL Server query designer to try and form an outer query that will return the full name and address of each insured with home policies and those without policies. My create statements are the following:
CREATE TABLE Address (
AddressID integer NOT NULL,
HouseNumber Integer NOT NULL,
Street varchar(20) NOT NULL,
CityCounty varchar(20) NOT NULL,
StateAbb char(2),
CountryAbb char(2) NOT NULL,
Zip char(5) NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Address PRIMARY KEY (AddressID));
CREATE TABLE Insured(
InsuredID integer NOT NULL,
FirstName varchar(15) NOT NULL,
LastName varchar(15) NOT NULL,
MI char(1),
DateOfBirth date NOT NULL,
CreditScore integer NOT NULL,
AddressID integer NOT NULL,
DriversLicenseNumber varchar(35),
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Insured PRIMARY KEY (InsuredID),
CONSTRAINT FK_InsuredAddress FOREIGN KEY (AddressID) references Address);
CREATE TABLE Policy(
PolicyID integer NOT NULL,
EffectiveDate date NOT NULL,
TerminationDate date NOT NULL,
Amount Numeric (8,2) NOT NULL,
PolicyYear integer NOT NULL,
PolicyType char(1) NOT NULL,
InsuredID integer NOT NULL,
AddressID integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Policy PRIMARY KEY (PolicyID),
CONSTRAINT FK_PolicyAddress FOREIGN KEY (AddressID) references Address,
CONSTRAINT FK_PolicyInsured FOREIGN KEY (InsuredID) references Insured);
CREATE TABLE Home(
PolicyID integer NOT NULL,
ExteriorType varchar(30) NOT NULL,
Alarm char(3) NOT NULL,
DistanceToFireStation integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Home PRIMARY KEY (PolicyID),
CONSTRAINT FK_HomePolicy FOREIGN KEY (PolicyID) references Policy);
CREATE TABLE Auto(
PolicyID integer NOT NULL,
VinNumber varchar(30) NOT NULL,
Make varchar(15) NOT NULL,
Model varchar(20) NOT NULL,
MilesPerYear integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Auto PRIMARY KEY (PolicyID),
CONSTRAINT FK_AutoPolicy FOREIGN KEY (PolicyID) references Policy);
I believe that the query requires tables address, insured, policy and an outer right or left join but I cant get SQL server to recognize this as it keeps forming an inner join and cross join. What do I need for a query that returns insureds with home policies and their addresses and insureds with no policy and their addresses?
What I've tried so far:
SELECT Insured.InsuredID, Insured.FirstName,
Insured.LastName, Address.HouseNumber,
Policy.PolicyID
FROM Address RIGHT JOIN Policy
ON Address.AddressID = Policy.AddressID
RIGHT JOIN Insured ON Policy.AddressID = Insured.AddressID
ORDER BY Insured.InsuredID
This is the most recent query that returns what I need for insureds with a home policy but for the insureds without a policy I get nulls in the address.
SELECT i.InsuredID, i.FirstName, i.MI, i.LastName,
a.HouseNumber, a.Street, a.CityCounty, a.StateAbb, a.CountryAbb, a.Zip
FROM INSURED i
LEFT JOIN (SELECT * FROM Policy WHERE PolicyType = 'H') HomePolicy on
i.InsuredID = HomePolicy.InsuredID
LEFT JOIN Address a on HomePolicy.AddressID = a.AddressID;
Could you try this query:
SELECT i.InsuredID,
i.FirstName,
i.LastName,
a.HouseNumber,
p.PolicyID
FROM insured i
LEFT JOIN policy p ON i.AddressID = p.AddressID AND p.PolicyType = 'H'
LEFT JOIN address a ON i.AddressID = a.AddressID
ORDER BY i.InsuredID;
I think the joins were in the wrong order. Does this give you what you need?
Update: Joining the Insured table to the Address table will show you addresses regardless of if they have a policy or not.
Database design seem good.I think we have minor doubts regarding "PolicyType" column. what value it hold and what is the purpose of this column.
Say PolicyType='H' it mean that it is home policy . Or other way of finding same query is to check if that policyid exists in home table.
Is this correct ?
Main query,
What do I need for a query that returns insureds with home policies
and their addresses and insureds with no policy and their addresses?
Check this script,
--insureds with home policies and their addresses
select i.InsuredID,
i.FirstName,
i.LastName
A.HouseNumber
,1 INDICATE
from Insured i
INNER JOIN policy p ON i.InsuredID = p.InsuredID
INNER JOIN [Address] A ON A.ADDRESSID=I.ADDRESSID
WHERE EXISTS(SELECT PolicyID FROM Home H WHERE h.PolicyID=P.PolicyID)
AND NOT EXISTS(SELECT PolicyID FROM [Auto] a WHERE A.PolicyID=P.PolicyID)
UNION ALL
--insureds with no policy and their addresses
select i.InsuredID,
i.FirstName,
i.LastName
,A.HouseNumber
,0 INDICATE
from Insured i
INNER JOIN [Address] A ON A.ADDRESSID=I.ADDRESSID
WHERE EXISTS(SELECT InsuredID FROM policy p WHERE i.InsuredID = p.InsuredID )
I have use "EXISTS clause" because that table column is not require in your output.