Insufficient output from SQL query - sql

I'm using the northwind db: http://dev.assets.neo4j.com.s3.amazonaws.com/wp-content/uploads/Northwind_diagram.jpg
I have to output all orders placed by CustomerID ALFKI with more than one unique product. I get the correct orders out, but I can't figure out why it's only printing one product name per order.
My query:
SELECT a.OrderID, p.ProductName
FROM Products p
INNER JOIN 'Order Details' a
ON (p.ProductID = a.ProductID)
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE (b.CustomerID = 'ALFKI')
GROUP BY a.OrderID
HAVING COUNT(DISTINCT a.ProductID) > 1

You need the GROUP BY and HAVING to be part of a subquery, with your primary query selecting the detail using the list of OrderIDs returned from the subquery as filter criteria. Try the following syntax for T-SQL:
SELECT
a.OrderID,
p.ProductName
FROM
Products p
INNER JOIN [Order Details] a
ON (p.ProductID = a.ProductID)
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE
a.OrderID IN
(
SELECT a.OrderID
FROM [Order Details] a
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE (b.CustomerID = 'ALFKI')
GROUP BY a.OrderID
HAVING COUNT(DISTINCT a.ProductID) > 1
)

Related

How to use select with GROUP BY clause

I have the task.
"For each order, enter the total number of units ordered and the customer's name."
Database: Microsoft SQL Server 12.0.2000.8
I write that code so far:
SELECT a.OrderID, SUM(a.Quantity), c.CompanyName FROM [Order Details] as a
INNER JOIN Orders as b ON b.OrderID = a.OrderID
INNER JOIN Customers as c ON c.CustomerID = b.CustomerID
GROUP BY a.OrderID
But i can not display CompanyName. It should be only one Company Name for each order and we do not need to concat it. How can i do that?
I enclose my database diagram.
The error you're probably getting is that all non-aggregated columns should be present in the GROUP BY clause.
So the mistake is basically in the missing CompanyName column in the GROUP BY.
The query should, thus, look like this:
SELECT
a.OrderID,
SUM(a.Quantity) as TotalQuantity,
c.CompanyName
FROM [Order Details] as a
INNER JOIN Orders as b ON b.OrderID = a.OrderID
INNER JOIN Customers as c ON c.CustomerID = b.CustomerID
GROUP BY a.OrderID, c.CompanyName
Works

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

What is 'keyword' is missing from this query?

This is what I have;
SELECT c.customerFN, c.customerEmail, p.productName,
SUM(p.unitsonstock + p.unitsordered) AS "All Units"
FROM customer c
INNER JOIN order o
WHERE c.customerID=o.customerID
INNER JOIN orderDetails d
WHERE o.orderID=d.orderID
INNER JOIN product p
WHERE p.productCode=l.productCode
WHERE orderDate <= '2015-03-15'
ORDER BY productName;
When I enter this the database throws a "missing keyword" error at the fourth line. Could you tell me what it is that I'm missing
Instead of WHERE in line 5, 7 and 9 you need to use ON. You are also using function SUM, but there is no GROUP BY. Change your query like this:
SELECT c.customerFN, c.customerEmail, p.productName,
SUM(p.unitsonstock + p.unitsordered) AS "All Units"
FROM customer c
INNER JOIN order o
ON c.customerID=o.customerID
INNER JOIN orderDetails d
ON o.orderID=d.orderID
INNER JOIN product p
ON p.productCode=l.productCode
WHERE orderDate <= '2015-03-15'
GROUP BY c.customerFN, c.customerEmail, p.productName
ORDER BY p.productName;
JOIN is performed using the ON clause, not with a WHERE:
...
FROM customer c
INNER JOIN order o ON c.customerID=o.customerID
INNER JOIN orderDetails d ON o.orderID=d.orderID
INNER JOIN product p ON p.productCode=d.productCode
WHERE orderDate <= '2015-03-15'
...
The WHERE clause that comes after join should be used like you have it in your query.
Apart from the problem with the JOIN there is also a problem using SUM without grouping. You probably want something like:
SELECT c.customerFN, c.customerEmail, p.productName,
SUM(p.unitsinstock + p.unitsordered) AS "All Units"
FROM customer c
INNER JOIN order o ON c.customerID=o.customerID
INNER JOIN orderDetails d ON o.orderID=d.orderID
INNER JOIN product p ON p.productCode=d.productCode
WHERE orderDate <= '2015-03-15'
GROUP BY customerFN, customerEmail, productName
ORDER BY p.productName;
Use of SUM function implies a GROUP BY clause. Every column selected that is not part of an aggregate function like SUM must be present in the GROUP BY clause.

