How to get the count and display only one row - sql

I've got 3 Tables:
tblCustomer
CustomerID CustomerName
1 Customer 1
2 Customer 2
tblOrder
OrderID CustomerID OrderTypeID LoanNumber
1 1 1 98513542
2 1 1 71283527
3 1 1 10268541
4 1 1 61258965
tblOrderType
OrderTypeID OrderTypeName
1 Purchase
2 Rental
Now, I'm looking to return CustomerID, CustomerName, OrderTypeName and OrderCount, where OrderCount is how many of each order the customer has. I'm using the following query:
SELECT tblCustomer.CustomerID, tblCustomer.customerName, tblOrderType.OrderTypeName, tblOrder.OrderID
FROM tblCustomer
INNER JOIN tblOrder
ON tblCustomer.CustomerID = tblOrder.CustomerID
INNER JOIN tblOrderType
ON tblOrderType.OrderTypeID = tblOrder.OrderTypeID
It sort of works. It gets all I'm asking for, except for the OrderCount, obviously. The result is like this:
CustomerID CustomerName OrderTypeName OrderID
1 Customer 1 Purchase 1
1 Customer 1 Purchase 2
1 Customer 1 Purchase 3
1 Customer 1 Purchase 4
But what I'm looking for is this:
CustomerID CustomerName OrderTypeName OrderCount
1 Customer 1 Purchase 4
Now, I've tried adding Count() into the query at various places (Count(tblOrder.OrderID) for one), and I get an error that tblCustomer.CustomerID is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
This isn't a homework assignment. I just don't know a whole lot about sql and database interactions, since it wasn't taught in my school, and I've got a friend who's throwing scenarios at me.

You need to use grouping and aggregation:
SELECT tblCustomer.CustomerID, tblCustomer.customerName, tblOrderType.OrderTypeName,
count (tblOrder.OrderID) asOrderCOunt
FROM tblCustomer
INNER JOIN tblOrder
ON tblCustomer.CustomerID = tblOrder.CustomerID
INNER JOIN tblOrderType
ON tblOrderType.OrderTypeID = tblOrder.OrderTypeID
GROUP BY
tblCustomer.CustomerID,
tblCustomer.customerName,
tblOrderType.OrderTypeName
You can't use aggregate functions without grouping everything that isn't aggregated.

The error message does tell you the issue. Whenever you use an aggregation operator (COUNT, SUM, AVG, etc.), you have to tell the database how these should be aggregated together. You do this with a GROUP BY statement (the link there is for SQL Server, but it should generally apply to all database engines):
SELECT
C.CustomerID
,C.customerName
,OT.OrderTypeName
,COUNT(O.OrderID)
FROM tblCustomer C
INNER JOIN tblOrder O
ON C.CustomerID = O.CustomerID
INNER JOIN tblOrderType OT
ON OT.OrderTypeID = O.OrderTypeID
GROUP BY
C.CustomerID
,C.customerName
,OT.OrderTypeName

Try this, just add group by and count the grouped rows
SELECT tblCustomer.CustomerID, tblCustomer.customerName,
tblOrderType.OrderTypeName, tblOrder.OrderID,
COUNT(tblOrder.OrderID) as OrderCount
FROM tblCustomer INNER JOIN tblOrder
ON tblCustomer.CustomerID = tblOrder.CustomerID
INNER JOIN tblOrderType
ON tblOrderType.OrderTypeID = tblOrder.OrderTypeID
GROUP BY tblCustomer.CustomerID, tblCustomer.customerName,
tblOrderType.OrderTypeName

Related

SQL Server : how to return highest agregated columns

