Order of inner join - sql

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

Related

I am getting this error ORA-00907: missing right parenthesis and cant find a way to fix

im in university and i have a exercise where im having a hard time finding a solution.
The question is: "Present a list with the amount of different products present in each purchase order made for customers in Norway (Norway)."
I tried this code:
SELECT ORDERS.ORDERID, COUNT(PRODUCTS.PRODUCTSID) AS NUMPRODUCTS
FROM PRODUCTS GROUP BY ORDERS.ORDERID
INNER JOIN ORDERSDETAILS ON PRODUCTS.PRODUCTID=ORDERDETAILS.PRODUCTID
INNER JOIN ORDERS ON ORDERDETAILS.ORDERID=ORDERS.ORDERID
INNER JOIN CUSTOMERS ON ORDERS.CUSTOMERSID=CUSTOMERS.CUSTOMERSID
WHERE (CUSTOMERS.COUNTRY='Norway');
But it gives me a error ORA-00907: missing right parenthesis.
Can you tell me what is the error in the code?
Parenthesis isn't missing; that's a misleading error message. True problem is in clauses' order; group by should go to the end of that query:
SELECT
orders.orderid,
COUNT(products.productsid) AS numproducts
FROM
products
INNER JOIN ordersdetails ON products.productid = orderdetails.productid
INNER JOIN orders ON orderdetails.orderid = orders.orderid
INNER JOIN customers ON orders.customersid = customers.customersid
WHERE ( customers.country = 'Norway' )
GROUP BY orders.orderid; --> here
I recommend using careful code layout as a first step in tracing syntax errors.
Failing code, laid out neatly:
select o.orderid
, count(p.productsid) as numproducts
from products p
group by o.orderid -- error now a bit more obvious
join ordersdetails d on d.productid = p.productid
join orders o on o.orderid = d.orderid
join customers c on c.customersid = o.customersid
where c.country = 'Norway';
Now easily fixed as:
select o.orderid
, count(p.productsid) as numproducts
from products p
join ordersdetails d on d.productid = p.productid
join orders o on o.orderid = d.orderid
join customers c on c.customersid = o.customersid
where c.country = 'Norway'
group by o.orderid;

INTERSECT between two pseudo (derived) tables in Microsoft SQL server

I'm trying to find out whether there are any differences between two pseudo tables with one column (see if every element in one table is in the other)
Code:
SELECT *
FROM
(SELECT Orders.OrderID
FROM (((Categories FULL OUTER JOIN Products on Categories.CategoryID = Products.CategoryID)
FULL OUTER JOIN OrderDetails on OrderDetails.ProductID = Products.ProductID)
FULL OUTER JOIN Orders on Orders.OrderID = OrderDetails.OrderID)
FULL OUTER JOIN Suppliers on Suppliers.SupplierID = Products.SupplierID
WHERE CategoryName LIKE 'Dairy%' AND country ='France')
INTERSECT
(SELECT Orders.OrderID
FROM (((Categories LEFT JOIN Products on Categories.CategoryID = Products.CategoryID)
LEFT JOIN OrderDetails on OrderDetails.ProductID = Products.ProductID)
LEFT JOIN Orders on Orders.OrderID = OrderDetails.OrderID)
LEFT JOIN Suppliers on Suppliers.SupplierID = Products.SupplierID
WHERE CategoryName LIKE 'Dairy%' AND country ='France')
eg of output:
Top part of query gives for first three results:
OrderID
10255
10267
10275
Second part of code (below INTERSECT) gives:
OrderID
10255
10267
10275
Now for some reason the code is not running with the intersection. The code works separately to give me the individual columns for the sub query above and below the INSERSECT, but in its entirety it just doesn't work. Error message I get is:
Msg 156, Level 15, State 1, Line 10
Incorrect syntax near the keyword 'INTERSECT'.
Completion time: 2022-05-23T14:10:06.3560367+01:00
Any idea how to fix this? If it helps, the INTERSECT is underlined red.
Thanks.
Just remove the FROM and the outer parenthesis, like this:
SELECT Orders.OrderID
FROM (((Categories FULL OUTER JOIN Products on Categories.CategoryID = Products.CategoryID)
FULL OUTER JOIN OrderDetails on OrderDetails.ProductID = Products.ProductID)
FULL OUTER JOIN Orders on Orders.OrderID = OrderDetails.OrderID)
FULL OUTER JOIN Suppliers on Suppliers.SupplierID = Products.SupplierID
WHERE CategoryName LIKE 'Dairy%' AND country ='France'
INTERSECT
SELECT Orders.OrderID
FROM (((Categories LEFT JOIN Products on Categories.CategoryID = Products.CategoryID)
LEFT JOIN OrderDetails on OrderDetails.ProductID = Products.ProductID)
LEFT JOIN Orders on Orders.OrderID = OrderDetails.OrderID)
LEFT JOIN Suppliers on Suppliers.SupplierID = Products.SupplierID
WHERE CategoryName LIKE 'Dairy%' AND country ='France'
The issue is that you have a FROM Clause attempting to run 2 sub selects enclosed within parenthesis.
SELECT
*
FROM
(SELECT 1 AS a)
Yields an error:
Msg 102, Level 15, State 1, Line 4
Incorrect syntax near ')'.
Adding an alias, however, works fine:
SELECT
*
FROM
(SELECT 1 AS a) as a
Update:
You only have to alias the first query:
SELECT
*
FROM
(SELECT 1 AS a) as a
INTERSECT
(SELECT 1 AS a)
Or, as suggested by RBarryYoung, remove the parenthesis altogether.
Simply putting an x before the INTERSECT works. i.e.:
SELECT *
FROM
(SELECT Orders.OrderID
FROM (((Categories FULL OUTER JOIN Products on Categories.CategoryID = Products.CategoryID)
FULL OUTER JOIN OrderDetails on OrderDetails.ProductID = Products.ProductID)
FULL OUTER JOIN Orders on Orders.OrderID = OrderDetails.OrderID)
FULL OUTER JOIN Suppliers on Suppliers.SupplierID = Products.SupplierID
WHERE CategoryName LIKE 'Dairy%' AND country ='France') x
INTERSECT
(SELECT Orders.OrderID
FROM (((Categories LEFT JOIN Products on Categories.CategoryID = Products.CategoryID)
LEFT JOIN OrderDetails on OrderDetails.ProductID = Products.ProductID)
LEFT JOIN Orders on Orders.OrderID = OrderDetails.OrderID)
LEFT JOIN Suppliers on Suppliers.SupplierID = Products.SupplierID
WHERE CategoryName LIKE 'Dairy%' AND country ='France')

