Taking SUM of values that are obtained from SUM of another column - sql

I have a MSSQL query in which I am taking grandtotal, which is a SUM of values that are obtained by taking SUM.
select
s.name
,SUM(b.dAmount) as total
,SUM(SUM(b.dAmount)) as grandtotal
from t_sales a
left outer join t_cust b on (b.dId=a.id)
where a.custId=#customerId
GROUP BY b.name;
I can get the name and total but grandtotal doesn't return any value. Please let me know what is the correct way to take SUM of values that are SUM of another values.Thanks

Try this:
select
b.name
,SUM(b.dAmount) as total
, SUM(SUM(b.dAmount)) OVER () as grandtotal
from t_sales a
left outer join t_cust b on (b.dId=a.id)
where a.custId=#customerId
GROUP BY b.name;

In MySQL, you can't do this without either using a nested subquery or by using the GROUP BY WITH ROLLUP
For your case, I'd recommend just using the WITH ROLLUP keyword, this will add another row to the result set with the grand total. It will also avoid returning the same total on every row of the set.
SELECT IFNULL(s.name, 'Total'), SUM(b.dAmount) as total
FROM t_sales a
LEFT OUTER JOIN t_cust b ON (b.dId = a.id)
WHERE a.custId = #customerId
GROUP BY b.name WITH ROLLUP;
If you're not directly displaying the results you can remove the IFNULL(s.name, 'Total') bit - the super-aggregate will have nulls on all columns not in the SUM()

You can also try this
create table #t_sales (name varchar(100),amount numeric(18,2))
INSERT INTO #t_sales (name,amount)
values ('A',100.00)
,('B',200.00)
,('C',300.00)
,('C',400.00)
INSERT INTO #t_sales (name,amount)
values ('A',100.00)
,('B',200.00)
,('C',300.00)
,('C',400.00)
SELECT CASE WHEN (GROUPING(name) = 1) THEN 'GRAND TOTAL'
ELSE ISNULL(name, ' ')
END AS [type]
,SUM(amount) AS TOTAL
FROM #t_sales
GROUP BY name WITH ROLLUP

Related

How to get the % of a SUM colum in the same query

I have a query that SUM all the amounts GROUP BY different categories. I would like to get as well the % of that SUM amount by the total.
My query is the next:
SELECT category.name, SUM(account.amount_default_currency) FROM account
INNER JOIN accounts ON account.accounts_id = accounts.id
INNER JOIN category ON account.category_id = category.id
INNER JOIN category_type ON category.category_type_id = category_type.id
GROUP BY category.name;
And I get:
name
SUM
salary
230
restaurants
2254
How could I do it?
Divide each sum by the total, which you can get in the same SELECT with a window function over the aggregate function:
SELECT c.name
, sum(a.amount_default_currency) AS sum
, round(sum(a.amount_default_currency) * 100.0
/ sum(sum(a.amount_default_currency)) OVER (), 2) AS pct
FROM category c
JOIN account a ON a.category_id = c.id
GROUP BY c.name; -- c.id ??
This works because window functions are applied after aggregate functions. See:
Postgres window function and group by exception
I removed joins to accounts and category_type, which are probably just ballast for the query, assuming the dropped joins wouldn't eliminate rows.
If category.id is the primary key of that table, rather use GROUP BY c.id, and include c.id in the SELECT list. ("name" is not necessarily unique?) See:
PostgreSQL - GROUP BY clause

SQL Query to remove duplicated data and take single column sum

