How to count sub data of customer in SQL - 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

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 get the count and display only one row

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

How filter tables in sql in group

I have two tables.
Customer | OrderItems
CustomerID CustomerName | OrderItemID OrderID CustomerID Status
1 ABC | 1 1 1 Started
2 1 1 Started
| 3 1 1 NotStarted
Now I want to get the record of all the customer where the status of orderItems is Completed. Means in this case the order is incomplete.
so If I want to get the status of incomplete orders it should give me for customer 1 is order1.
even though the items are started of 1st two but still I want to get that Incomplete.
Not sure if I understood you correctly, but this should do the job:
select distinct c.CustomerId, oi.OrderId
from Customer c
inner join OrderItems oi on c.CustomerID = oi.CustomerID
where c.OrderId not in (select o.OrderId from OrderItems o where o.Status <> 'Started')
select OrderID, CustomerID,
SUM(case Status when 'Started' Then 0 Else 1) NS
from OrderItems
having NS > 0;
If you only want the customers with NO INCOMPLETE ORDERS, then this should do the trick:
SELECT C.CustomerID, C.CustomerName
FROM Customer AS C
WHERE (((C.CustomerID) Not In
(SELECT DISTINCT [O].CustomerID
FROM OrderItems AS O
WHERE ((([O].Status)="NotStarted")))));
I miss something though: I think there should be an ORDER table with information regarding the order. Data in your OrderItems table would be inconsistent if you changed the customerID for one record let's say for OrderItemID = 3 the clientID is 2. Are there two different clients for the same order? I suppose that you didn't handle all the information and that there is an Order table.
Regards,
select OrderID, CustomerID,
SUM(case Status when 'NotStarted' Then 1 Else 0) NS
from OrderItems
group by OrderID, CustomerID
having NS > 0;
select c.customerId,c.Customername,O.OrderID, from Customer c left join OrderItem O on C.customerID = o.OrderID where o.Status = 'started'

How to select rows where multiple joined table values meet selection criteria?

Given the following sample table schema
Customer Table
CustID
1
2
3
Invoice Table
CustID InvoiceID
1 10
1 20
1 30
2 10
2 20
3 10
3 30
The objective is to select all customers who have an InvoiceID value of 10 and 20 (not OR). So, in this example customers w/ CustID=1 and 2 would be returned.
How would you construct the SELECT statement?
Use:
SELECT c.custid
FROM CUSTOMER c
JOIN INVOICE i ON i.custid = c.custid
WHERE i.invoiceid IN (10, 20)
GROUP BY c.custid
HAVING COUNT(DISTINCT i.invoiceid) = 2
The key thing is that the counting of i.invoiceid needs to equal the number of arguments in the IN clause.
The use of COUNT(DISTINCT i.invoiceid) is in case there isn't a unique constraint on the combination of custid and invoiceid -- if there's no chance of duplicates you can omit the DISTINCT from the query:
SELECT c.custid
FROM CUSTOMER c
JOIN INVOICE i ON i.custid = c.custid
WHERE i.invoiceid IN (10, 20)
GROUP BY c.custid
HAVING COUNT(i.invoiceid) = 2
The Group By answers will work unless it is possible for there to be multiples of CustID/InvoiceId in the Invoice table. Then you might get some unexpected results. I like the answer below a little better because it mirrors more closely the logic as you are describing it.
Select CustID
From Customer
Where
Exists (Select 1 from Invoice Where CustID=Customer.CustID and InvoiceID=10)
and
Exists (Select 1 from Invoice Where CustID=Customer.CustID and InvoiceID=20)
select CustID
from InvoiceTable
where InvoiceID in (10,20)
group by CustID
having COUNT(distinct InvoiceID) = 2