Jow can I return two highest aggregated results?
For example, I have a result like this:
CustomerId Total
---------------------
5 1100.00
n/a 100.00
7 100.00
6 0.00
and I need to return max 2 highest rows like this:
CustomerId Total
-----------------------
5 1100.00
7 100.00
n/a 100.00
I tried with TOP 2, but the problem is that I do not know how can I return more rows if there are rows with the same value.
Here is my query at the moment
SELECT
ISNULL(CONVERT(varchar(50), u.CustomerId), 'not found') CustomerId ,
ISNULL(SUM(o.Total), 0.00) Total
FROM
Orders o
FULL OUTER JOIN
CustomerId u ON u.UserId = o.UserId
GROUP BY
u.CustomerId
ORDER BY
Total DESC;
Do you want WITH TIES?
SELECT TOP (2) WITH TIES
ISNULL(CONVERT(varchar(50), u.CustomerId), 'not found') CustomerId ,
ISNULL(SUM(o.Total), 0.00) Total
FROM Orders o
FULL OUTER JOIN CustomerId u ON u.UserId = o.UserId
GROUP BY u.CustomerId
ORDER BY total desc;
It is quite unclear why you actually need a FULL JOIN. Unless you have orphan orders, that should be a LEFT JOIN starting from the customers table and then going to the orders table. It is also unclear why you have a table named CustomerId, with a column that has the same name. Ideally you would name that table Customers instead, so:
SELECT TOP (2) WITH TIES
c.CustomerId
ISNULL(SUM(o.Total), 0.00) Total
FROM Customers c
LEFT JOIn Orders o ON u.UserId = c.UserId
GROUP BY c.CustomerId
ORDER BY total desc;
First, an outer join should not be necessary, unless your data model is really messed.
You can use TOP 2 WITH TIES:
SELECT TOP (2) WITH TIES u.CustomerId, SUM(o.Total)
FROM Orders o JOIN
CustomerId u
ON u.UserId = o.UserId
GROUP BY u.CustomerId
Order by Total desc;

Selecting count with other columns through joined tables (Oracle SQL)

I have the following query that returns the number of orders a stock item has had:
select count(Orders.OrderID) from Stocks, Orders
where Stocks.StockID = Orders.StockID(+) group by Stocks.StockID;
This returns:
count(Orders.OrderID)
---------------------
0
1
2
0
1
...
However, I also want to display the name of the particular stock item alongside this query. So far, I have tried this, but the following error occurs...
select Stocks.Name, count(Orders.OrderID) from Stocks, Orders
where Stocks.StockID = Orders.StockID(+) group by Stocks.StockID;
The following error occurs:
select Stocks.Name, count(Orders.OrderID) from Stocks, Orders
*
Error: not a GROUP BY expression.
This should return:
Name count(Orders.OrderID)
---------- ---------------------
Item1 0
Item2 1
Item3 2
Item4 0
Item5 1
..... ...
Can anyone help? Thanks in advance.
It should be sth like:
select Stocks.StockID,Stocks.Name, count(Orders.OrderID)
from Stocks
left join Orders
on Stocks.StockID = Orders.StockID -- explicit outer join syntax
group by Stocks.StockID,Stocks.Name; -- matching with select column list
I suggest that you use the COUNT analytic function:
SELECT DISTINCT s.NAME,
COUNT(*) OVER (PARTITION BY s.STOCKID ORDER BY s.STOCKID) AS ON_ORDER
FROM STOCKS s
LEFT OUTER JOIN ORDERS o
ON s.STOCKID = o.STOCKID
dbfiddle here
Another option would be the following;
SELECT S.StockID, S.Name, Orders.[Count]
FROM Stocks AS S
CROSS APPLY
( SELECT COUNT(*) AS [Count]
FROM Orders AS O
WHERE S.StockID = O.StockID
) AS Orders
:)
From your description, it seems that you want to report one aggregate row for each stock name, or in other words group by the stock name:
select s.name as stock_name, count(o.orderid) as orders
from stocks s
left join orders o
on o.stockid = s.stockid
group by s.name;
That will give results like
STOCK_NAME ORDERS
----------- ------
X 123
Y 45
Z 6
You can include other columns from Stocks such as the Stock ID if you want:
select s.stockid, s.name as stock_name, count(o.orderid) as orders
from stocks s
left join orders o
on o.stockid = s.stockid
group by s.stockid, s.name;
which will give results like
STOCKID STOCK_NAME ORDERS
-------- ----------- ------
1 X 123
2 Y 45
3 Z 6

