SUM subquery for total amount for each line - sql

I have information in a CheckLine table that essentially breaks down the various fees and information on a particular check. For this query I am wanting to SUM the total of the CheckLine but it is instead giving a SUM for ALL CheckLines together. I know I am missing something blatantly obvious, but I keep scratching my head on why I individualize the SUMs. Here is my query:
SELECT DISTINCT
O.FileNumber
,(SELECT DISTINCT
SUM(CL.Amount)
FROM
dbo.Orders O
LEFT JOIN dbo.Checks C
ON O.OrdersID = C.OrdersID
LEFT JOIN dbo.CheckLine CL
ON C.ChecksID = CL.ChecksID
) AS 'Total'
FROM
dbo.Orders O
LEFT JOIN dbo.Checks C
ON O.OrdersID = C.OrdersID
LEFT JOIN dbo.CheckLine CL
ON C.ChecksID = CL.ChecksID
This is what it is returning:
| FileNumber | … | Total |
| 1 | | 2000 |
| 2 | | 2000 |
What it should be returning is:
| FileNumber | … | Total |
| 1 | | 700 |
| 2 | | 1300 |
Thoughts on my complete brain fart here? Thanks guys!

SELECT
O.FileNumber,
O.CloseDate,
SUM(CL.Amount) as Total
FROM dbo.Orders O
LEFT JOIN dbo.Checks C
ON O.OrdersID = C.OrdersID
LEFT JOIN dbo.CheckLine CL
ON C.ChecksID = CL.ChecksID
GROUP BY O.FileNumber, O.CloseDate
When you calculate Total in a subquery, that value will be treated as constant by SQL Server that will repeat every row.
It is very common to confuse GROUP BY with DISTINCT (please look at here and here) since they return the same values if no aggregation function is in the SELECT clause. In your example:
SELECT DISTINCT FileNumber FROM ORDERS
will return the same of
SELECT FileNumber FROM ORDERS GROUP BY FileNumber
Use GROUP BY if you are wanting to aggregate information (like your field TOTAL).

You probably want this:
SELECT O.FileNumber, SUM(CL.Amount) as total
FROM dbo.Orders O
LEFT JOIN dbo.Checks C
ON O.OrdersID = C.OrdersID
LEFT JOIN dbo.CheckLine CL
ON C.ChecksID = CL.ChecksID
group by O.FileNumber

Related

GROUP BY with SUM without removing empty (null) values

TABLES:
Players
player_no | transaction_id
----------------------------
1 | 11
2 | 22
3 | (null)
1 | 33
Transactions
id | value |
-----------------------
11 | 5
22 | 10
33 | 2
My goal is to fetch all data, maintaining all the players, even with null values in following query:
SELECT p.player_no, COUNT(p.player_no), SUM(t.value) FROM Players p
INNER JOIN Transactions t ON p.transaction_id = t.id
GROUP BY p.player_no
nevertheless results omit null value, example:
player_no | count | sum
------------------------
1 | 2 | 7
2 | 1 | 10
What I would like to have is mention about the empty value:
player_no | count | sum
------------------------
1 | 2 | 7
2 | 1 | 10
3 | 0 | 0
What do I miss here?
Actually I use QueryDSL for that, but translated example into pure SQL since it behaves in the same manner.
using LEFT JOIN and coalesce function
SELECT p.player_no, COUNT(p.player_no), coalesce(SUM(t.value),0)
FROM Players p
LEFT JOIN Transactions t ON p.transaction_id = t.id
GROUP BY p.player_no
Change your JOIN to a LEFT JOIN, then add IFNULL(value, 0) in your SUM()
left join keeps all the rows in the left table
SELECT p.player_no
, COUNT(*) as count
, SUM(isnull(t.value,0))
FROM Players p
LEFT JOIN Transactions t
ON p.transaction_id = t.id
GROUP BY p.player_no
You might be looking for count(t.value) rather than count(*)
I'm just offering this so you have a correct answer:
SELECT p.player_no, COUNT(t.id) as [count], COALESCE(SUM(t.value), 0) as [sum]
FROM Players p LEFT JOIN
Transactions t
ON p.transaction_id = t.id
GROUP BY p.player_no;
You need to pay attention to the aggregation functions as well as the JOIN.
Please Try This:
SELECT P.player_no,
COUNT(*) as count,
SUM(isnull(T.value,0))
FROM Players P
LEFT JOIN Transactions T
ON P.transaction_id = T.id
GROUP BY P.player_no
Hope this helps.

