sql count on joined tables - sql

I know that there a a bazillion of these on here, but I have spent an hour reading them and trying.
All I need to do is return a count of order and items assigned to order.
Totals, not each.
So if I have 300 order with exactly 3 items per order I need a return of:
-- OrderCount: 300 ItemCount: 900
SELECT COUNT (o.id) AS OrderCount, COUNT (i.id) AS ItemCount
FROM order_detail o JOIN item_detail i
ON i.job_id = o.id
WHERE o.customer_terminal_id = 182 AND o.requested_del_date = '2018-12-03'
This returns a count of everything and they are both the same.
I have tried with grouping as well.
Update:
This works:
SELECT COUNT (DISTINCT o.id) AS OrderCount, COUNT (i.id) AS ItemCount
FROM order_detail o JOIN item_detail i
ON i.job_id = o.id
WHERE o.customer_terminal_id = 182 AND o.requested_del_date = '2018-12-04'
but the real requirement is that some of the orders goto locations that have the same address. What I really need is the count of those unique addresses.
They are in a table called Common_Address_points which is joined to orders by
o.Delivery_Location_Id = Common_Address_Points.id
So desired output would be Orders, unique addresses and items
So in the above if all of them were 1 order to 1 address, except for 1 that had 10 orders going to the same address it would show:
Orders: 300
Addresses: 290
Items: 900
I think this does it but I have to verify:
SELECT COUNT (DISTINCT o.id) AS OrderCount, COUNT (i.id) AS ItemCount, COUNT (DISTINCT Common_Address_Point.Id) AS Addresses
FROM order_detail o
JOIN item_detail i ON i.job_id = o.id
JOIN Common_Address_Point ON Common_Address_Point.Id = o.Delivery_Location_Id
WHERE o.customer_terminal_id = 182 AND o.requested_del_date = '2018-12-04'

You can try below - you need to add distinct for order count - COUNT (distinct o.id)
SELECT COUNT (distinct o.id) AS OrderCount, COUNT (i.id) AS ItemCount
FROM order_detail o JOIN item_detail i
ON i.job_id = o.id
WHERE o.customer_terminal_id = 182 AND o.requested_del_date = '2018-12-03'

Related

SQL Selecting & Counting From Another Table

I have this query that works excellently and gives me the results I want, however, does anybody know how I can remove any rows that have 0 orders? I am sure it is something simple, I just can't get my head around it.
In other words, should it only show the top 2 rows?
SELECT customers.id, customers.companyname, customers.orgtype,
(SELECT COALESCE(SUM(invoicetotal), 0)
FROM invoice_summary
WHERE invoice_summary.cid = customers.ID
and invoice_summary.submitted between '2022-08-01' and '2022-08-31'
) AS total,
(SELECT COUNT(invoicenumber)
FROM invoice_summary
WHERE invoice_summary.cid = customers.ID
and invoice_summary.submitted between '2022-08-01' and '2022-08-31'
) AS orders
FROM customers WHERE customers.orgtype = 10
ORDER BY total DESC
ID
Company
Org
Total
Orders
1232
ACME 1
10
523.36
3
6554
ACME 2
10
411.03
2
1220
ACME 3
10
0.00
0
4334
ACME 4
10
0.00
0
You can use a CTE to keep the request simple :
WITH CTE_Orders AS (
SELECT customers.id, customers.companyname, customers.orgtype,
(SELECT COALESCE(SUM(invoicetotal), 0)
FROM invoice_summary
WHERE invoice_summary.cid = customers.ID
and invoice_summary.submitted between '2022-08-01' and '2022-08-31'
) AS total,
(SELECT COUNT(invoicenumber)
FROM invoice_summary
WHERE invoice_summary.cid = customers.ID
and invoice_summary.submitted between '2022-08-01' and '2022-08-31'
) AS orders
FROM customers WHERE customers.orgtype = 10
ORDER BY total DESC
)
SELECT * FROM CTE_Orders WHERE orders > 0
You will find aditionals informations about CTE on Microsoft documentation : https://learn.microsoft.com/fr-fr/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver16
You can do this by transforming your subquery to a CROSS APPLYof a pre-aggregated table
SELECT
c.id,
c.companyname,
c.orgtype,
ins.total,
ins.orders
FROM customers c
CROSS APPLY (
SELECT
COUNT(*) AS orders,
ISNULL(SUM(ins.invoicetotal), 0) AS total
FROM invoice_summary ins
WHERE ins.cid = c.ID
AND ins.submitted between '20220801' and '20220831'
GROUP BY () -- do not remove the GROUP BY
) ins
WHERE c.orgtype = 10
ORDER BY
ins.total DESC;
You can also do this with an INNER JOIN against it
SELECT
c.id,
c.companyname,
c.orgtype,
ins.total,
ins.orders
FROM customers c
INNER JOIN (
SELECT
ins.cid,
COUNT(*) AS orders,
ISNULL(SUM(ins.invoicetotal), 0) AS total
FROM invoice_summary ins
WHERE ins.submitted between '20220801' and '20220831'
GROUP BY ins.cid
) ins ON ins.cid = c.ID
WHERE c.orgtype = 10
ORDER BY
ins.total DESC;
Quick and dirty way would be to dump your results into a temp table, delete the records you don't want, then select what remains.
Add this to the end of your select before the FROM clause:
INTO #temptable
Then delete the records you don't want:
DELETE FROM #temptable WHERE [Orders] = 0
Then just select from the temp table.
There are other ways to do this, and you should read up on the downsides of temp tables before implementing this solution.

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

Finding count in multiple tables

I need to find the amount of times a customer appears in the Orders and Requests tables respectively. However this script is producing the same count value for both places where COUNT is used. The value cannot possibly be the same so what am I doing wrong?
SELECT o.CustomerID,
COUNT(o.CustomerID) as OrdersPerCustomer,
COUNT(r.CustomerID) as RequestsPerCustomer
FROM Orders o
INNER JOIN [Customers] c on c.ID = o.CustomerID
INNER JOIN [Request] r on r.CustomerID = c.ID
GROUP BY o.CustomerID
You are multiplying the number of order and request records. I.e. by joining the tables, you get for, say, 3 orders and 4 requests for a customer 12 result rows. As the IDs will never be null in a record, COUNT(o.CustomerID) and COUNT(r.CustomerID) are just COUNT(*) (12 in my example, and not 3 and 4 as you expected).
The easiest approach:
select
customer_id,
(select count(*) from orders o where o.customerid = c.id) as o_count,
(select count(*) from request r where r.customerid = c.id) as r_count
from customers c;
The same with subqueries (derived tables) in the from clause:
select
customer_id,
coalesce(o.total, 0) as o_count,
coalesce(r.total, 0) as r_count
from customers c
left join (select customerid, count(*) as total from orders group by customerid) o
on o.customerid = c.id
left join (select customerid, count(*) as total from request group by customerid) r
on r.customerid = c.id;
When aggregating from multiple tables, always aggregate first and join then.

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