I have the following table resulted from
SELECT m.MedName as [Medicine],m.MedSellPrice as [RetailPrice],m.MedType as [Type],
m.SoldQuantity as [Sold],m.Quantity as [Available],b.BillAmount as [Total Bill],b.BillDate
FROM BillMedicine AS bm LEFT JOIN
Medicine AS m
ON bm.MedicineID=m.id LEFT JOIN
Bill AS b
ON bm.BilIID = b. ID
but now I want to remove the repeated rows except the Sum of 'TotalBill'.
Use GROUP BY:
SELECT
m.MedName AS [Medicine],
m.MedSellPrice AS [RetailPrice],
m.MedType AS [Type],
m.SoldQuantity AS [Sold],
m.Quantity AS [Available],
SUM(b.BillAmount) AS [Total Bill]
FROM BillMedicine AS bm
LEFT JOIN Medicine AS m
ON bm.MedicineID = m.id
LEFT JOIN Bill AS b
ON bm.BilIID = b.ID
GROUP BY
m.MedName,
m.MedSellPrice,
m.MedType,
m.SoldQuantity,
m.Quantity;
Note that for the billing date, the two "duplicate" records you have highlighted have different dates. It is not clear which date, if any, you want to report here. I have omitted this column.
GROUP BY Is Best Option for DUPLICATE DATE Removed & SUM.
Select Column1,column2....., SUM(Total) as Total From Tablename Group BY column1,column2
You seem to want most (or all) columns from m and then the sum from another table. One method is a lateral join or correlated subquery:
SELECT m.*, -- or whatever columns you want,
(SELECT SUM(b.BillAmount)
FROM BillMedicine bm JOIN
Bill b
ON bm.BilIID = b.ID
WHERE bm.MedicineID = m.id
) as [Total Bill]
FROM Medicine m ;
I suggest this approach for several reasons.
This is often more efficient than an outer aggregation.
You have LEFT JOINs but they do not look correct. I suspect you want to start with the Medicine table.
You are including a date/time in the results, but clearly that is not appropriate when combining multiple rows.

Sql Join and Sum

I'm trying to sum an amount from two different tables using a left join. I need all rows returned regardless of whether or not there is a match on the second table.
SELECT l.tender,
l.starting+SUM(t.amount) AS 'amount'
FROM label l
LEFT JOIN transfers t on l.tender=t.name
ORDER BY l.tender
This should work:
SELECT l.tender,
l.starting + ISNULL(t.amount,0) AS amount
FROM label l
LEFT JOIN ( SELECT name, SUM(amount) amount
FROM transfers
GROUP BY name) t
ON l.tender = t.name
ORDER BY l.tender
Wrap the SUM(amount) in a COALESCE function so that if there is no match and it is NULL, it will add 0 and won't mark the whole row as NULL.
Change line 2 of your query to look like this:
l.starting + COALESCE(SUM(t.amount), 0) AS amount
Edit:
As #Lamak noted, you also need to GROUP BY your results so that you can SUM it properly. The whole query can look like this (alternative to the other answer):
SELECT l.tender,
l.starting + COALESCE(SUM(t.amount), 0) AS amount
FROM label l
LEFT JOIN transfers t on l.tender=t.name
GROUP BY l.tender, l.starting
ORDER BY l.tender

sql count statement leads to wrong value

select count(d.Games_played),count(d.No_ofgames) from
(
SELECT COUNT(UserGamePlayed.intID) AS 'Games_played',games.vchCompetency,b.No_Games as 'No_ofgames'
FROM UserGamePlayed
inner join games on games.intGameID=UserGamePlayed.intGameID
inner join
(
select COUNT(Games.intGameID) AS 'No_Games',vchCompetency,intGradeID from Games
WHERE intGradeID=3
GROUP BY vchCompetency,intGradeID
) as b on b.vchCompetency=games.vchCompetency
WHERE intUserID=403 and UserGamePlayed.intGradeID=3
GROUP BY games.vchCompetency,b.No_Games
)as d
the table which i get from d is:
As per the table d i want to get a count of played,when exicute a full i am getting
You should replace COUNT with SUM (in your outer select only).
COUNT only counts (as the name indicates ;)) the rows while SUM will add up the values that are passed to it.

How can I SELECT a result set of data from a single table with one of the columns coming from the SUM of a column in a different table?

