Conditional query of the tables - sql

ALL,
Consider the following database schema:
CREATE TABLE players(playerid integer primary key, playertype integer, ....);
CREATE TABLE scoretype1(scoreid integer primary key, scorename varchar);
CREATE TABLE scoretype2(scoreid integer primary key, scorename varchar);
CREATE TABLE scoreforplayerstype1(playerid integer, scoreid integer, value double, foreign key(playerid) references players(playerid), foreign key(scoreid) references scoretype1(scoreid));
CREATE TAble scoreforplayerstype2(playerid integer, scoreid integer, value double, foreign key(playerid) references players(playerid), foreign key(scoreid) references scoretype2(scoreid));
Now the problem:
Is it possible to get the score values for all players in one query or I have to do 2 queries for type 1 and type 2? I'm looking to have a score name and score value for a player.
Thank you.

SELECT P1.PLAYERID, S1.SCORENAME, J1.VALUE
FROM PLAYERS AS P1
INNER JOIN SCOREFORPLAYERSTYPE1 AS J1
ON J1.PLAYERID = P1.PLAYERID
INNER JOIN SCORETYPE1 AS S1
ON S1.SCOREID = J1.SCOREID
UNION ALL
SELECT P2.PLAYERID, S2.SCORENAME, J2.VALUE
FROM PLAYERS AS P2
INNER JOIN SCOREFORPLAYERSTYPE2 AS J2
ON J1.PLAYERID = P1.PLAYERID
INNER JOIN SCORETYPE2 AS S2
ON S1.SCOREID = J1.SCOREID

SELECT p.playerid
,p.playertype
,IFNULL(sfp1.value, sfp2.value) AS value
,IFNULL(st1.scorename, st2.scorename) AS scorename
FROM players p
LEFT JOIN scoreforplayerstype1 sfp1 ON p.playerid = sfp1.playerid
LEFT JOIN scoreforplayerstype2 sfp2 ON p.playerid = sfp1.playerid
LEFT JOIN scoretype1 st1 ON sfp1.scoreid = st1.scoreid
LEFT JOIN scoretype2 st2 ON sfp2.scoreid = st2.scoreid
That should do it, but as the comments suggest, you should rethink your table structure.

Related

SQL select the actor and movie name from every actor that has worked with a particular actor

This is a HW assignment, so please no exact answers if you can help it; I want to learn, not have it done for me.
(The create table statments are at the end of this post)
My task is to find all of the actors who have been in a movie with Tom Hanks, ordered by movie title, using 2 queries.
So far I have been able to create the following query; I know that my join is wrong, but I'm not sure why. How can I think about this differently? I feel like I'm close to the answer, but not quite there.
SELECT actor.name, movie.title FROM actor
LEFT OUTER JOIN character.movie_id ON movie.id IN
(
-- Get the ID of every movie Tom Hanks was in
SELECT movie_id FROM actor
INNER JOIN character ON character.actor_id = actor.id
WHERE actor.name = 'Tom Hanks'
)
WHERE actor.name != 'Tom Hanks'
ORDER BY movie.title;
Here are the create table statments for the schema:
create table actor (
id varchar(100),name varchar(100),
constraint pk_actor_id primary key (id));
create table movie(
id varchar(100),
title varchar(100),
year smallint unsigned,
mpaa_rating varchar(10),
audience_score smallint unsigned,
critics_score smallint unsigned,
constraint pk_id primary key(id));
create table character(
actor_id varchar(100),
movie_id varchar(100),
character varchar(100),
constraint pk_character_id primary key(movie_id, actor_id, character),
constraint fk_actor_id foreign key (actor_id) references actor (id),
constraint fk_movie_id foreign key (movie_id) references movie (id));
A left outer join will give you every entry in the left table (actor). If it has a corresponding value in the right table, it will give you that value, otherwise, you will get a null value returned.
Additionally, you join a table. In your query, you are trying to join a column
Something like this, perhaps? FWTH is films with Tom Hanks.
select mo.title, ac.name
from character ch join
(select m.movie_id
from character c join movie m on c.movie_id = m.id
join actor a on a.id = c.actor_id
where a.name = 'Tom Hanks'
) fwth on ch.movie_id = fwth.movie_id
join actor ac on ac.id = ch.actor_id
join movie mo on mo.id = fwth.movie_id
order by mo.title;

