Subquery automatically producing cross join - sql

I am not certain WHY but when I follow the example (from the northwind datase in a ms sql server) to do a subquery on Microsoft SQL Server Management Studio 2008 by typing in the code like shown below,
Select Orders.OrderID,
(Select Customers.CompanyName
From Customers
Where Customers.CustomerID = Orders.CustomerID) As Company Name
From Orders,
Customers
This sql code with subquery automatically gained a cross join and become
Select Orders.OrderID,
(Select Customers.CompanyName
From Customers
Where Customers.CustomerID = Orders.CustomerID) As Company Name
From Orders
CROSS JOIN Customers as Customers_1
I have played around with several variation of this but with no luck in eliminating this problem. Is this a known bug for microsoft sql server management studio 2008? If so, has it been patched, how do I find the patched? Otherwise, how can I report this to Microsoft and get them to really fixed it quickly?
In my actual query, I need to query/lookup the name of this particular table about 50 times by equating the ID and I think it is simply dumb having to do a JOIN of any sort for this because the code is crumpy, VERY long, and performance may be poor?

The subquery isn't causing the cross join, the lack of a condition controlling the join is. You need something like this:
Select Orders.OrderID, (Select Customers.CompanyName From Customers Where Customers.CustomerID = Orders.CustomerID) As Company Name
From Orders, Customers
Where Orders.CustomerID = Customers.CustomerID

I don't know why a sub-query is suggested by your book -- I would do it like this:
Select Orders.OrderID, Customers.CompanyName
From Orders
left join Customers on Customers.CustomerID = Orders.CustomerID

Looks like it should be a correlated-subquery
Select Orders.OrderID,
(Select Customers.CompanyName
From Customers
Where **Customers.CustomerID = Orders.CustomerID**) As Company Name
From Orders
--,
-- Customers
Why would you need Customers again when the inner Correlated Subquery brings the customer Name for each Order that is processed?
The Management Studio's insistence on adding CROSS JOIN is a warning that you are doing something strange. Trying to query two tables: Customer,Orders without any join condition.
Also, the query optimizer will usually convert these correlated sub-queries into joins during processing, but you can use the clearer syntax where appropriate.
Where is it appropriate? Particularly if you need to generate some sort of aggregate on the inner query.

Related

SQL - When & How to filter with JOIN

Suppose I have two tables.. One is customers and the other is orders. Orders has a foreign key that joins to the customers table. How should I go about returning data from both tables:
Filtered on a field in the orders table and,
Filtered on a field in the customers table?
Is using WHERE to filter after the JOIN in my SELECT statement the correct way to go, or putting in an AND within the JOIN statement? And would I have to use one method for one of the above situations and the other for the other one?
For example,
SELECT customers.customer_type, orders.grant_date
FROM orders
JOIN customers ON customers.customer_id = orders.customer_id
WHERE orders.order_id = 3;
or
SELECT customers.customer_type, orders.grant_date
FROM orders
JOIN customers ON customers.customer_id = orders.customer_id
AND orders.order_id = 3;
I guess I can summarize my questions as:
a. Which table should I pair with my FROM statement? Should it be the one which has the foreign key i.e. orders? Or does it depend on the situation?
b. How should I filter the data? With a WHERE or an AND with the JOIN? And how is one different from the other i.e. when should I use one over the other in my two situations?
It doesn't matter whether you do
FROM orders
JOIN customers ON customers.customer_id = orders.customer_id
or
FROM customers
JOIN orders ON customers.customer_id = orders.customer_id
Which table you make the first table is up to you. Here I would make orders the first table, because it is orders along with their customer information you are showing in your results.
With an inner join it doesn't make a difference either, whether you put criteria in your WHERE clause or ON clause.
However, it looks strange to join customers on a condition on orders:
JOIN customers ON customers.customer_id = orders.customer_id AND orders.order_id = 3
This is not how an ON clause is supposed to work. So either:
FROM orders
JOIN customers ON customers.customer_id = orders.customer_id
WHERE orders.order_id = 3
or
FROM customers
JOIN orders ON customers.customer_id = orders.customer_id
WHERE orders.order_id = 3
or
FROM customers
JOIN orders ON customers.customer_id = orders.customer_id AND orders.order_id = 3
Many people prefer the last query over the second last, because you can easily convert the inner join into an outer join. So the general advice is: put criteria on the first table in WHERE and the criteria on other tables in ON. Make this a rule of thumb.
I my experience with SQL, when using an inner join (aka. join ), order of tables after the FROM clause has never made a difference in results. Also, it has not made any difference if I used a 'where' clause or an 'and' clause after the join. But this behavior is limited ONLY and ONLY to Inner joins. If you are using left or right joins, the order as well as Where/And clauses make a lot of difference in the results returned.
I'd like to add that if you have a lot of nulls in your keys(which should never be the case), that might affect the result set in inner joins when switching between Where and And or changing the sequence of tables after from.

