How to use select with GROUP BY clause - sql

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

Related

Not in aggregate function or group by clause: org.hsqldb.Expression#59bcb2b6 in statement

I'm trying to group SUM(OrderDetails.Quantity) but keep getting the error Not in aggregate function or group by clause: org.hsqldb.Expression#59bcb2b6 in statement but since I already have an GROUP BY part I don't know what I'm missing
SQL Statement:
SELECT OrderDetails.CustomerID, Customers.CompanyName, Customers.ContactName, SUM(OrderDetails.Quantity)
FROM OrderDetails INNER JOIN Customers ON OrderDetails.CustomerID = Customers.CustomerID
WHERE OrderDetails.CustomerID = Customers.CustomerID
GROUP BY OrderDetails.CustomerID
ORDER BY OrderDetails.CustomerID ASC
I'm trying to create a table that shows customers and the amount of products they ordered, while also showing their CompanyName and ContactName.
Write this:
GROUP BY OrderDetails.CustomerID, Customers.CompanyName, Customers.ContactName
Unlike in MySQL, PostgreSQL, and standard SQL, in most other SQL dialects, it is not sufficient to group only by the primary key if you also want to project functionally dependent columns in the SELECT clause, or elsewhere. You have to explicitly GROUP BY all of the columns that you want to project.
Don't take the customer id from the orders table. Take it from the customers table. If you do so, this might work in your database:
SELECT c.CustomerID, c.CompanyName, c.ContactName, SUM(od.Quantity)
FROM OrderDetails od INNER JOIN
Customers c
ON od.CustomerID = c.CustomerID
GROUP BY c.CustomerID
ORDER BY c.CustomerID ASC;
Note that the WHERE clause does not need to repeat the conditions in the ON clause.
Your version won't work in standard SQL because od.CustomerId is not unique in OrderDetails. Many databases don't support this, so in these you need the additional columns:
SELECT c.CustomerID, c.CompanyName, c.ContactName, SUM(od.Quantity)
FROM OrderDetails od INNER JOIN
Customers c
ON od.CustomerID = c.CustomerID
GROUP BY c.CustomerID, c.CompanyName, c.ContactName
ORDER BY c.CustomerID ASC;
Even so, it is much, much better to take all columns from the same table. That would allow the SQL optimizer to use indexes on Customers.

COUNT with LEFT JOIN

