how to join 4 tables together in sql - sql

I have customers, products, orders orderdetails 4 table.
their relationship looks like this.relashions
my SQL code looks like this:
select customers.CUSTOMERNAME, customers.STATE, customers.creditlimit
from customers
INNER JOIN ORDERS ON customers.customernumber = ORDERS.CUSTOMERNUMBER;
select ORDERDETAILS.PRICEEACH, ORDERDETAILS.QUANTITYORDERED
from ORDERDETAILS
inner join orders on ORDERS.ORDERNUMBER = ORDERDETAILS.ordernumber;
select products.productname
from products
inner join orderdetails on orderdetails.productcode = products.productcode;
I want to join the 4 tables into one table with selected segment. how can I do that?

you already figured out your answer. Add all 3 queries together to make one. Please be mindful about joins and sequence of joins.
SELECT
customers.CUSTOMERNAME, customers.STATE, customers.creditlimit ,
ORDERDETAILS.PRICEEACH, ORDERDETAILS.QUANTITYORDERED ,
products.productname
FROM ORDERS
INNER JOIN customers ON customers.customernumber = ORDERS.CUSTOMERNUMBER
inner join orderdetails on ORDERS.ORDERNUMBER = ORDERDETAILS.ordernumber
inner join products on products.productcode=orderdetails.productcode

You can do the following
SELECT c.CUSTOMERNAME
, o.CUSTOMERNUMBER
, od.PRICEEACH
, p.productname
FROM customers c
INNER JOIN orders o
on c.customernumber = o.customernumber
INNER JOIN ORDERDETAILS od
on o.ORDERNUMBER = od.ORDERNUMBER
INNER JOIN products p
on od.productcode = p.productcode

Here's the way to join 4 tables together--
SELECT CUST.CUSTOMERNAME
,CUST.STATE
,CUST.CREDITLIMIT
,DET.PRICEEACH,
,DET.QUANTITYORDERED
,PRD.PRODUCTNAME
FROM CUSTOMERS CUST
JOIN ORDERS ORD
ON CUST.CUSTOMERNUMBER = ORD.CUSTOMERNUMBER
JOIN ORDERDETAILS DET
ON ORD.ORDERNUMBER = DET.ORDERNUMBER
JOIN PRODUCTS PRD
ON DET.PRODUCTCODE = PRD.PRODUCTCODE;

Related

Gross sales of top ten customers that made at least 5 purchases of some Category in a specified year