Postgres SQL: getting group count

I have the following table
>> tbl_category
id | category
-------------
0 | A
1 | B
...|...
>>tbl_product
id | category_id | product
---------------------------
0 | 0 | P1
1 | 1 | P2
...|... | ...
I can use the following query to count the number of products in a category.
select category, count(tbl.product) from tbl_product
join tbl_category on tbl_product.category_id = category.id
group by catregory
However, there are some categories that never have any product belonging to. How do I get these to show up in the query result as well?
Use a left join:
select c.category, count(tbl.product)
from tbl_category c left join
tbl_product p
on p.category_id = c.id
group by c.category;
The table where you want to keep all the rows goes first (tbl_category).
Note the use of table aliases to make the query easier to write and to read.

Select Customer Name From Customer Table and Count all Orders placed using orders table- SQL

I have two table as defined below,
Table: Customer:
CustomerID | CustomerName |
--------------------------
1 | John
2 | Mack
3 | Andy
Table: Orders:
OrderID | CustomerID|
--------------------------
1515 | 1
1516 | 3
1517 | 1
1518 | 1
1519 | 3
1520 | 1
I want to write a query to select each name and count of all orders placed by each customer using JOIN. the result will be,
John | 4
Mack | 0
Andy | 2
My query:
SELECT
CustomerName, Count(*)
FROM
Orders
INNER JOIN
Customers WHERE Orders.CustomerID = Customers.CustomerID;
But its returning incorrect results. Please advise.
You are missing the GROUP BY. I would write the query like this:
SELECT c.CustomerName, Count(o.CustomerId)
FROM Customers c LEFT JOIN
Orders o
ON o.CustomerID = c.CustomerID
GROUP BY c.CustomerName;
Notes:
Table aliases (c and o) make the query easier to write and to read.
The LEFT JOIN keeps all customers, even those without orders. If you don't want 0 counts, then change to an INNER JOIN.
All joins should have an ON clause, not a WHERE clause for the JOIN conditions.
The GROUP BY is also needed to fix your query attempt.
Use:
SELECT Customers.CustomerName, Count(*)
FROM Orders LEFT OUTER JOIN Customers
WHERE Orders.CustomerID=Customers.CustomerID GROUP BY Customers.CustomerName;
SELECT CustomerName,ISNULL(_Count,0) [Count]
FROM Customer
LEFT OUTER JOIN
(
SELECT COUNT(*) _Count,CustomerId _CustomerId
FROM Orders
GROUP BY CustomerId
) A ON _CustomerId = CustomerID

Inner join gives undesired result with row number in sql server

I've tried to do a pagination on data in using ROW_NUMBER()
Here is my query:
SELECT * FROM
(SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS Row,* FROM SpecificOrders)
AS EMP
inner join Users as c on EMP.UserID = c.UserID
inner join Users as u on EMP.CreatedBy = u.UserID
inner join SpecificOrderPayment as p on EMP.OrderID= p.OrderID
WHERE Row BETWEEN 0 AND 10
When I execute this query, I get output like following with :
Row | OrderID | UserID |
1 | | |
5 | | |
6 | | |
7 | | |
8 | | |
9 | | |
10 | | |
If I remove this WHERE Row BETWEEN 0 AND 10 condition then it'll gives me all records
Here my question is why I get only 7 rows and why here 2,3 and 4 is missing in the row column.
Moreover, If i remove 3rd join query (SpecificOrderPayment)then it will give me proper result.
you've got OrderID that are null or blanks in SpecificOrders and they are sorting to the top - the approach isn't wrong otherwise, although there are other ways of doing it such as TOP 10..etc
SELECT * FROM
(SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS Row,* FROM SpecificOrders
WHERE RTRIM(COALESCE(OrderID, '')) <> '')
AS EMP
inner join Users as c on EMP.UserID = c.UserID
inner join Users as u on EMP.CreatedBy = u.UserID
inner join SpecificOrderPayment as p on EMP.OrderID= p.OrderID
WHERE Row BETWEEN 0 AND 10
The problem is that you are numbering the rows of SpecificOrders and not of final result.
In your case you only have one row per order, so using left joins should solve the issue
But, if the inner query could return multiple rows for each OrderID you will see the same row number many times
And if the join (inner) will filter some row you will not get that row number in result.
You have simply to separate the query for data extraction from the query for pagination,
Try this:
SELECT *
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY EMP.OrderID) AS Row, EMP.*
FROM SpecificOrders AS EMP
left join Users as c on EMP.UserID = c.UserID
left join Users as u on EMP.CreatedBy = u.UserID
left join SpecificOrderPayment as p on EMP.OrderID= p.OrderID
) D
WHERE [Row] BETWEEN 0 AND 10

