Find avg of each row from the grand total - sql

I have a sales table sale with following columns
sale_id | Department | gross_amount
I need to find the avg of sales in each department from the total sale
eg:-
Table
sale_id Department gross_amount
1 A 10
2 B 30
3 A 25
4 c 5
Desired output
Department Gross_amount avg
A 35 50 --(35/70)*100
B 30 42.86 --(30/70)*100
C 5 7.14 --(5/70) *100
ie is dept_avg = (dept_total / total) *100
eg:- dept_total of A = 35
total = A+B+C = 35+30+5 =70
I am able to find up to Gross_amount
select Department ,sum(si.GrossPrice) gross_amt
from Sale si
group by Department
order by Department
For getting avg I tried follow
select Department ,sum(si.GrossPrice) gross_amt,
AVG(sum(si.GrossPrice)) avg
from Sale si
group by Department
order by Department
It is giving me an error
Cannot perform an aggregate function on an expression containing an
aggregate or a subquery.
Also I am not sure i can get my expected avergage with the above query. How can I achieve the same.

Divide grouped sum by total sum:
SqlFiddleDemo
SELECT Department ,
[Gross_amount] = SUM(gross_amount),
[avg] = ROUND(CAST(SUM(gross_amount) AS DECIMAL(10,2))/
CAST((SELECT SUM(gross_amount) FROM tab) AS DECIMAL(10,2)) * 100
,2)
FROM tab
GROUP BY Department
ORDER BY Department

If you want the proportion of the total for each department out of the overall total, I would suggest using window functions:
SELECT Department, SUM(gross_amount) as gross_amount
SUM(gross_amount)*100.0 / SUM(SUM(gross_amount)) over () as propotion
FROM tab
GROUP BY Department
ORDER BY Department;

Related

To group by department take sum(sales) and the create separate column with sum(sales) for the entire table in hive?

I have a table like this
Department Sales
A 2000
A 2000
A 3000
B 1000
B 4000
B 2000
C 2500
C 2000
C 2000
No I want My output like
Department Sales Total_Sales
A 7000 20500
B 7000 20500
C 6500 20500
How to achieve this using hive, Window functions?
It can be something like
SELECT DISTINCT
Department,
SUM(Sales) OVER (PARTITION BY Department) Sales,
SUM(Sales) OVER () Total_Sales
FROM source_table
But
SELECT Department,
SUM(Sales) Sales,
FROM source_table
GROUP BY Department WITH ROLLUP
may be more useful (total sales will be calculated in additional row with Department IS NULL).
select *,sum(sales) over() as Total_Sales
from(select department,sum(sales) as sales from orders group by department)t1;

how to add grand total row in bigquery?

I have got the results in the following format
customer ; Sales
A ; 1000
B ; 1500
c ; 2500
I want to add a grand total row in the results like
customer ; Sales
A ; 1000
B ; 1500
c ; 2500
Grand Total ; 5000
how can I do this?
I have tried roll up function
Select customer, sales from `xyz`
group by customer
expecting grand total in the output
To add a new row to the query you had, you can use the WITH statement, and use a query like the following:
WITH grand_total AS (SELECT SUM(sales) as grand_total FROM TABLE_NAME)
SELECT customer, sales FROM TABLE_NAME
UNION DISTINCT
SELECT 'grand_total' as customer, grand_total.grand_total from grand_total;
which will output the following:
Row customer sales
1 B 1500
2 C 2500
3 A 1000
4 grand_total 5000
You can read more information about the WITH statement in the public documentation.

How to create a oracle view of the max sum of a sum of values of a column based on the values of another

I need to create a view in Oracle 11g that would take these tables:
employees
FirstName | LastName | EmployeeID
-----------------------------------
joe | shmo | 1
bob | moll | 2
salesData
Employee ID | commission on sale
----------------------------------
1 | $20
1 | $30
2 | $50
2 | $60
and then sum up the total commission each employee earned and return the employee who earned the most commission.
So using the sample data the view will contain the employee id :: 2 or bob moll.
This should get you what you need
Create someviewname as view
Select EmployeeID, sum (commision)
from employees
left outer join salesData on salesData.EmployeeID = employees.EmployeeID
Group by EmployeeID, commision
order by commission desc
SELECT employeeID
FROM
(SELECT employeeID,
SUM(commission)
FROM sales
GROUP BY employeeID
ORDER BY SUM(commission)
)
WHERE rownum = 1
Not sure why you want a view of that, but hopefully, you can figure that out.
In Oracle 12g+, you can use fetch:
select employeeid
from sales
group by employeeid
order by sum(commission) desc
fetch first 1 row only;
In earlier versions, one method is to use rownum:
select s.*
from (select employeeid
from sales
group by employeeid
order by sum(commission) desc
) s
where rownum = 1;

