SQL confusion with the groupby function - sql

SELECT customers.CompanyName,
customers.ContactName,
customers.phone,
customers.country,
SUM(orders.Freight) AS Total_Freight
FROM CUSTOMERS INNER JOIN ORDERS
ON customers.CustomerID = ORDERS.customerID
WHERE orders.orderDate BETWEEN '1993-07-01' AND '1993-08-31'
GROUP BY Orders.orderID, customers.CustomerID
ORDER BY customers.companyName
Above is my code, but I am getting error
Column 'CUSTOMERS.CompanyName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Why is that? Where did I go wrong?
The database
THis is the question.
List the company name, contact name, phone number, and country from the Customers table, and the sum of the freight from the Orders table where the order date is between July 1, 1993 and August 31, 1993. Order the result set by the company name. The query should produce the result set listed below.
The result format is too messy, I doubt it will be helpful to anyone.

use all the selection column in group by also as you used aggregate function
SELECT customers.CompanyName,
customers.ContactName,
customers.phone,
customers.country,
SUM(orders.Freight) AS Total_Freight
FROM CUSTOMERS INNER JOIN ORDERS
ON customers.CustomerID = ORDERS.customerID
WHERE orders.orderDate BETWEEN '1993-07-01' AND '1993-08-31'
GROUP BY customers.CompanyName,
customers.ContactName,
customers.phone,
customers.country
ORDER BY customers.companyName

Related

Beginner: LEFT JOIN not doing what it should?

I'm having trouble with a really simple left join statement that's driving me nuts
I wanted to count the numbers of orders from each customer, that's fine, but I want to display the name, and I'm joining with the customers table and trying to select the name and it says that CustomerName is not part of an aggregate function, it's really weird.
SELECT Customers.CustomerName as 'Name',
COUNT(*) AS 'Order Count'
FROM Orders
LEFT JOIN Customers
ON Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerID
Thanks for any tips.
You need to count the rows from the orders table, and the left join should be in the other direction:
SELECT c.customerid,
c.CustomerName as "Name",
COUNT(o.customerid) AS "Order Count"
FROM Customers c
LEFT JOIN Orders o ON o.CustomerID = cs.CustomerID
GROUP BY c.CustomerID, c.customername;
count() will ignore NULL values that come into the result due to the outer join so it will count the number of orders for each customers. Customers without orders will be show with a zero count.
Include CustomerName in Group BY instead of CustomerID
SELECT Customers.CustomerName as 'Name', COUNT(*) AS 'Order Count'
FROM Orders LEFT JOIN Customers ON Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerName
If you are using SQL Server then try using OVER() without Group BY
SELECT Customers.CustomerName as 'Name', COUNT(*) OVER (PARTITION BY Customers.CustomerName ORDER BY Customers.CustomerName)AS 'Order Count'
FROM Orders LEFT JOIN Customers ON Orders.CustomerID = Customers.CustomerID
Modify as below. column used in group by clause should be in column queried in select clause
SELECT Customers.CustomerName as 'Name',
COUNT(*) AS 'Order Count'
FROM Orders
LEFT JOIN Customers
ON Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerName
I have just reordered your query,please try this it will definitely work for you.
SELECT Customers.CustomerName as 'Name',
COUNT(*) AS 'Order Count'
FROM Customers
LEFT JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
GROUP BY Customers.CustomerID
A simple approach to get all the columns in the customers table is to use a correlated subquery:
select c.*, -- or whatever columns you want
(select count(*)
from orders o
where o.CustomerID = c.CustomerID
) as order_count
from customers c;
Because this avoids the outer GROUP BY, this also has the advantage of having better performance in most databases, particularly with an index on orders(CustomerId). Plus, it returns 0 if the customer has no orders. And, it allows you to choose any or all of the columns from Customers.
The correct way to get the counts you want is to count a column from Orders:
SELECT c.CustomerName, c.CustomerID,
COUNT(o.CustomerId) AS Order_Count
FROM Customers c LEFT JOIN
Orders o
ON o.CustomerID = c.CustomerID
GROUP BY c.CustomerID, c.CustomerName;
Notes:
The Customers table goes first in the LEFT JOIN because presumably you want all rows in Customers.
Table aliases make the query easier to write and to read.
Do not use single quotes for column aliases, even if your database supports it. The best method is to choose aliases that do not need to be supported.
Include the CustomerId in the logic, just in case two customers have the same name.
Count a column from Orders so you get a count of 0 for customers with no orders.