SQL query with w3schools db

I should have asked multiple questions in my other post. Thanks to all who have helped, I am now stuck on another one..
Using the w3schools db, List SupplierID, SupplierName and ItemSupplied (count of number of items supplied by a supplier), sort the list first by number of items supplied (descending) and then by supplier name (ascending)
SELECT supplierid,
suppliername,
p.productname,
Count(s.supplierid) AS itemssupplied
FROM [Suppliers] AS s
INNER JOIN [Products] AS p
ON p.supplierid = s.supplierid
GROUP BY p.productid,
p.productname
ORDER BY Count (p.productid, p.productname) DESC
order BY s.suppliername
It's giving me an error, then again I am ordering by multiple ones. I think there's something I am not quite understanding here.
My other question is
List customers for each category and the total of order placed by that customer in a given category. In the query show three columnm: CategoryName, CustomerName, and TotalOrders (which is price * quantity for orders for a given customer in a given category). Sort this data in descending order by TotalOrders.
SELECT cg.CategoryName,
c.CustomerName,
Sum(p.Price * od.Quantity) AS TotalOrders
FROM [products] AS p
INNER JOIN [orderdetails] AS od
ON od.ProductID = p.ProductID
INNER JOIN [orders] AS o
ON o.OrderID = od.OrderID
INNER JOIN [customers] AS c
ON c.customerID = o.CustomerID
INNER JOIN [categories] AS cg
ON cg.CategoryID = p.CategoryID
GROUP BY c.CustomerName
ORDER BY TotalOrders DESC
Can someone please check if my query is correct? Thank you once again!
Question 1
You are really close but you only need to state ORDER BY once (also make sure to include all shown fields in your GROUP BY unless you are aggregating them):
SELECT SupplierID, SupplierName, p.ProductName, count(s.SupplierID) AS ItemsSupplied
FROM [Suppliers] AS s
INNER JOIN [Products] AS p ON p.SupplierID = s.SupplierID
GROUP BY p.ProductID, p.ProductName, SupplierID, SupplierName -- Added SupplierID, SupplierName
ORDER BY COUNT (p.productID, p.ProductName) DESC, s.SupplierName
Notice that you just place multiple sorts on the same line with a comma separating them.
Question 2
You're almost there but you need to group by any field that is not being aggregated. So in order not to get a parsing error, I added the cg.CategoryName to the GROUP BY line.
SELECT cg.CategoryName, c.CustomerName, Sum(p.Price*od.Quantity) AS TotalOrders
FROM [Products] AS p
INNER JOIN [OrderDetails] AS od ON od.ProductID = p.ProductID
INNER JOIN [Orders] AS o ON o.OrderID = od.OrderID
INNER JOIN [Customers] AS c ON c.customerID = o.CustomerID
INNER JOIN [Categories] AS cg ON cg.CategoryID = p.CategoryID
GROUP BY c.CustomerName, cg.CategoryName --Added CategoryName
ORDER BY TotalOrders DESC
You have several problems with the first query:
You're grouping by ProductID and ProductName even though you want the number of items supplied by a supplier, which means that you want to group by SupplierID and SupplierName.
You're supplying too many arguments to the COUNT function, which takes a single column name or *.
You've included a ProductName column in your results, which is not called for.
You need to ORDER BY both the number of products supplied and the SupplierName.
With those points in mind:
SELECT
s.SupplierID,
s.SupplierName,
COUNT(p.ProductID) AS ItemsSupplied
FROM
[Suppliers] AS s
INNER JOIN [Products] AS p ON p.SupplierID = s.SupplierID
GROUP BY
s.SupplierID, s.SupplierName
ORDER BY
ItemsSupplied DESC,
s.SupplierName ASC
Your second query is quite close, you're just missing one point, which is that you're looking for total of order placed by that customer in a given category. This means that in addition to grouping by c.CustomerName, you need to group by cg.CategoryID:
SELECT
cg.CategoryName,
c.CustomerName,
SUM(p.Price*od.Quantity) AS TotalOrders
FROM
[Products] AS p
INNER JOIN [OrderDetails] AS od ON od.ProductID = p.ProductID
INNER JOIN [Orders] AS o ON o.OrderID = od.OrderID
INNER JOIN [Customers] AS c ON c.customerID = o.CustomerID
INNER JOIN [Categories] AS cg ON cg.CategoryID = p.CategoryID
GROUP BY
c.CustomerName, cg.CategoryID
ORDER BY
TotalOrders DESC
The first one has two order by clauses
ORDER BY COUNT (p.productID, p.ProductName) DESC
and
ORDER BY s.SupplierName
also some databases will complain when order by columns for queries using group by are not included in the selected columns