SQL Query with the Northwind database (Catch: no Inner Join)

First and foremost - it is a homework assignment, yet I am not asking for anyone to do it. Instead I need help with how to construct the query.
As part of an assignment, using the Northwind database via Microsoft Access, I have to construct this query:
The product ID, product name, and quantity ordered for all products ordered on an order taken by an employee with last name Fuller.
Now, when I construct the query in design mode, this is the code I get:
SELECT Products.ProductID, Products.ProductName, [Order Details].Quantity
FROM Products INNER JOIN ((Employees INNER JOIN Orders ON Employees.EmployeeID = Orders.EmployeeID) INNER JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID) ON Products.ProductID = [Order Details].ProductID
WHERE (((Employees.LastName)="Fuller"));
As I mentioned earlier, we are not allowed to use Inner Join. After scouring the text/notes thus far I can't find how to go about it. (Very new to SQL)
Would I be rewriting the FROM statement? And if so, do the SELECT and WHERE statements change?
UPDATE: Here is the code as I rewrote it:
SELECT Orders.OrderID, Orders.CustomerID, Orders.ShipCity
FROM Products, Orders, [Order Details], Employees
WHERE
Products.ProductID = [Order Details].ProductID
AND Employees.EmployeeID = Orders.EmployeeID
AND Ordes.OrderID = [Order Details].OrderID
AND Employees.LastName = "Fuller";
I'm having a sort of syntax issue though. Since the Order Details must be enclosed in brackets, it wants to ask for parameter values for what I wrote in the WHERE statement.
The requirement not to use INNER JOIN is a little peculiar and I cannot guarantee this is what was intended for your assignment.
One way to alternatively write a simplistic relationship between two tables is with an IN () subquery, the general form being:
SELECT *
FROM a_table
WHERE some_column IN (
SELECT some_related_column
FROM b_table
WHERE some_condition
)
But since you must represent columns from more than one of your 4 tables in the SELECT list, that form isn't going to work for you. Another way of not explicitly using an INNER JOIN is to use the older implicit joining syntax, in which multiple tables are listed in the FROM clause separated by commas, and their joining conditions placed in the WHERE clause instead of in ON.
The general form is:
SELECT
a_table.col1,
a_table.col2,
b_table.col1
FROM
a_table,
b_table
WHERE
a_table.some_column = b_table.some_related_column
AND some_other_conditions
It being an assignment, I will leave it to you to work out the entire statement, but yours would take a form like
SELECT
Orders.OrderID,
Orders.CustomerID
FROM
Products,
Orders,
[Order Details],
Employees
WHERE
Products.ProductID = [Order Details].ProductID
AND ... (the other table relationships)
AND Employees.LastName = 'Fuller'
Although it is functionally identical to explicit INNER JOINs, this is an older syntax, and is often discouraged nowadays. More discussion is available in this question

A simple nested SQL statement

I have a question in SQL that I am trying to solve. I know that the answer is very simple but I just can not get it right. I have two tables, one with customers and the other one with orders. The two tables are connected using customer_id. The question is to list all the customers that did not make any order! The question is to be run in MapInfo Professional, a GIS desktop software, so not every SQL command is applicable to that program. In other words, I will be thankful if I get more than approach to solve that problem.
Here is how I have been thinking:
SELECT customer_id
from customers
WHERE order_id not in (select order_id from order)
and customer.customer_id = order.customer_id
How about this:
SELECT * from customers
WHERE customer_id not in (select customer_id from order)
The logic is, if we don't have a customer_id in order that means that customer has never placed an order. As you have mentioned that customer_id is the common key, hence above query should fetch the desired result.
SELECT c.customer_id
FROM customers c
LEFT JOIN orders o ON (o.customer_id = c.customer_id)
WHERE o.order_id IS NULL
... The NOT EXISITS way:
SELECT * FROM customers
WHERE NOT EXISTS (
SELECT * FROM orders
WHERE orders.customer_id = customer.customer_id
)
There are some problems with your approach:
There is probably no order_id in the customers table, but in your where-statement you refer to it
The alias (or table-name) order in the where-statement (order.customer_id) is not known because there is no join statement in there
If there would be a join, you would filter out all customers without orders, exactly the opposite of what you want
Your question is difficualt to answer to me because I do not know which SQL subset MapInfo GIS understands, but lets try:
select * from customers c where not exists (select * from order o where o.customer_id=c.customer_id)

