Joining together results of two select statements - sql

I have the following schema and I am just stuck on one particular part.
CREATE TABLE Suppliers (ID INT, Name VARCHAR(128), Postcode VARCHAR(10));
CREATE TABLE Branches (ID INT, Name VARCHAR(128), Postcode VARCHAR(10));
CREATE TABLE Postcode_States (ID INT, State VARCHAR(128), Postcode VARCHAR(10));
SELECT S.Name AS SupplierName, PS.State AS SupplierState
FROM Suppliers AS S
LEFT JOIN Postcode_States PS ON S.Postcode = PS.Postcode;
SELECT B.Name AS BranchName, PS.State AS BranchCounty
FROM Branches AS B
LEFT JOIN Postcode_States PS ON B.Postcode = PS.Postcode;
I have three tables, Suppliers, Branches and Postcode_States. I have selected all the Suppliers and their states joined on postcode in one query and all the Branches and their states joined on postcode in another query. Can anyone give me any guidance on how I could combine these two queries so that I could return all the Suppliers and Branches with the same state? Thanks
Sample data and requested query output

You can join:
select s.name, b.name, p.state
from suppliers s
inner join branches b on b.postcode = s.postcode
inner join postcodes p on p.postcode = s.postcode

If you want states with more than one supplier, you can use window functions:
select s.*
from (select s.name, b.name, p.state,
count(*) over (partition by state) as cnt
from suppliers s join
branches b
on b.postcode = s.postcode join
postcodes p
on p.postcode = s.postcode
) s
where cnt >= 2
order by cnt desc, state;
This doesn't return Texas, but your question suggests that you want duplicates.

Related

How to select passengers that never flew to a city

I will send the Database Description in an Image.
I tried this Select but I'm afraid that this isn't right
SELECT t.type , a.ICAOId , a.name , ci.id , c.ISOAlpha2ID , p.docReference , ti.docReference , ti.number , p.name , p.surname
FROM dbo.AirportType t
INNER JOIN dbo.Airport a ON t.type = a.type
INNER JOIN dbo.City ci ON a.city = ci.id
INNER JOIN dbo.Country c ON ci.ISOalpha2Id = c.ISOalpha2Id
INNER JOIN dbo.Passenger p ON c.ISOalpha2Id = p.nationality
INNER JOIN dbo.Ticket ti ON p.docReference = ti.docReference
WHERE NOT ci.id = 'Tokyo'
Can you please help to get this right?
enter image description here
You could make a list of the passengers that HAVE flown to the city then use that as a subquery to select the ones not in the list
I am just going to make an example of how it should be done
Subquery:
SELECT p.id FROM passengers
JOIN tickets t ON p.id = t.passengerID
JOIN city c ON c.id = t.cityID
Now you just put that into another query that selects the elements not in it
SELECT * FROM passenger
WHERE id not in (
SELECT p.id FROM passengers
JOIN tickets t ON p.id = t.passengerID
JOIN city c ON c.id = t.cityID
WHERE c.name= 'tokyo'
)
Notice I didn't use your attribute names, you will have to change those.
This was a bit simplified version of what you will have to do because the city is not directly in your tickets table. So you will also have to join tickets, with coupons, and flights to get the people that have flown to a city. But from there it is the same.
Overall I believe this should help you get what you have to do.
A minimal reproducible example is not provided.
Here is a conceptual example, that could be easily extended to a real scenario.
SQL
-- DDL and sample data population, start
DECLARE #passenger TABLE (passengerID INT PRIMARY KEY, passenger_name VARCHAR(20));
INSERT #passenger (passengerID, passenger_name) VALUES
(1, 'Anna'),
(2, 'Paul');
DECLARE #city TABLE (cityID INT PRIMARY KEY, city_name VARCHAR(20));
INSERT #city (cityID, city_name) VALUES
(1, 'Miami'),
(2, 'Orldando'),
(3, 'Tokyo');
-- Already visited cities
DECLARE #passenger_city TABLE (passengerID INT, cityID INT);
INSERT #passenger_city (passengerID, cityID) VALUES
(1, 1),
(2, 3);
-- DDL and sample data population, end
SELECT * FROM #passenger;
SELECT * FROM #city;
SELECT * FROM #passenger_city;
;WITH rs AS
(
SELECT c.passengerID, b.cityID
FROM #passenger AS c
CROSS JOIN #city AS b -- get all possible combinations of passengers and cities
EXCEPT -- filter out already visited cities
SELECT passengerID, cityID FROM #passenger_city
)
SELECT c.*, b.city_name
FROM rs
INNER JOIN #passenger AS c ON c.passengerID = rs.passengerID
INNER JOIN #city AS b ON b.cityID = rs.cityID
ORDER BY c.passenger_name, b.city_name;
Output
passengerID
passenger_name
city_name
1
Anna
Orldando
1
Anna
Tokyo
2
Paul
Miami
2
Paul
Orldando