Two tables named Sales.Customers and Sales.Orders.
Sales.Customers has a foreign key relationship to a column
named CustomerID in Sales.Orders.
Requirement: A query that returns all the customers. The query must also return the number of orders that each customer placed.
Query 1:
SELECT cust.cutomername,
NumberofOrders= COUNT(ord.OrderID)
FROM Sales.Customers Cust
LEFT JOIN
Sales.Orders Ord
ON Cust.CustomerID=Ord.OrderID
GROUP BY
Cust.CutomerName;
But I'm thinking of below one also,
Query2:
SELECT cust.cutomername,
NumberofOrders= COUNT(Cust.cutomerID)
FROM Sales.Customers Cust
LEFT JOIN
Sales.Orders Ord
ON Cust.CustomerID=Ord.OrderID
GROUP BY
Cust.CutomerName;
From both which one do you recommend & why?
This query:
SELECT c.customername, COUNT(o.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.OrderID
GROUP BY c.CustomerName;
Probably returns all customers with meaningless counts -- probably 0 except for OrderIDs that happen to match CustomerIDs.
You probably intend:
SELECT c.customername, COUNT(o.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.CustomerId
GROUP BY c.CustomerName;
In this query, the COUNT() is counting the number of matching orders. It can take the value of 0 for customers with no orders.
For this query:
SELECT c.customername, COUNT(c.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerName;
The COUNT() is returning the number of rows. Every customer has at least one row, so the value would never be 0. Normally, you want the previous query.
Maybe this is your solution:
select c.Customername,
NumberOfOrders = (select count(o.OrderID) from Sales.Orders o where o.CustomerID = c.CustomerID)
from Sales.Customers c
order by c.Customername

Creating a table view for invoice - Northwind

I have a little problem with my last tasks. I am using an old Northwind database.
First, I had to create a query, that will give me all the important information for the invoice. My query looks like this:
SELECT b.OrderID,
b.CustomerID,
c.CompanyName,
c.Address,
c.City,
c.PostalCode,
c.CountryID as CustomersCountryID,
concat(d.FirstName, ' ', d.LastName) as Salesperson,
a.CompanyName as ShippingVia,
e.ProductID,
f.ProductName,
e.Quantity,
e.UnitPrice * e.Quantity * (1 - e.Discount) as ExtendedPrice
from Shippers a
inner join Orders b on a.ShipperID = b.ShipVia
inner join Customers c on c.CustomerID = b.CustomerID
inner join Employees d on d.EmployeeID = b.EmployeeID
inner join [Order Details] e on b.OrderID = e.OrderID
inner join Products f on f.ProductID = e.ProductID
order by b.OrderID
It works, it gives me all the orders made with informations. But now, I need to create a table view for an invoice of particular OrderId. When I write something like this:
CREATE VIEW FAKTURA AS
SELECT b.OrderID,
b.CustomerID,
c.CompanyName,
c.Address,
c.City,
c.PostalCode,
c.CountryID as CustomersCountryID,
concat(d.FirstName, ' ', d.LastName) as Salesperson,
a.CompanyName as ShippingVia,
e.ProductID,
f.ProductName,
e.Quantity,
e.UnitPrice * e.Quantity * (1 - e.Discount) as ExtendedPrice
from Shippers a
inner join Orders b on a.ShipperID = b.ShipVia
inner join Customers c on c.CustomerID = b.CustomerID
inner join Employees d on d.EmployeeID = b.EmployeeID
inner join [Order Details] e on b.OrderID = e.OrderID
inner join Products f on f.ProductID = e.ProductID
WHERE b.OrderID = 10248
I am just creating a separate view file for that particular OrderID. It doesn't look like a real life invoice at all.
It should resemble something like this:
I need to separate general data about invoice and customer from data about order itself, product ID, quantity etc.
Is it possible to create something similar in SQL Server Management Studio? How can I do it?
Your query already provides the header (customer info) and table body parts, so what you could do is (NOTE: this is NOT what I would do but, considering the need to have a very simple solution):
Phrase a query that would perform all the needed calculations for the trailing part based on the INVOICE number (this can be similar to what you already have except that it would SUM the amounts, calculate taxes and shipping cost),
Once you have that query ready, INNER JOIN it to the one you already have (using the invoice ID as a key); Note that you will have to add the additional fields to the top SELECTs list.
The result will be what you already have + the subtotal, tax, shipping and total in each and every record.
Again, this is NOT the most efficient and elegant solution, but matches your needs (simplicity and final result).

How to Organize Multiple Joins SQL

In SQL, how should I be joining tables together when I do multiple joins in one query. Should I join on only one table - in this case the Customers table or is it okay to do what I have done (joining on different tables as new keys are needed)?
SELECT O.OrderID, O.OrderDate, C.City, C.Country, C.PostalCode, C.ContactName, O.CustomerID, O.ShipperID, D.ProductID, COUNT(D.ProductID) ProductCount, S.SupplierID
FROM Customers C
INNER JOIN Orders O
ON O.CustomerID = C.CustomerID
INNER JOIN OrderDetails D
ON O.OrderID = D.OrderID
INNER JOIN Products P
ON D.ProductID = P.ProductID
INNER JOIN Suppliers S
ON S.SupplierID = P.SupplierID
WHERE 1 = 1
GROUP BY O.OrderID
ORDER BY OrderDate DESC
I am using W3Schools SQL TryIt editor to test this, not sure what DB engine it is!
Thanks!
Of course you can join on multiple tables in a query. That is a big part of the power of SQL.
In your particular case, you don't need the join to the Suppliers table, because the column is already in Products.
Also, you need to be careful about your SELECT and GROUP BY clauses. In general, you should put all non-aggregated columns in the GROUP BY:
SELECT O.OrderID, O.OrderDate, C.City, C.Country, C.PostalCode, C.ContactName,
O.CustomerID, O.ShipperID, D.ProductID,
COUNT(D.ProductID) as ProductCount,
P.SupplierID
FROM Customers C INNER JOIN
Orders O
ON O.CustomerID = C.CustomerID INNER JOIN
OrderDetails D
ON O.OrderID = D.OrderID INNER JOIN
Products P
ON D.ProductID = P.ProductID
GROUP BY O.OrderID, O.OrderDate, C.City, C.Country, C.PostalCode, C.ContactName,
O.CustomerID, O.ShipperID, D.ProductID, P.SupplierId
ORDER BY OrderDate DESC;
The WHERE 1=1 is also unnecessary.
I wonder if this query really does what you want. However, you don't state what you actually want the query to do, so I'm merely speculating.
The way you have done it is find, don't forget that for each inner join, your record set may reduce by the number of non matching keys in each additional join.
you could also just use the JOIN syntax.

Insufficient output from SQL query

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
)