SQL Change output of column if duplicate

I have a table which has rows for each product that a customer has purchased. I want to output a column from a SELECT query which shows the time it takes to deliver said item based on whether the customer has other items that need to be delivered. The first item takes 5 mins to deliver and all subsequent items take 2 mins to deliver e.g. 3 items would take 5+2+2=9 mins to deliver.
This is what I have at the moment(Using the Northwind sample database on w3schools to test the query):
SELECT orders.customerid,
orders.orderid,
orderdetails.productid,
CASE((SELECT Count(orders.customerid)
FROM orders
GROUP BY orders.customerid))
WHEN 1 THEN '00:05'
ELSE '00:02'
END AS DeliveryTime
FROM orders
LEFT JOIN orderdetails
ON orderdetails.orderid = orders.orderid
This outputs '00:05' for every item due to the COUNT in my subquery(I think?), any ideas on how to fix this?
Try this
SELECT orders.customerid,
orders.orderid,
orderdetails.productid,
numberorders,
2 * ( numberorders - 1 ) + 5 AS deleveryMinutes
FROM orders
INNER JOIN (SELECT orders.customerid AS countId,
Count(1) AS numberOrders
FROM orders
GROUP BY orders.customerid) t1
ON t1.countid = orders.customerid
LEFT JOIN orderdetails
ON orderdetails.orderid = orders.orderid
ORDER BY customerid
Gregory's answer works a treat and here's my attempts
-- Without each product line item listed
SELECT O.CustomerId,
O.OrderId,
COUNT(*) AS 'NumberOfProductsOrderd',
CASE COUNT(*)
WHEN 1 THEN 5
ELSE (COUNT(*) * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
GROUP BY O.CustomerId, O.OrderId
-- Without each product line item listed
SELECT O.CustomerId,
O.OrderId,
D.ProductId,
CASE
WHEN P.ProductsInOrder = 1 THEN 5
ELSE (P.ProductsInOrder * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
INNER JOIN (
SELECT OrderId, COUNT(*) AS ProductsInOrder
FROM OrderDetails
GROUP BY OrderId
) AS P ON P.OrderId = O.OrderId
GROUP BY O.CustomerId,
O.OrderId,
D.ProductId,
P.ProductsInOrder
Final code is below for anyone interested:
SELECT O.CustomerId,
O.OrderId,
Group_Concat(D.ProductID) AS ProductID,
CASE COUNT(*)
WHEN 1 THEN 5
ELSE (COUNT(*) * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
GROUP BY O.CustomerId