SQL Join Having Group By Count

I am new to SQL and databases and am trying to learn about queries and the different relationship types by challenging myself.
I am not sure if I drew this correctly but I basically have two tables. Supplier and Brand. One brand can have many suppliers but one supplier may also supply to many brands.
I created a third table which holds these relationships which is called Supplier_Brand.
SELECT supplier_name, brand.brand_name
FROM Brand
INNER JOIN Supplier_Brand
ON Brand.brand_id = Supplier_Brand.brand_id
INNER JOIN Supplier
ON Supplier.supplier_id = Supplier_Brand.supplier_id;
I managed to join them with the query above and get the following output:
However, I would like to only show the supplier that delivers to more than one brand ( what is shown in the green box ) I have tried all sort of things with GROUP BY and HAVING and count but I am not able to get it right. How could I solve this?
You can use CTE (Common Table Expression) to achieve your expectation.
WITH id_of_multiple_brand AS (SELECT supplier_id
FROM Brand
INNER JOIN Supplier_Brand
ON Brand.brand_id = Supplier_Brand.brand_id
INNER JOIN Supplier
ON Supplier.supplier_id = Supplier_Brand.supplier_id
GROUP BY supplier_id
HAVING count(brand.brand_name) > 1)
SELECT supplier_name, brand.brand_name
FROM Brand
INNER JOIN Supplier_Brand
ON Brand.brand_id = Supplier_Brand.brand_id
INNER JOIN Supplier
ON Supplier.supplier_id = Supplier_Brand.supplier_id
where supplier_id in (select supplier_id from id_of_multiple_brand);
We can use MIN() and MAX() here as analytic functions:
WITH cte AS (
SELECT s.supplier_name, b.brand_name,
MIN(b.brand_name) OVER (PARTITION BY s.supplier_name) AS min_brand_name,
MAX(b.brand_name) OVER (PARTITION BY s.supplier_name) AS max_brand_name
FROM Brand b
INNER JOIN Supplier_Brand sb ON b.brand_id = sb.brand_id
INNER JOIN Supplier s ON s.supplier_id = sb.supplier_id
)
SELECT supplier_name, brand_name
FROM cte
WHERE min_brand_name <> max_brand_name
ORDER BY supplier_name, brand_name;

What is the most efficient way of selecting data from relational database?

