Selecting count with other columns through joined tables (Oracle SQL) - 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

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;

Get max value from another query

I have problems with some query. I need to get max value and product_name from that query:
select
products.product_name,
sum(product_invoice.product_amount) as total_amount
from
product_invoice
inner join
products on product_invoice.product_id = products.product_id
inner join
invoices on product_invoice.invoice_id = invoices.invoice_id
where
month(invoices.invoice_date) = 2
group by
products.product_name
This query returns a result like this:
product_name | total_amount
--------------+--------------
chairs | 70
ladders | 500
tables | 150
How to get from this: ladders 500?
Select product_name,max(total_amount) from(
select
products.product_name,
sum(product_invoice.product_amount) as total_amount
from product_invoice
inner join products
on product_invoice.product_id = products.product_id
inner join invoices
on product_invoice.invoice_id = invoices.invoice_id
where month(invoices.invoice_date) = 2
group by products.product_name
) outputTable
You can use order by and fetch first 1 row only:
select p.product_name,
sum(pi.product_amount) as total_amount
from product_invoice pi inner join
products p
on pi.product_id = p.product_id inner join
invoices i
on pi.invoice_id = i.invoice_id
where month(i.invoice_date) = 2 -- shouldn't you have the year here too?
group by p.product_name
order by total_amount
fetch first 1 row only;
Not all databases support the ANSI-standard fetch first clause. You may need to use limit, select top, or some other construct.
Note that I have also introduced table aliases -- they make the query easier to write and to read. Also, if you are selecting the month, shouldn't you also be selecting the year?
In older versions of SQL Server, you would use select top 1:
select top (1) p.product_name,
sum(pi.product_amount) as total_amount
from product_invoice pi inner join
products p
on pi.product_id = p.product_id inner join
invoices i
on pi.invoice_id = i.invoice_id
where month(i.invoice_date) = 2 -- shouldn't you have the year here too?
group by p.product_name
order by total_amount;
To get all rows with the top amount, use SELECT TOP (1) WITH TIES . . ..
If you are using SQL Server, then TOP can offer a solution:
SELECT TOP 1
p.product_name,
SUM(pi.product_amount) AS total_amount
FROM product_invoice pi
INNER JOIN products p
ON pi.product_id = p.product_id
INNER JOIN invoices i
ON pi.invoice_id = i.invoice_id
WHERE
MONTH(i.invoice_date) = 2
GROUP BY
p.product_name
ORDER BY
SUM(pi.product_amount) DESC;
Note: If there could be more than one product tied for the top amount, and you want all ties, then use TOP 1 WITH TIES, e.g.
SELECT TOP 1 WITH TIES
... (the same query I have above)

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

SQL: How do I count the rows of a summed column?

How do I count the number of lines of a summed column?
I have built a query that will show how many items in each order, but I need to do a count of each Sum. My goal is to see how many people bought 3 items, how many bought 4, etc...
SELECT Orders.id,
sum(Quantity) AS "Box Count"
FROM OrderLines
INNER JOIN Orders ON OrderLines.Order_id = Orders.id
INNER JOIN Products ON OrderLines.Product_id = Products.id
WHERE (Products.ProductType_id = 2) AND Orders.shipdate > '10/01/2014'
GROUP BY Orders.id
It is returning this:
id Box Count
----- ---------
68015 6
69660 3
70923 3
72697 13
I want it to return this:
Box Count Total Count
--------- -----------
3 2
6 1
13 1
You could use a second query:
SELECT
[Box Count]
,COUNT(*) AS [Total Count]
FROM
(
SELECT
Orders.id,
sum(Quantity) AS "Box Count"
FROM OrderLines
INNER JOIN Orders ON OrderLines.Order_id = Orders.id
INNER JOIN Products ON OrderLines.Product_id = Products.id
WHERE (Products.ProductType_id = 2) AND Orders.shipdate > '10/01/2014'
GROUP BY Orders.id
) AS InnerQuery
GROUP BY [Box Count]
ORDER BY COUNT(*) DESC -- optional

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