How to count sub data of customer in SQL

I have Customer table as following
CustomerId CustomerName CustomerEmail
1 AAA AAA#AAA.com
2 BBB BBB#BBB.BBB
This is example data I have shown. Like this I have 50000 customer in customer table now their invoices are also stored in invoice table
InvoiceId InvoiceAmount InvoiceCustomerID
1 22.00 1
2 58.00 2
3 21.00 2
4 45.00 2
Now I want to count the invoice for each customer when I show the customer listing, for example:
CustomerId CustomerName CustomerEmail TotalInvoice
1 AAA AAA#AAA.com 1
2 BBB BBB#BBB.BBB 3
I have used the following query but didnt worked
SELECT customer.*,COUNT(invoice.InvoiceId) FROM `customer` as customer INNER JOIN invoice as invoice ON customer.CustomerId= invoice.InvoiceCustomerID
Can suggest any method to solve this ?
Also there is more then 5 lacks invoice so it's taking to much time to load.
SELECT a.CustomerID, a.CustomerName, a.CustomerEmail,
SUM(CASE WHEN b.InvoiceID IS NOT NULL THEN 1 ELSE 0 END) as TotalInvoice
FROM `customer` a LEFT JOIN invoice b ON a.CustomerId= b.InvoiceCustomerID
GROUP BY a.CustomerId, a.CustomerName, a.CustomerEmail
Just use GROUP BY
Also, do you need to display customers with no invoices? You're going to have to turn this into a left join if you do.
You can't use a grouping function without GROUP BY:
SELECT customer.CustomerID, customer.Customer.Name, customer.CustomerEmail
,COUNT(invoice.InvoiceId) AS RC
FROM `customer` AS customer
INNER JOIN invoice AS invoice ON customer.CustomerId = invoice.InvoiceCustomerID
GROUP BY customer.CustomerID, customer.Customer.Name, customer.CustomerEmail
select c.CustomerId "CustomerId",
c.CustomerName "CustomerName",
c.CustomerEmail "CustomerEmail",
count(i.InvoiceCustomerID) "TotalInvoice"
from customer as c
inner join invocie i
on(i.InvoiceCustomerID = c.CustomerId) group by
c.CustomerId, c.CustomerName, c.CustomerEmail order by CustomerId
due to bulk data other queries was taking to much time to load
so I have settled the issue using following query
SELECT c.CustomerId,c.CustomerName,totalinvoice AS ttlinv FROM customer
as c LEFT JOIN (select COUNT(InvoiceId) as totalinvoice,InvoiceCustomerID
from invoice GROUP by InvoiceCustomerID) as io on io.InvoiceCustomerID=c.CustomerId

sqlerrorColumn 'tableName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