how to join 4 tables together in 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;

Query returns cartesian product when not expected

Task: Select all orders having products belonging to ‘Sea Food’ category.
Result: OrderNo, OrderDate, Product Name
I write this query but it returns Cartesian products.
select o.orderid, o.orderdate as "Order Date", p.productname , ct.categoryname from orders o,
order_details od , products p , customers c ,categories ct
where
od.orderid = o.orderid and p.productid = od.productid and ct.categoryid = p.categoryid
and ct.categoryname = 'Seafood';
Question: What is wrong with my query ?
You're doing a CROSS JOIN on customers table since you forgot to specify the connection. This is why you should use explicit JOIN syntax rather than old syntax using commas in WHERE clause.
After translating your query into explicit syntax, you will see that there is no WHERE condition involving customers table:
select
o.orderid,
o.orderdate as "Order Date",
p.productname,
ct.categoryname
from
orders o,
inner join order_details od on od.orderid = o.orderid
inner join products p on p.productid = od.productid
inner join categories ct on ct.categoryid = p.categoryid
cross join customers c -- either you don't need this table, or you need to specify conditions
where
ct.categoryname = 'Seafood'
Basically the reason you got it was that your where clause omitted join condition involving customers table, so you were left with:
from (...), customers -- cross join when joining condition not applied in where clause

2 Questions on Northwind SQL

I have 2 questions about the Northwind SQL Server sample database that I don't know how to solve
Show CustomerID for all customers who have at least three different products, but never use both products in the same category.
Code I tried for this question:
SELECT
CustomerID, p.ProductID,ProductName, CategoryID
FROM
(Orders o
JOIN
[Order Details] od ON o.OrderID = od.OrderID)
JOIN
Products p ON od.ProductID = p.ProductID
Show CustomerID for customers who have orders from all categories.
I've been stuck on these queries for hours, please help guys!
This is link for Northwind sample database: https://northwinddatabase.codeplex.com/
For #2, you could use something like this:
SELECT
c.CustomerID, COUNT(DISTINCT p.CategoryID)
FROM
dbo.Customers c
INNER JOIN
dbo.Orders o ON o.CustomerID = c.CustomerID
INNER JOIN
dbo.[Order Details] od ON od.OrderID = o.OrderID
INNER JOIN
dbo.Products p ON p.ProductID = od.ProductID
GROUP BY
c.CustomerID
HAVING
COUNT(DISTINCT p.CategoryID) = (SELECT COUNT(*) FROM dbo.Categories)
This works for question #1:
SELECT c.CustomerID,
od.productid,
p.ProductName,
COUNT(od.productid),
ct.Category
FROM [Order Details] od
INNER JOIN [dbo].[Products] p on od.ProductID = p.ProductID
INNER JOIN [dbo].[Categories] ct on p.CategoryID = c.CategoryID
INNER JOIN [dbo].[Orders] o on od.OrderID = o.OrderID
INNER JOIN [dbo].[Customers] c on o.CustomerID = c.CustomerID
GROUP BY od.productid,
ct.CategoryID,
p.ProductName,
c.CustomerID
HAVING COUNT(od.productid) > 3
ORDER BY COUNT(od.productid) desc
;