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

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')

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;

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;

LEFT JOIN vs Stacked Left Join

I wanted to ask whats the difference between those two queries:
SELECT
Customers.CustomerID, Customers.CustomerName, Orders.OrderID,
OrderDetails.Quantity, Products.ProductName
FROM
Customers
LEFT JOIN
(Orders
LEFT JOIN
(OrderDetails
LEFT JOIN
Products ON Products.ProductID = OrderDetails.ProductID
) ON OrderDetails.OrderID = Orders.OrderID
) ON Customers.CustomerID = Orders.CustomerID
GROUP BY
Customers.CustomerName;
Vs
SELECT
Customers.CustomerID, Customers.CustomerName, Orders.OrderID,
OrderDetails.Quantity, Products.ProductName
FROM
Customers
LEFT JOIN
Orders ON Orders.CustomerID = Customers.CustomerID
LEFT JOIN
OrderDetails ON OrderDetails.OrderID = Orders.OrderID
LEFT JOIN
Products ON Products.ProductID = OrderDetails.ProductID
GROUP BY
Customers.CustomerName;
Tested here
https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_join
From what I can see one selects the first of multiple entries, one selects the last of multiple entries, but is that all?
From my point of view the not nested LEFT Join is way easier to read and to understand. Is there any downside of using it?
Your problem is the incorrect use of GROUP BY. The only unaggregated columns in the SELECT should be in the GROUP BY.
The rest of this answer addresses the point about joins.
Your second query is interpreted as:
FROM (((Customers c LEFT JOIN
Orders o
ON o.CustomerID = c.CustomerID
) LEFT JOIN
OrderDetails
ON od.OrderID = o.OrderID
) LEFT JOIN
Products p
ON p.ProductID = od.ProductID
The parentheses can affect the interpretation. But what effect? Essentially, you have:
(((c left join o) left join od) left join p)
versus
c left join (o left join (od left join p)))
Both keep all records in c, regardless of matches in the second. In this case, the two versions do the same thing. But for a particular reason -- the on conditions are strictly chained (that is, c to o, o to od, od to p). If p where joined to o instead of od, then subtle differences can occur.
What are the subtle differences? Two things can differ:
Whether columns from a particular table are NULL or have values.
Whether rows get duplicated, due to multiple matches between two tables.
In practice, I don't fine parentheses particularly useful. If I can about JOIN order, I use an explicit subquery or CTE>

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