I have three tables
Table 1:
tblCustomer
CustomerID CustomerName
1 ABC Bank
2 Chase Bank
Table 2:
tblOrderType
OrderTypeID OrderTypeName
1 Assignment
2 LienRelease
Table 3:
tblOrder
OrderID CustomerID OrderTypeID LoanNumber
1 1 1 45584565
2 1 1 45566856
3 1 1 45565584
4 1 1 45588545
I am trying to return CustomerID, CustomerName, OrderTypeName and OrderCount in CustomerName order but when using the following query:
SELECT tblOrder.CustomerID,CustomerName,OrderTypeName,COUNT(tblOrder.CustomerID) FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
GROUP BY tblOrder.CustomerID
I am getting the error:
Column 'tblCustomer.CustomerName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I dont know what I am doing wrong.
Your SELECT and GROUP BY statements should have same fields. In your case
SELECT tblOrder.CustomerID,CustomerName,OrderTypeName
The answer is exactly what the error message is telling you.
You cannot select columns which aren't in the group by clause OR aggregated by somehow.
You also haven't included the actual order by clause.
SELECT
tblOrder.CustomerID,
tblCustomer.CustomerName,
tblOrderType.OrderTypeName,
COUNT(tblOrder.CustomerID)
FROM
tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
GROUP BY
tblOrder.CustomerID,
tblCustomer.CustomerName,
tblOrderType.OrderTypeName,
ORDER BY
tblCustomer .CustomerName ASC
If you use GROUP BY in SQl-Server you have to aggregate all selected columns(f.e. with Min, Max, Count etc) or you have to include them in the GROUP BY. That makes sense because it's not clear which row's value you want to take for CustomerName and OrderTypeName, there could be multiple for each id-group.
If that's not the case include it in the Group by:
SELECT tblOrder.CustomerID,
CustomerName,
OrderTypeName,
COUNT(tblOrder.CustomerID) As CountCustomerID
FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
GROUP BY tblOrder.CustomerID, CustomerName, OrderTypeName
Another way in SQL-Server(>=2005) is using a CTE(or subquery) + ROW_NUMBER, then you can select all fields:
WITH CTE AS
(
SELECT tblOrder.CustomerID,
CustomerName,
OrderTypeName,
Count(*) OVER (PARTITION BY tblOrder.CustomerID, CustomerName, OrderTypeName),
RN = ROW_NUMBER() OVER (PARTITION BY tblOrder.CustomerID, CustomerName, OrderTypeName
ORDER BY CustomerID, CustomerName)
FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
)
SELECT * FROM CTE
WHERE RN = 1
You need to aggregate the columns that are not included in your GROUP BY statement:
SELECT A.CUSTOMERID, MAX(B.CUSTOMERNAME), MAX(C.ORDERTYPENAME), COUNT(A.CUSTOMERID)
FROM TBLORDER AS A
INNER JOIN TBLCUSTOMER AS B
ON A.CUSTOMERID=B.CUSTOMERID
INNER JOIN TBLORDERTYPE AS C
ON A.ORDERTYPEID=C.ORDERTYPEID
GROUP BY A.CUSTOMERID
Or you can group by the same columns in your SELECT.
Something like this
SELECT tblOrder.CustomerID, CustomerName, OrderTypeName, COUNT(*)
FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
GROUP BY tblOrder.CustomerID, CustomerName, OrderTypeName
or this
SELECT tblOrder.CustomerID, CustomerName, COUNT(*)
FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID = tblCustomer.CustomerID
GROUP BY tblOrder.CustomerID, CustomerName

SQL Server inner join after Count and GroupBy

I'm trying to make an eCommerce web site. And at ProductCategory page I have to do a list about Companies that included by Products.
I have a Product table that contains:
ProductID
ProductName
...
MarkID
And I have a Company table that contains:
CompanyID
CompanyName
I want to mix them in a query.
After that code block,
SELECT
CompanyID,
count(CompanyID) as CompanyCount
FROM
Products
GROUP by
CompanyID
I get this result:
CompanyID CompanyCount
-------------------------
1 2
3 1
4 4
after that I just want to inner join that with CompanyName
And want a result like this:
CompanyName CompanyCount
---------------------------
1 2
3 1
4 4
How can I do that?
With a subquery:
SELECT * FROM
(
SELECT CompanyID, count(CompanyID) as CompanyCount
FROM Products
GROUP by CompanyID
) CompanyCounts
INNER JOIN Companies
on CompanyCounts.CompanyId = Companies.CompanyID
If you need this in more places, you may want to create a view for company count.
This can be achieved without a subquery.
SELECT C.CompanyID, C.CompanyName, COUNT(*)
FROM Products P INNER JOIN Companies C ON P.CompanyId = C.CompanyID
GROUP BY C.CompanyID, C.CompanyName
You can use your first select as a subquery to join with Companies table:
SELECT C.CompanyName, Q1.CompanyCount
FROM Companies C
JOIN (
SELECT CompanyID, count(CompanyID) as CompanyCount
FROM Products
GROUP by CompanyID
) Q1
ON Q1.CompanyID = C.CompanyId