SQL - how to get specific order on a specific date in two different tables

We were asked to create a SQL statement to show total order amount of the order that Rattlesnake Canyon Grocery placed on 1997-01-01.. However, the ORDERS table is different from the CUSTOMERS table.
So here's what I did:
SELECT Orders.OrderID,
Orders.CustomerID,
Orders.EmployeeID,
Orders.OrderDate,
Orders.ShipperID,
Customers.CustomerID,
Customers.CustomerName,
Customers.ContactName,
Customers.Address,
Customers.City,
Customers.PostalCode,
Customers.Country
FROM Customers
INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
WHERE DATE = 1997-01-01
But it's showing me an 'error' sign. How to fix this? The error says: 'could not prepare'.
Here's the link for the database: http://www.w3schools.com/sql/trysql.asp?filename=trysql_select_all
You haven't any DATE column in any of your table, please Replace DATE column to Orders.OrderDate and also semicolumn in wrong place
SELECT Orders.OrderID,
Orders.CustomerID,
Orders.EmployeeID,
Orders.OrderDate,
Orders.ShipperID,
Customers.CustomerID,
Customers.CustomerName,
Customers.ContactName,
Customers.Address,
Customers.City,
Customers.PostalCode,
Customers.Country
FROM Customers
INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate= '1997-01-01';
You forgot to add quotes on date and a wrong place to add a semicolon.
SELECT Orders.OrderID,
Orders.CustomerID,
Orders.EmployeeID,
Orders.OrderDate,
Orders.ShipperID,
Customers.CustomerID,
Customers.CustomerName,
Customers.ContactName,
Customers.Address,
Customers.City,
Customers.PostalCode,
Customers.Country
FROM Customers
INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID //u added semicolon here which is wrong
WHERE DATE = '1997-01-01';

Using DISTINCT in SQL Query

How do i use DISTINCT command in a SQL query to show the supplier id, company name, and the number of distinct products from that supplier that were ordered prior to a specific date? I ran the code in Access but it doesn't translate over to SQL efficiently. The table appears.
[Supplier ID Company Name Product Name Order Date
1 Exotic Liquids Chang 17-Aug-94
1 Exotic Liquids Chang 22-Nov-94
1 Exotic Liquids Aniseed Syrup 26-Sep-94]
The code I have so far is the following. Where I get confused is where to put the DISTINCT statement. Should it be immediately after the Select? Should it go in Parentheses in addition to the SELECT? Excuse my lack of knowledge on this subject in advance.
SELECT Suppliers.SupplierID, Customers.CompanyName, Products.ProductName,
Orders.OrderDate
FROM Suppliers INNER JOIN
Products ON Suppliers.SupplierID = Products.SupplierID CROSS JOIN
Customers INNER JOIN
Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate <='1/1/1999'
ORDER BY Suppliers.SupplierID
You can either distinct by all columns selected :
SELECT DISTINCT
Suppliers.SupplierID, Customers.CompanyName, Products.ProductName,
Orders.OrderDate
FROM
Suppliers INNER JOIN
Products ON Suppliers.SupplierID = Products.SupplierID CROSS JOIN
Customers INNER JOIN
Orders ON Customers.CustomerID = Orders.CustomerID
WHERE
Orders.OrderDate <='1/1/1999'
ORDER BY
Suppliers.SupplierID
or use group by instead if you need to distinct only by SupplierID. DISTINCT is not a function, hence DISTINCT(Suppliers.SupplierID) means the same as simply put DISTINCT word after SELECT in this case (see the 2nd reference below).
For Reference :
http://blog.sqlauthority.com/2007/12/20/sql-server-distinct-keyword-usage-and-common-discussion/
http://weblogs.sqlteam.com/jeffs/archive/2007/10/12/sql-distinct-group-by.aspx
I'm pretty sure it's this:
SELECT DISTINCT(Suppliers.SupplierID), Customers.CompanyName, Products.ProductName,Orders.OrderDate
FROM Suppliers INNER JOIN
Products ON Suppliers.SupplierID = Products.SupplierID CROSS JOIN
Customers INNER JOIN
Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate <='1/1/1999'
ORDER BY Suppliers.SupplierID