Stored procedure containing inner join with count not working

Let's say i've got a databasetable looking a bit like this, containing information about some assignments.
Id | ProfessionId | Title | Deadline | DateCreated | ClosingDate
1 | 5 | Something | 01-12-2012 | 05-11-2012 | 12-11-2012
2 | 6 | Something | 01-12-2012 | 05-11-2012 | 12-11-2012
3 | 7 | Something | 01-12-2012 | 05-11-2012 | 12-11-2012
4 | 7 | Something | 01-12-2012 | 05-11-2012 | 12-11-2012
I want to generate an overview foreach profession (assignments belong to a certain profession) and count the number of assignment in each profession. The overview coming from the database should look like this;
Id | Name | FriendlyUrl | Ordinal | NumberOfAssignments
5 | Profession 1 | profession-1 | 1 | 1
6 | Profession 2 | profession-2 | 1 | 1
7 | Profession 3 | profession-3 | 1 | 2
8 | Profession 4 | profession-4 | 1 | 0
I've currently got a stored procedure returning the overview above, except that the amount of assignments isn't correct. Assignments with a closingdate in the past (we then assume the assignment is closed) shouldn't be taken into the the total number of assignment.
The current stored procedure is like this:
BEGIN
SELECT p.Id,
p.Naam,
p.FriendlyUrl,
p.Ordinal,
COUNT(a.ProfessionId) AS NumberOfAssignments
FROM ME_Profession AS p
LEFT OUTER JOIN ME_Assignment AS a ON a.ProfessionId = p.Id
INNER JOIN ME_Client AS c ON a.ClientId = c.Id
INNER JOIN aspnet_Membership AS m ON m.UserId = c.UserId
WHERE m.IsApproved = 1
GROUP BY p.Id, p.Naam, p.FriendlyUrl, p.Ordinal
END
I've already came up with and modified procedure like the one below, but it doesn't work. It feels like i'm either thinking too difficult or missing something obvious. What could go wrong?
SELECT p.Id, p.Naam, p.FriendlyUrl, p.Ordinal, pc.NumberOfAssignments
FROM ME_Profession AS p
INNER JOIN ME_Assignment AS a ON a.ProfessionId = p.Id
INNER JOIN ME_Client AS c ON a.ClientId = c.Id
INNER JOIN aspnet_Membership AS m ON m.UserId = c.UserId
INNER JOIN (SELECT a2.ProfessionId, COUNT(*) AS NumberOfAssignments FROM ME_Assignment AS a2 GROUP BY a2.ProfessionId WHERE a2.Closingdate > GETDATE()) pc ON p.ProfessionId = pc.ProfessionId
WHERE m.IsApproved = 1 AND a.Closingdate > GETDATE()
GROUP BY p.Id, p.Naam, p.FriendlyUrl, p.Ordinal
UPDATE 1: Added where condition for date
I don't think that you need to join against the table ME_profession again, try this:
SELECT p.Id, p.Naam, p.FriendlyUrl, p.Ordinal, pc.NumberOfAssignments,
COUNT(CASE WHEN ClosingDate > GETDATE() OR ClosingDate IS NULL THEN 1 END) AS NumberOfAssignments
FROM ME_Profession AS p
INNER JOIN ME_Assignment AS a
ON a.ProfessionId = p.Id
INNER JOIN ME_Client AS c
ON a.ClientId = c.Id
INNER JOIN aspnet_Membership AS m
ON m.UserId = c.UserId
WHERE (m.IsApproved = 1)
GROUP BY p.Id, p.Naam, p.FriendlyUrl, p.Ordinal
How about ... LEFT OUTER JOIN (SELECT * FROM ME_Assignment WHERE ClosingDate > GETDATE()) as a ...
I don't see criteria in the current stored procedure that would satisfy this statement:
Assignments with a closingdate in the past (we then assume the
assignment is closed) shouldn't be taken into the the total number of
assignment.
It may be you simply need to add the criteria you have in your work in progress to the existing proc:
WHERE ClosingDate > GETDATE()