So let's say I want 5 columns total in my result set, for example:
Name, Date, Color, Price, TotalSales
Name, Date, Color, and Price are all stored in a single table so I will just get every row from that table.
SELECT * FROM AwesomeStuff
However, TotalSales needs to be calculated from the SUM of values in another table, and the values that needed to be combined must match up with the ID of the row from the AwesomeStuff table.
SELECT SUM(SalePrice) FROM AwesomeSales
Each row in the AwesomeSales table has an ID that matches a single item in the AwesomeStuff table. So I want to add up all the SalePrice values into a single column and match it up with the correct row in the AwesomeStuff query so I get back the single result set.
How does this work? Along with the query, can you explain what SQL is doing in plain english so I can understand how to write this type of SELECT again in the future?
Thanks.
You can perform a GROUP BY operation to group the results per "AwesomeStuff" item:
SELECT
A.Name,
A.Date,
A.Color,
A.Price,
SUM(S.SalePrice) AS TotalSales
FROM
AwesomeStuff A
INNER JOIN
AwesomeSales S
ON
S.AwesomeStuffId = A.Id
GROUP BY
A.Name,
A.Date,
A.Color,
A.Price
select
t.name,
t.date,
t.color,
t.price,
a.TotalSales
from awesomestuff t
inner join
(
select id, sum(saleprice) as TotalSales
from awesomesales
group by id
)a
on t.id = a.id
What this does is calculates the SUM() based on each id. And then with an inner join it creates the relationship for the TotalSales per id to show in the result set.
The SQL to do what you want is:
select AwesomeStuff.Name,
AwesomeStuff.Date,
AwesomeStuff.Color,
AwesomeStuff.Price,
AwesomeStuff.TotalSales,
TotalSales.Price
from AwesomeStuff
join (select AwesomeSales.id,
sum(AwesomeSales.SalePrice) As Price
from AwesomeSales
group by id) As TotalSales
on TotalSales.id = AwesomeStuff.id;
I will update this post after lunch with an English explanation.
English You aggregate the sale prices, taking the sum, grouped by their ID. This is what the inline view (sub-query) does: we include the ID because we need to use it in the join. That is we join your AwesomeStuff table with the inline view of sales (aliased as TotalSales, as we refer to it later), match them by ID -- as this is the primary key -- and then select all the fields (including the calculated sum, which we have aliased as Price) together.
You could use a subquery if your Database supports it:
SELECT stuff.Name, stuff.Date, stuff.Color, stuff.Price, sales.total
FROM AwesomeStuff AS stuff,
(SELECT STUFF_ID, SUM(SalePrice) AS total
FROM AwesomeSales
GROUP BY STUFF_ID) AS sales
where stuff.ID = sales.STUFF_ID
SELECT
a.Name,
a.Date,
a.Color,
a.Price,
SUM(s.SalesPrice)
FROM AwesomeStuff as a
INNER JOIN AwesomeSales as s on a.ID = s.AwesomestuffID
GROUP BY a.Name, a.Date, a.Color, a.Price
In plain English, what you are doing is saying give me all the unique combinations of name, date, color and price from your stuff table and a sum of all the sales from the sales table. This assumes that each ID in the stuff table represents a unique combination of name, date, color and price.
Try:
SELECT A.Id, -- not required in select for query to work - included for clarity
max(A.Name),
max(A.Date),
max(A.Color),
max(A.Price),
SUM(S.SalePrice) AS TotalSales
FROM AwesomeStuff A
LEFT JOIN AwesomeSales S ON S.AwesomeStuffId = A.Id
GROUP BY A.Id
By joining AwesomeStuff to AwesomeSales on the product's unique ID, you will get a row returned for every sale of every product - since you only want one row per product, you need to group by the product's unique ID. (The SUM function should be self-explanatory.)
Unfortunately, most forms of SQL will not allow you to include unaggregated values in a grouped query, even where these are functionally dependant on one of the values that is being grouped - as in this query. This is why name, date, color and price have all been MAXed.
A left join ensures that records on the left-hand side of the join (here, AwesomeStuff) will be returned even if there are no corresponding records on the right-hand side of the join (AwesomeSales). In other words, this version of the query will include products that have had no sales.