Difference b/w putting condition in JOIN clause versus WHERE clause

Suppose I have 3 tables.
Sales Rep
Rep Code
First Name
Last Name
Phone
Email
Sales Team
Orders
Order Number
Rep Code
Customer Number
Order Date
Order Status
Customer
Customer Number
Name
Address
Phone Number
I want to get a detailed report of Sales for 2010. I would be doing a join. I am interested in knowing which of the following is more efficient and why ?
SELECT
O.OrderNum, R.Name, C.Name
FROM
Order O INNER JOIN Rep R ON O.RepCode = R.RepCode
INNER JOIN Customer C ON O.CustomerNumber = C.CustomerNumber
WHERE
O.OrderDate >= '01/01/2010'
OR
SELECT
O.OrderNum, R.Name, C.Name
FROM
Order O INNER JOIN Rep R ON (O.RepCode = R.RepCode AND O.OrderDate >= '01/01/2010')
INNER JOIN Customer C ON O.CustomerNumber = C.CustomerNumber
JOINs must reflect the relationship aspect of your tables. WHERE clause, is a place where you filter records. I prefer the first one.
Make it readable first, table relationships should be obvious (by using JOINs), then profile
Efficiency-wise, the only way to know is to profile it, different database have different planner on executing the query
Wherein some database might apply filter first, then do the join subsquently; some database might join tables blindly first, then execute where clause later. Try to profile, on Postgres and MySQL use EXPLAIN SELECT ..., in SQL Server use Ctrl+K, with SQL Server you can see which of the two queries is faster relative to each other

SQLITE INNERJOIN Nightmare, need a solution to this

It's nice to find such a useful site with genius members. I have been trying to find a solution for this SQLITE problem for a while now. Google didn't help me, except in finding this website. The SQL query works fine on the MSAccess version of the same database.
Here's my SQL statement - which didn't work for me.
SELECT Invoices.InvoiceNumber, Invoices.Quantity,Invoices.Code, Invoices.Price,Invoices.Discount, Invoices.InvoiceGrandTotal, Employees.EmployeeName, Customers.CustomerName, Invoices.DateOfInvoice, [price]*[Quantity] AS Total, Customers.Address, Products.Description,Products.Unit
FROM Products
INNER JOIN (
(
( Invoices INNER JOIN InvoiceDetails
ON Invoices.InvoiceNumber = InvoiceDetails.InvoiceNumber
) INNER JOIN Customers
ON Invoices.CustomerID = Customers.CustomerID
) INNER JOIN Employees
ON Invoices.UserID = Employees.EmployeeID
) ON Products.Code = InvoiceDetails.Code
WHERE (((InvoiceDetails.InvoiceNumber)='10111'));
The error message is: "Cannot compile Select-Statement: no such column: Invoices.InvoiceNumber"
That usually just means that you mis-spelled the column name ... check your Invoices table and make sure the column is InvoiceNumber and not "Invoice_Number" or something similar ...
Also, a much simpler version of this query would look something like this .. without all the strange nesting:
SELECT
Invoices.InvoiceNumber,
Invoices.Quantity,
Invoices.Code,
Invoices.Price,
Invoices.Discount,
Invoices.InvoiceGrandTotal,
Employees.EmployeeName,
Customers.CustomerName,
Invoices.DateOfInvoice,
[price]*[Quantity] AS Total,
Customers.Address,
Products.Description,
Products.Unit
FROM
Invoices
JOIN Employees
ON Employees.EmployeeID = Invoices.UserID
JOIN Customers
ON Customers.CustomerID = Invoices.CustomerID
JOIN InvoiceDetails
ON InvoiceDetails.InvoiceNumber = Invoices.InvoiceNumber
JOIN Products
ON Products.Code = InvoiceDetails.Code
WHERE
InvoiceDetails.InvoiceNumber = '10111'
I think the issue might be with case sensitivity. Unless I'm mistaken, MS Access field names are not case sensitive. Check the offending column name for the correct casing in you SQLITE table definition.