I need to get (sales.customers) | year | gross_sales of top ten customers that made at least 5 purchases of Category "Beverages" in the year 2014. I have already written these SELECT queries, but since I am new to SQL, I think I am very inefficient in writing code. This does not work properly and there is probably a simpler way of doing it. I have also pinned a picture of an ER diagram .
SELECT
T6.COMPANYNAME, YEAR, GROSS_SALES
FROM
(SELECT T1.CUSTID
FROM
(SELECT R.CUSTID, COUNT(R.CUSTID) AS NUMBEROFSALES
FROM SALES.ORDERDETAILS O
RIGHT JOIN PRODUCTION.PRODUCTS P ON P.PRODUCTID = O.PRODUCTID
RIGHT JOIN SALES.ORDERS R ON R.ORDERID = O.ORDERID
INNER JOIN SALES.CUSTOMERS C1 ON R.CUSTID = C1.CUSTID
INNER JOIN PRODUCTION.CATEGORIES C2 ON P.CATEGORYID = C2.CATEGORYID
WHERE C2.CATEGORYNAME = 'Beverages' AND YEAR(R.ORDERDATE) = 2014
GROUP BY R.CUSTID
ORDER BY SUM(R.CUSTID) DESC) T1
--HAVING COUNT(R.CUSTID) > 5
RIGHT JOIN
(SELECT R.CUSTID, SUM(O.UNITPRICE) AS MONEYSPENT
FROM SALES.ORDERDETAILS O
RIGHT JOIN PRODUCTION.PRODUCTS P ON P.PRODUCTID = O.PRODUCTID
RIGHT JOIN SALES.ORDERS R ON R.ORDERID = O.ORDERID
INNER JOIN SALES.CUSTOMERS C1 ON R.CUSTID = C1.CUSTID
INNER JOIN PRODUCTION.CATEGORIES C2 ON P.CATEGORYID = C2.CATEGORYID
WHERE C2.CATEGORYNAME = 'Beverages' AND YEAR(R.ORDERDATE) = 2014
GROUP BY R.CUSTID
ORDER BY SUM(O.UNITPRICE) DESC) T2 ON T1.CUSTID = T2.CUSTID
ORDER BY T1.NUMBEROFSALES DESC
LIMIT 10) T5
INNER JOIN
(SELECT DISTINCT(T4.COMPANYNAME), T4.CUSTID, YEAR, GROSS_SALES
FROM
(SELECT R.CUSTID AS CUSTID, YEAR(R.ORDERDATE) AS YEAR, SUM(O.UNITPRICE * O.QTY * (1 - O.DISCOUNT)) AS GROSS_SALES
FROM SALES.ORDERDETAILS O
RIGHT JOIN SALES.ORDERS R ON R.ORDERID = O.ORDERID
INNER JOIN SALES.CUSTOMERS C1 ON R.CUSTID = C1.CUSTID
GROUP BY R.CUSTID, YEAR(R.ORDERDATE)
ORDER BY YEAR(R.ORDERDATE)) T3
INNER JOIN
(SELECT C.COMPANYNAME, C.CUSTID
FROM SALES.ORDERS R
INNER JOIN SALES.CUSTOMERS C ON R.CUSTID = C.CUSTID) T4 ON T3.CUSTID = T4.CUSTID) T6 ON T5.CUSTID = T6.CUSTID
I'm not going to try and fix your code or explain the misakes there, as there are many of them. Instead based on your requirements I wrote a query that solves the problem. I show it in steps below which should make clear the process I used to solve the problem.
First how do we find the top ten customers that made 5 purchases of Beverages?
Take customer table and join to orders with beverages (inner join will exclude customers that don't meet criteria)
SELECT CUSTOMERID
FROM CUSTOMERS C
JOIN ORDERS O ON C.CUSTOMERID = O.CUSTOMERID
JOIN ORDER_DETAILS OD ON O.ORDERID = OD.ORDERID
JOIN PRODUCTS P ON OD.PRODUCTID = P.PRODUCTID
JOIN CATEGORIES C ON P.CATEGORYID = C.CATEGORYID AND C. CATEGORY_NAME = 'Beverages'
WHERE YEAR(ORDER_DATE) = 2014
GROUP BY CUSTOMERID
HAVING COUNT(ORDER_DETAILS) >= 5
Now we need the sum of order (for 2014) by customers which looks like this:
SELECT CUSTOMERID, YEAR(ORDER_DATE) AS YEAR, SUM(OD.UNIT_PRICE*OD.QUANTITY) AS TOTAL_SPEND
FROM CUSTOMERS C
JOIN ORDERS O ON C.CUSTOMERID = O.CUSTOMERID
JOIN ORDER_DETAILS OD ON O.ORDERID = OD.ORDERID
WHERE YEAR(ORDER_DATE) = 2014
GROUP BY CUSTOMERID, YEAR(ORDER_DATE)
Now we just combine these two queries like this:
SELECT CUSTOMERID, YEAR(ORDER_DATE) AS YEAR, SUM(OD.UNIT_PRICE*OD.QUANTITY) AS TOTAL_SPEND
FROM CUSTOMERS C
JOIN ORDERS O ON C.CUSTOMERID = O.CUSTOMERID
JOIN ORDER_DETAILS OD ON O.ORDERID = OD.ORDERID
JOIN (
SELECT CUSTOMERID
FROM CUSTOMERS C
JOIN ORDERS O ON C.CUSTOMERID = O.CUSTOMERID
JOIN ORDER_DETAILS OD ON O.ORDERID = OD.ORDERID
JOIN PRODUCTS P ON OD.PRODUCTID = P.PRODUCTID
JOIN CATEGORIES C ON P.CATEGORYID = C.CATEGORYID AND C. CATEGORY_NAME = 'Beverages'
WHERE YEAR(ORDER_DATE) = 2014
GROUP BY CUSTOMERID
HAVING COUNT(ORDER_DETAILS) >= 5
) as SUB ON SUB.CUSTOMERID = C.CUSTOMERID
WHERE YEAR(ORDER_DATE) = 2014
GROUP BY CUSTOMERID, YEAR(ORDER_DATE)
ORDER BY SUM(OD.UNIT_PRICE*OD.QUANTITY)
LIMIT 10
Note I did not test this but just wrote the SQL since I don't have a db to test against so there might be typos
Also Note: I'm expect it is possible to remove the sub query as it is doing a lot of the same joins the outer query is-- but we want to make sure we get the correct result and it is easier to see it is correct this way. You can also test the sub-query by itself to make sure it returns expected results.

T-SQL How to select all items without relationship in many-to-many situation?

Let's say there are 3 tables:
How can I show which CustomerId did not make an order for particular SupplierId
For example: SupplierId 2 did not get orders from CustomerId 1 and 5
So far my idea is to create a Table of all possible combinations of CustomerId/SupplierId and rows that have a match in the Orders table.
Is there a better way?
You can cross join the two referrential tables to generate all possible combinations, and use not exists to filter on those that do not exists in the bridge table:
select c.customerId, s.supplierId
from customers c
cross join suppliers s
where not exists (
select 1
from orders o
where o.customerId = c.customerId and o.supplierId = s.supplierId
)
You can also do this with an anti-left join:
select c.customerId, s.supplierId
from customers c
cross join suppliers s
left join orders o
on o.customerId = c.customerId and o.supplierId = s.supplierId
where o.customerId is null

Give the name of customers who bought all products with price less than 5.(NORTHWIND)

Hi im trying to learn sql and im using the northwind test database to practice.
This is how far I have come:
select
c.CompanyName
from Customers as c
inner join Orders as O on > o.OrderID=c.CustomerID
inner join [Order Details] as OD on > od.ProductID=o.OrderID
inner join Products as p on > p.ProductID=od.ProductID
where p.UnitPrice < 5
p.s I have more querys I could use some help with if anyone is up for it
Why you are joing everything with Order ID ?
inner join Orders as O on > o.OrderID=c.CustomerID (Customer ID from both the tables should be joined here)
inner join [Order Details] as OD on od.ProductID=o.OrderID - (Order ID from master and transaction should be joined)
Yes your right, now it works thanks!
select c.CompanyName
from Customers as c
inner join Orders as O on o.CustomerID=c.CustomerID
inner join [Order Details] as OD on od.OrderID=o.OrderID
inner join Products as p on p.ProductID=od.ProductID
where p.UnitPrice > 5

Order of inner join

I was inspecting Northwind database. There is one View called 'Invoice' fairly complicated.
I tried to change the original sql (pull last inner join up, merge with the other inner join statement).
'Official' code to get invoice: (correct)
SELECT *
FROM dbo.Shippers as shipper
INNER JOIN dbo.Products as product
INNER JOIN dbo.Employees as employee
INNER JOIN dbo.Customers as customer
INNER JOIN orders as orders
ON customer.CustomerID = orders.CustomerID
ON employee.EmployeeID = orders.EmployeeID
INNER JOIN dbo.[Order Details]
ON orders.OrderID = dbo.[Order Details].OrderID
ON product.ProductID = dbo.[Order Details].ProductID
ON shipper.ShipperID = orders.ShipVia
My first try: (doesn't work)
SELECT *
FROM dbo.Shippers as shipper
INNER JOIN dbo.Products as product
INNER JOIN dbo.Employees as employee
INNER JOIN dbo.Customers as customer
INNER JOIN orders as orders
INNER JOIN dbo.[Order Details]
ON orders.OrderID = dbo.[Order Details].OrderID
ON product.ProductID = dbo.[Order Details].ProductID
ON shipper.ShipperID = orders.ShipVia
ON customer.CustomerID = orders.CustomerID
ON employee.EmployeeID = orders.EmployeeID
My second try (works):
select *
from Orders as orders
inner join Shippers as ships
on ships.ShipperID = orders.ShipVia
inner join [Order Details] as ods
on ods.OrderID = orders.OrderID
inner join Products as products
on ods.ProductID = products.ProductID
inner join Customers as customers
on customers.CustomerID = orders.CustomerID
Both of them return 2155 lines of record.
Here is a reference for Table Structure:
My question is why 'my first try' is not right ?
Also, do you think my second try is right ?
Thanks
Each ON clause is used to specify the join conditions for the most immediate preceding JOIN clause that hasn't yet had an ON specified.
So, indenting to show how they're matching up:
SELECT *
FROM dbo.Shippers as shipper
INNER JOIN dbo.Products as product
INNER JOIN dbo.Employees as employee
INNER JOIN dbo.Customers as customer
INNER JOIN orders as orders
INNER JOIN dbo.[Order Details]
ON orders.OrderID = dbo.[Order Details].OrderID
ON product.ProductID = dbo.[Order Details].ProductID
ON shipper.ShipperID = orders.ShipVia
ON customer.CustomerID = orders.CustomerID
ON employee.EmployeeID = orders.EmployeeID
And the most deeply nested JOIN will be performed first. So, whilst the inner most join seems to be correct (joining orders to Order Details with an ON clause of orders.OrderID = dbo.[Order Details].OrderID), the next one out is incorrect - we're trying to join customer to the result of the previous join (or orders and order details), but with an ON clause of product.ProductID = dbo.[Order Details].ProductID - and that's wrong because we've not joined to the product table yet.
You might try re-arranging them as:
SELECT *
FROM dbo.Shippers as shipper
INNER JOIN dbo.Products as product
INNER JOIN dbo.Employees as employee
INNER JOIN dbo.Customers as customer
INNER JOIN orders as orders
INNER JOIN dbo.[Order Details]
ON orders.OrderID = dbo.[Order Details].OrderID
ON customer.CustomerID = orders.CustomerID
ON employee.EmployeeID = orders.EmployeeID
ON product.ProductID = dbo.[Order Details].ProductID
ON shipper.ShipperID = orders.ShipVia
Where now at least each ON clause is dealing in terms of table aliases that are in scope for each join.
However, I'd usually recommend (except for complex joins) to follow a pattern of:
FROM a
INNER JOIN b
ON a.column = b.column
INNER JOIN c
ON a_or_b.column = c.column
...
Where each ON clause is kept close to the JOIN clause that it's actually specifying the conditions for, much like your second attempt. I can see no reason for trying to get all of the JOINs to occur at the top of the FROM.
in your 1st try, you didn't link Shipper to Order table.
SELECT *
FROM dbo.Shippers as shipper
INNER JOIN dbo.Products as product
INNER JOIN dbo.Employees as employee
INNER JOIN dbo.Customers as customer
INNER JOIN orders as orders
INNER JOIN dbo.[Order Details]
ON orders.OrderID = dbo.[Order Details].OrderID
ON product.ProductID = dbo.[Order Details].ProductID
ON shipper.ShipperID = orders.ShipVia
ON customer.CustomerID = orders.CustomerID
ON employee.EmployeeID = orders.EmployeeID
2ndly when you use join, you have to mention the columns of the two table on which the join will be done.
so when you join x and join y then you have to mention column of x and column of y. otherwise it will be a Cartesian product. when you make a join just immediately you have to mention the column.
in your second query, the ideal practice is link all the associated table 1st.
you can re-write it like:
select *
from Orders as orders
inner join Shippers as ships
on orders.ShipVia= ships.ShipperID
inner join Customers as customers
on orders.CustomerID = customers.CustomerID
inner join [Order Details] as ods
on orders.OrderID = ods.OrderID
inner join Products as products
on ods.ProductID = products.ProductID

Joining on a group by

Lets say that I have three tables, customers, orders and orderDetails.
I'm doing this:
SELECT orders.ordersId, sum(orderDetails.total)
FROM orders
LEFT OUTER JOIN orderDetails ON orders.ordersId = orderDetails.ordersId
GROUP BY orders.ordersId
But lets say the orders table contains customersId. How do I join on the customers table so that I can also add the customer's name to the fields selected?
Thanks,
Barry
SELECT orders.ordersId, sum(orderDetails.total), customer.name
FROM orders
LEFT OUTER JOIN orderDetails ON orders.ordersId = orderDetails.ordersId
LEFT OUTER JOIN customer on customer.customerid = orders.customerid
GROUP BY orders.ordersId , customer.name
Try that out or something similar.
you can do it this way, which will let you get more than customer name if needed:
SELECT o.ordersId, o.orderTotal, c.customername, c.(other customer data)
FROM
(
SELECT orders.ordersId
, sum(orderDetails.total) as orderTotal
, orders.customersid
FROM orders
LEFT OUTER JOIN orderDetails
ON orders.ordersId = orderDetails.ordersId
GROUP BY orders.ordersId, orders.customersid
) o
LEFT JOIN customers c
ON o.customersid = c.customersid