SQL get all entries by ids

I have 3 tables roughly like below:
create table user(
id integer primary key
)
create table post(
id integer primary key,
author integer,
foreign key (author) references user(id)
)
create table user_following(
id integer primary key,
follower integer,
followee integer,
foreign key (follower) references user(id),
foreign key (followee) references user(id)
)
these tables were created by ORM framework, I want to use raw SQL to get all posts by a user's followee, which can be multiple users. Can I do it in SQL?
If you know the follower's ID, the below statement will conduct a join and get the follower's followees' posts. You can replace the number 3 with any user id.
SELECT * FROM user_following AS a
JOIN post AS b ON a.followee = b.author
WHERE a.follower=3;
Something like this?
select p.*
from post p
join user_following uf on p.author = uf.followee
where uf.follower = 123;
select posts.*
from post posts
inner join [user] u_followee on u_followee.id = posts.author
inner join user_following ufo on ufo.followee = u_followee.id
inner join [user] u_follower on ufo.follower = u_follower.id
where u_follower.id = #USER_ID_WHOSE_FOLLOWEE_POSTS_REQUIRED

Finding Standings Table in a tournament

I have 2 tables
create table players
(name text,
id serial primary key);
create table matches
(winner integer references players(id),
loser integer references players(id),
id serial primary key);
I have to make a table called "standings" containing:
player_id,player_name,total_wins,total_matches
How to proceed?
Something like this:
select p.id, p.name,
count(w.id) as total_wins,
count(l.id) + count(w.id) as total_matches
from players p
left join matches w on w.winner = p.id
left join matches l on l.loser = p.id
group by p.id, p.name;
Online example: http://rextester.com/EHDCG19917

How to select NOT using SQL JOIN

My question is to select pilots that are currently not assigned to any flight.
My idea is to use LEFT JOIN to select pilots that are currently assigned to flights, then select the null values. Am I right?
I am trying to select the null value by using WHERE...IS NULL, but I don't know how. Thanks for the help.
There are five tables:
Flight:
PRIMARY KEY (id),
FOREIGN KEY (route) REFERENCES Route (id),
FOREIGN KEY (aircraft) REFERENCES Aircraft (id)
Aircraft:
PRIMARY KEY (id),
FOREIGN KEY (aircraftType) REFERENCES AircraftType (id)
AircraftType:
PRIMARY KEY (id)
Pilot:
PRIMARY KEY (person, forAircraftType),
FOREIGN KEY (person) REFERENCES Person (id),
FOREIGN KEY (forAircraftType) REFERENCES AircraftType (id)
Person:
PRIMARY KEY (id)
Here is my code, I can select pilots that are currently assigned to flight
SELECT name
FROM Flight
LEFT JOIN Aircraft ON Flight.aircraft = Aircraft.id
LEFT JOIN AircraftType ON Aircraft.AircraftType = AircraftType.id
LEFT JOIN Pilot ON AircraftType.id = Pilot.forAircraftType
LEFT JOIN Person ON Pilot.person = Person.id
Instead of trying to join your "Flight" table into the query, simply check if the pilot exists in the Flight table:
SELECT name
FROM Aircraft
LEFT JOIN AircraftType
ON Aircraft.AircraftType = AircraftType.id
LEFT JOIN Pilot
ON AircraftType.id = Pilot.forAircraftType
LEFT JOIN Person
ON Pilot.person = Person.id
WHERE NOT EXISTS (SELECT 1 FROM Flight WHERE Flight.aircraft = Aircraft.id)
Reverse your query or use Right Join as opposed to Left. In its current configuration, Flight is your base table that all other tables are being joined to so it will only return records where pilots have been assinged to a flight i.e. this acts a filter which excludes unassigned Pilots.
By making Pilot or Person as your base, you are aligning all other tables to it and can simply use IS NULL to get your results.
SELECT name
FROM Person
LEFT JOIN Pilot ON Person.id = Pilot.person
LEFT JOIN AircraftType ON Pilot.forAircraftType = AircraftType.id
LEFT JOIN Aircraft ON AircraftType.id = Aircraft.AircraftType
LEFT JOIN Flight ON Aircraft.id = Flight.aircraft
Where Flight.aircraft IS NULL
You want to select those rows which are contains null into name field of flight
SELECT name
FROM Flight
LEFT OUTER JOIN Aircraft
ON Flight.aircraft = Aircraft.id
LEFT JOIN AircraftType
ON Aircraft.AircraftType = AircraftType.id
LEFT JOIN Pilot
ON AircraftType.id = Pilot.forAircraftType
LEFT JOIN Person
ON Pilot.person = Person.id
WHERE Flight.name is null