Compare a table with a count result from another table and add the names that have a zero count

I am counting how many times a company has ordered. Then I am only showing if a company has ordered less than 5 times. I am then checking it against the table with all company names to see what company has not ordered, which would not show up on the order table, then add their name on the displayed list.
What I have tried:
Select Orders.CustomerID, Count(Orders.CustomerID) AS OrderCount
From Orders Left Join Customers
On Orders.CustomerID = Customers.CustomerID
Group By Orders.CustomerID
Having Count(Orders.CustomerID) <5
This is totally wrong:
Select CustomerID
From Customers
Where EXISTS
(Select CustomerID, Count(CustomerID) AS 'OrderCount'
From Orders
Group BY CustomerID
Having Count(Orders.CustomerID) < 5)
I need to somehow compare the list of names before I ask it to see which ones have ordered less than 5 times.
Thanks
If you want to use LEFT JOIN, interchange the table names since you want to show values from Customers, otherwise use RIGHT JOIN instead.
SELECT Customers.CustomerID,
COUNT(Orders.CustomerID) AS OrderCount
FROM Customers
LEFT JOIN Orders
ON Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerID
HAVING COUNT(Orders.CustomerID) < 5
using EXISTS()
SELECT CustomerID
FROM Customers c
WHERE EXISTS
(
SELECT 1
FROM Orders o
WHERE o.CustomerID = c.CustomerID
GROUP BY CustomerID
HAVING COUNT(CustomerID) < 5
)
Try this:
SELECT C.CustomerID, C.CustomerName, COUNT(O.CustomerID) AS OrderCount
FROM Customers C
LEFT JOIN Orders O ON O.CustomerID = C.CustomerID
GROUP BY C.CustomerID
HAVING OrderCount < 5
ORDER BY OrderCount, C.CustomerName

comparison two column of same row

i want to Display the OrderID of all orders that where placed after all orders placed by Bottom-Dollar Markets.
i used the fllowing query
select
Orders.OrderID
from
Orders
where
Orders.OrderDate > (
select
Orders.OrderDate
from
Orders
where
Orders.CustomerID = (
select
Customers.CustomerID
from
Customers
where
Customers.CompanyName='Bottom-Dollar Markets'
)
);
but it gives the error subquery returened more than one value
i am using northwind database
Both of your subqueries could return multiple rows, which isn't allowed when you're using a scalar comparison operation - > and =, respectively, in your case.
Try this instead:
select Orders.OrderID
from Orders
where Orders.OrderDate > (
select max(Orders.OrderDate)
from Orders
where Orders.CustomerID in (
select Customers.CustomerID
from Customers
where Customers.CompanyName='Bottom-Dollar Markets'
)
);
You don't actually need to compare all orders since if the order of a customer is greater than the latest order placed by Bottom-Dollar Markets, then it follows it is also greater than earlier orders.
Alternatively this would work with a JOIN:
select Orders.OrderID
from Orders
where Orders.OrderDate > (
select max(Orders.OrderDate)
from Orders join Customers on Orders.CustomerID = Customers.CustomerID
where Customers.CompanyName='Bottom-Dollar Markets'
);