Multiple counts with different conditions

I want to retrieve and display on one row, the number of sales made by an employee followed by the total number of sales.
SELECT COUNT(SalesID) AS SalesForEmployee, COUNT(SalesID) AS TotalSales
FROM Sales
WHERE EmployeeID = 123
How do I make it so that the where clause only applies to the first column in the select?
SELECT
sum(case when EmployeeID = 123 then 1 else 0 end) AS SalesForEmployee
,COUNT(SalesID) AS TotalSales
FROM Sales
select count(SalesEmp.SalesID) AS SalesForEmployee count(Sales.salesID) As TotalSales
from Sales left outer join Sales as SalesEmp
on Sales.salesID=SalesEmp.SalesID
and SalesEmp.EmployeeID = 123
You can't have a where that only applies to one column.
In order to get both counts while only scanning the table once, you can do this:
select
sum(case when EmployeeID=123 then 1 else 0 end) as SalesForEmployee,
Count(SalesID) as TotalSales
from Sales
There's no where clause because Count(SalesID) needs to count every row to give you the total count.
Since you have to look at every row, case when EmployeeID=123 then 1 else 0 end gives you a 1 for each row that belongs to the target employee and a 0 for every row that doesn't. Therefore, summing that expression gives you the count only for that employee.
SalesID EmployeeID (case when ... )
1 123 1
2 311 0
3 333 0
4 123 1
5 300 0
count = 5 sum = 2
You could also do it like this:
select
(select count(SalesID) from Sales where EmployeeID=123) as SalesForEmployee,
(select count(SalesID) from Sales) as TotalSales
But now you are scanning the Sales table twice, which will be slower.
This is a nested subquery approach combining two select statements into one.
SELECT
(SELECT COUNT(SalesID) FROM Sales WHERE EmployeeID = 123) AS SalesForEmployee,
(SELECT COUNT(SalesID) FROM Sales) AS TotalSales
Another way to write it would be like this.
SELECT COUNT(SalesID) AS SalesForEmployee,
(SELECT COUNT(SalesID) FROM Sales) AS TotalSales
FROM Sales WHERE EmployeeID = 123
With a correlated subquery, you can link the outer query with the inner query. Say you wanted to get the Total sales not including the sales of EmployeeID 123
SELECT COUNT(SalesEmployee.SalesID) AS SalesForEmployee,
(SELECT COUNT(SalesID) FROM Sales WHERE Sales.EmplyeeID <> SalesEmployee.EmployeeID) AS TotalSales
FROM Sales As SalesEmployee WHERE SalesEmployee.EmployeeID = 123
Here the inner query is referencing the outqueries EmployeeeID in the WHERE clause to filter them out.

How to select items according to their sums in SQL?

I've got the following table:
ID Name Sales
1 Kalle 1
2 Kalle -1
3 Simon 10
4 Simon 20
5 Anna 11
6 Anna 0
7 Tina 0
I want to write a SQL query that only returns the rows that
represents a salesperson with sum of sales > 0.
ID Name Sales
3 Simon 10
4 Simon 20
5 Anna 11
6 Anna 0
Is this possible?
You can easily get names of the people with the sum of sales that are greater than 0 by using the a HAVING clause:
select name
from yourtable
group by name
having sum(sales) > 0;
This query will return both Simon and Anna, then if you want to return all of the details for each of these names you can use the above in a WHERE clause to get the final result:
select id, name, sales
from yourtable
where name in (select name
from yourtable
group by name
having sum(sales) > 0);
See SQL Fiddle with Demo.
You can make it like this, I think the join will be more effective than the where name in() clause.
SELECT Sales.name, Sales.sales
FROM Sales
JOIN (SELECT name FROM Sales GROUP BY Sales.name HAVING SUM(sales) > 0) AS Sales2 ON Sales2.name = Sales.name
This will work on some databases, like oracle, mssql, db2
SELECT ID, Name, Sales
FROM
(
SELECT ID, Name, Sales, sum(sales) over (partition by name) sum1
FROM <table>
) a
WHERE sum1 > 0