I just started working with databases and
I have this data sample from PostgreSQL tutorial
https://www.postgresqltutorial.com/postgresql-sample-database/
Which diagram looks like this:
I want to find all film categories rented in for example Canada. Is there a way of doing it without using SELECT within SELECT.. statement like this:
SELECT * FROM category WHERE category_id IN (
SELECT category_id FROM film_category WHERE film_id IN (
SELECT film_id FROM film WHERE film_id IN (
SELECT film_id FROM inventory WHERE inventory_id IN (
SELECT inventory_id FROM rental WHERE staff_id IN (
SELECT staff_id FROM staff WHERE store_id IN (
SELECT store_id FROM store WHERE address_id IN (
SELECT address_id FROM address WHERE city_id IN (
SELECT city_id FROM city WHERE country_id IN (
SELECT country_id FROM country WHERE country IN ('Canada')
)
)
)
)
)
)
)
)
)
I'm sure there must be something that i'm missing.
The proper way is to use joins instead of all these nested subqueries:
select distinct c.category_id, c.name
from category c
inner join film_category fc on fc.category_id = c.category_id
inner join inventory i on i.film_id = fc.film_id
inner join rental r on r.inventory_id = i.inventory_id
inner join staff s on s.staff_id = r.staff_id
inner join store sr on sr.store_id = s.store_id
inner join address a on a.address_id = sr.address_id
inner join city ct on ct.city_id = a.city_id
inner join country cr on cr.country_id = ct.country_id
where cr.country = 'Canada'
For your requirement you must join 9 tables (1 less than your code because the table film is not really needed as the column film_id can link the tables film_category and inventory directly).
Notice the aliases for each table which shortens the code and makes it more readable and the ON clauses which are used to link each pair of tables.
Also the keyword DISTINCT is used so you don't get duplicates in the results because all these joins will return many rows for each category.

Retrive counts of two columns from two diffrent tables with third table using join query in SQL

I have 3 tables: COUNTRY, STATE, CITY
This is my Country table with two columns:
CountryID, Name
This is my State table:
This is my City table:
I want to retrieve the count of states and cities according to the country table using join query.
Skipping the fact that your question is not asked well - try this query, it should work for you:
WITH
tab_a AS (
SELECT c.countryid, COUNT (s.stateid) AS state_num
FROM country c
LEFT JOIN state s ON c.countryid = s.countryid
GROUP BY c.countryid
),
tab_b AS (
SELECT c.countryid, COUNT (cc.cityid) city_num
FROM country c
LEFT JOIN state s ON c.countryid = s.countryid
LEFT JOIN city cc ON s.stateid = cc.stateid
GROUP BY c.countryid
)
SELECT a.countryid,
a.state_num,
b.city_num
FROM tab_a a JOIN tab_b b ON a.countryid=b.countryid

Confused with sql query

I have the following tables:
Customer(login varchar, town varchar)
Orders (Ordno int , login varchar) >>login Fk from Customer
combination (Id int, ordno int ,Product_Id int) >>ordno fk from orders
I need to show the products that have been sold in ALL the cities.
Example:
Insert into Customer (log1 , NY) (log2, NY) (log3, London)
Insert into Orders (1,log1) (2,log1) (3,log3)
Insert into combination (1,1,1) (2,2,2) (3,3,1)
Product 1 sold in NY
product 2 sold in NY
product 1 sold in London
if the available cities are only NY and London, then the only product that must be the result of the query is product 1
SELECT a.ProductID
FROM Combination a
INNER JOIN Orders b
ON a.OrdNo = b.OrdNo
INNER JOIN Customer c
ON b.Login = c.LogIn
GROUP BY a.ProductID
HAVING COUNT(DISTINCT a.ID) = (SELECT COUNT(DISTINCT town) FROM Customer)
SQLFiddle Demo
Not sure what exactly you are trying to do here.
SELECT c.Town, cc.Product_Id FROM from Customer c
JOIN Orders o ON c.login = o.login
JOIN Combination cc ON o.Ordno = cc.ordNo
GROUP BY c.town
This will group the towns together and show you the Product_Id
You still need a Product table to display the product table.
This query excludes the product table
Assuming Products table looks like this:
Products (Product_Id int, Name)
You need to join stuff all the way down (or up) to customer...
SELECT p.Name, c.town
FROM Products p
INNER JOIN Combination comb ON comb.Product_Id=p.Product_Id
INNER JOIN Orders o ON o.Ordno=comb.ordno
INNER JOIN Customer cust ON cust.login=o.login
GROUP BY p.Name, c.town