Write a query using INNER JOIN AND OR

I have a form and an insert button and when i click on the button - the fields goes in to these tables (i didn't put here all the fields because they are not important for my question).
The Tables:
CREATE TABLE SafetyAct (
SafetyAct_id int identity(1,1),
Username varchar(50),
SafetyType_id int,
constraint pk_SafetyAct_id
primary key (SafetyAct_id),
constraint fk_Users_SafetyAct
foreign key(Username)
references Users(Username)
on delete cascade
)
CREATE TABLE Product (
Product_id int identity(1,1) primary key,
SafetyAct_id int,
Cause_id int,
constraint fk_SafetyAct_Product
foreign key(SafetyAct_id)
references SafetyAct(SafetyAct_id)
on delete cascade,
constraint fk_Cause_Product
foreign key(Cause_id)
references Cause(Cause_id)
on delete cascade
)
CREATE TABLE SafetyIntervention (
SafetyIntervention_id int identity(1,1) primary key,
SafetyAct_id int,
Cause_id int,
constraint fk_SafetyAct_SafetyIntervention
foreign key(SafetyAct_id)
references SafetyAct(SafetyAct_id)
on delete cascade,
constraint fk_Cause_SafetyIntervention
foreign key(Cause_id)
references Cause(Cause_id)
on delete cascade
)
CREATE TABLE Cause (
Cause_id int primary key,
Cause_name varchar(80)
)
I want to write a query that shows the fields - SafetyAct_id and Cause_name.
in the Cause_name field i have a problem because i want that the query will show me the cause name drom the Product table or from the SafetyIntervension table (of course to connect it to the Cause table because i have only the cause_id - foriegn key in these tables) and i don't know how to write INNER JOIN and OR at the same query.
I am new with this so plase be patient.
Thank you!
SELECT SA.SafetyAct_id,
C.Cause_name
FROM SafetyAct SA
LEFT JOIN Product P
ON SA.SafetyAct_id = P.SafetyAct_id
LEFT JOIN SafetyIntervention SI
ON SA.SafetyAct_id = SI.SafetyAct_id
LEFT JOIN Cause C
ON ISNULL(P.Cause_id,SI.Cause_id) = C.Cause_id
An or is easy. So, based on Lamak's code:
SELECT SA.SafetyAct_id,
C.Cause_name
FROM SafetyAct SA LEFT JOIN
Product P
ON SA.SafetyAct_id = P.SafetyAct_id LEFT JOIN
SafetyIntervention SI
ON SA.SafetyAct_id = SI.SafetyAct_id LEFT JOIN
Cause C
ON C.Cause_id = P.Cause_id OR C.Cause_Id = SI.Cause_id;
--------------------------------^
You can just use OR in the ON condition.
However, it is often challenging for a SQL engine (SQL Server included) to optimize a join when the on condition includes or or functions on the columns used for the join. Hence, the following is often more efficient:
SELECT SA.SafetyAct_id,
COALESCE(Cp.Cause_name, Csi.Cause_Name) as Cause_Name
FROM SafetyAct SA LEFT JOIN
Product P
ON SA.SafetyAct_id = P.SafetyAct_id LEFT JOIN
SafetyIntervention SI
ON SA.SafetyAct_id = SI.SafetyAct_id LEFT JOIN
Cause Cp
ON Cp.Cause_id = P.Cause_id LEFT JOIN
Cause Csi
ON Csi.Cause_Id = SI.Cause_id;
If only some of the records have a cause of either type, then add:
WHERE Cp.Cause_Id IS NOT NULL OR Csi.Cause_Id IS NOT NULL;