find percentage of sale and percentage of returns - sql

I have a table in MS SQL DB which contains transactions of any company, there are two columns
sub_cat_code
total_amount
The total_amount contain sometimes positive and sometimes negative value. Where positive values indicates the sale and negative value indicates Returns.
Now, I need to find the percentage of sales and percentage of return using following query, in percentage of return column every value coming same. any help would be appreciable.
Select prod_subcat_code ,
(sum(total_amt)*100 /(select sum(total_amt) from transection)) as
Sale_pers,
((select sum(total_amt) from transection where total_amt<0)*100/(select
sum(total_amt) from transection)) as return_sale
from transection
group by prod_subcat_code
order by Sale_pers desc

Use a CTE which returns the total sales and total returns of the table:
with cte as (
select
sum(case when total_amount > 0 then total_amount else 0 end) total_sales,
sum(case when total_amount < 0 then total_amount else 0 end) total_returns
from transection
)
select prod_subcat_code ,
100.0 * sum(case when total_amount > 0 then total_amount else 0 end) / (select total_sales from cte) as sale_perc,
100.0 * sum(case when total_amount < 0 then total_amount else 0 end) / (select total_returns from cte) as return_perc
from transection
group by prod_subcat_code
See the demo.

If I understand correctly, you just want to divide two aggregated values:
Select prod_subcat_code,
sum(total_amt) as net_sales,
sum(case when total_amt > 0 then total_amt else 0 end) as sales,
sum(case when total_amt < 0 then total_amt else 0 end) as returns,
(sum(case when total_amt > 0 then total_amt else 0 end) /
nullif(sum(total_amt), 0)
) as sales_ratio,
(sum(case when total_amt < 0 then total_amt else 0 end) /
nullif(sum(total_amt), 0)
) as return_ratio
from transection
group by prod_subcat_code;

You may want change your query to this for desired result:
Select prod_subcat_code,
sum(case when total_amt > 0 then total_amt else 0 end) as sales,
(sum(case when total_amt > 0 then total_amt else 0 end) /
(sum(total_amt)) ) * 100 as sales_Percent,
sum(case when total_amt < 0 then total_amt else 0 end) as [returns],
(sum(case when total_amt < 0 then total_amt else 0 end) /
(sum(total_amt)) ) * 100 as Return_Percent
from transection
group by prod_subcat_code
order by sales_Percent desc

Hope it will help you,
SELECT prod_subcat_code
,(SUM(CASE WHEN total_amt > 0 THEN total_amt END)/sum(total_amt))*100 AS Sales_Percentage
,(SUM(CASE WHEN total_amt < 0 THEN total_amt END)/sum(total_amt))*100 AS Return_Percentage
FROM transection
GROUP BY prod_subcat_code;

Related

SQL row in column

I have this SQL query
SELECT COUNT(*)*100/(SELECT COUNT(*) FROM tickets WHERE status = 'closed')
FROM tickets
WHERE closed_at <= due_at
UNION
SELECT COUNT(*)*100/(SELECT COUNT(*) FROM tickets WHERE status = 'closed')
FROM tickets
WHERE closed_at > due_at;
and it returns this
ROW 1 - 35
ROW 2 - 47
but I need the return like this:
1 | 2 |
35 47
I need the returns in columns, not rows.
Thanks.
Use conditional aggregation. I would recommend:
SELECT (SUM(CASE WHEN closed_at <= due_at THEN 100.0 ELSE 0 END) /
SUM(CASE WHEN status = 'closed' THEN 1 ELSE 0 END)
),
(SUM(CASE WHEN closed_at > due_at THEN 100.0 ELSE 0 END) /
SUM(CASE WHEN status = 'closed' THEN 1 ELSE 0 END)
)
FROM tickets ;
It seems strange that you are filtering on status = 'closed' in the denominator, but not in the numerator. If status = closed should be the filter for both, then you can simplify this to:
SELECT AVG(CASE WHEN closed_at <= due_at THEN 100.0 ELSE 0 END),
AVG(CASE WHEN closed_at > due_at THEN 100.0 ELSE 0 END)
FROM tickets
WHERE status = 'closed';

rank out of the total in postgres

I am writing a sql script in which I want to get total number of appointments per salesperson then also get how much he rank out of the rest salesperson. e.g Salesperson x has 5 appointment and he rate 4 out of 10 salespersons.
**expected results**:
Salesperson x 5 4/10
Salesperson D 6 5/10
Salesperson s 8 7/10
Use rank()
with sales as
(
select Salesperson, count(appointment) appointments
from SalesTable
group by Salesperson
)
select sales.*, rank() over (order by appointments desc) as salesrank
from sales
Hi Thanks for your response. I tried it this way it works:
select id,sales_person,"Appointment/Day",rank_for_the_day,"Appointment/Week",rank_for_the_week,"Appointment/Month",
rank_for_the_month,"Appointment/year",rank_for_the_year
from(
select supplied_id,salesperson,sum(case when appointment_date::date=current_date then 1 else 0 end )"Appointment/Day",
rank() over (order by sum(case when appointment_date::date=current_date then 1 else 0 end ) desc )||'/'||
(select sum(case when appointment_date::date=current_date then 1 else 0 end ) from match where date_part( 'year', appointment_date)=2017
and appointment_date is not null and date_part('day',appointment_date)=date_part('day',current_date) ) rank_for_the_day,
sum(case when appointment_date::date between current_date-7 and current_date then 1 else 0 end )"Appointment/Week",
rank() over (order by sum(case when appointment_date::date between current_date-7 and current_date then 1 else 0 end ) desc)||'/'||
(select sum(case when appointment_date::date between current_date-7 and current_date then 1 else 0 end )
from match m where date_part( 'year', appointment_date)=2017 and appointment_date is not null
and date_part('week',appointment_date)=date_part('week',current_date) ) rank_for_the_week,
sum(case when date_part('month',appointment_date)=date_part('month',current_date) then 1 else 0 end )"Appointment/Month",
rank() over (order by sum(case when date_part('month',appointment_date)=date_part('month',current_date) then 1 else 0 end ) desc)||'/'||
(select sum(case when date_part('month',appointment_date)=date_part('month',current_date) then 1 else 0 end )
from match m where date_part( 'year', appointment_date)=2017 and appointment_date is not null
and date_part('month',appointment_date)=date_part('month',current_date) ) rank_for_the_month,
sum(case when date_part('year',appointment_date)=date_part('year',current_date) then 1 else 0 end )"Appointment/year",
rank() over (order by sum(case when date_part('year',appointment_date)=date_part('year',current_date) then 1 else 0 end ) desc)||'/'||
(select sum(case when date_part('year',appointment_date)=date_part('year',current_date) then 1 else 0 end )
from match m where date_part( 'year', appointment_date)=2017 and appointment_date is not null
and date_part('year',appointment_date)=date_part('year',current_date) ) rank_for_the_year
from salespersontable
where date_part( 'year', appointment_date)=2017 and appointment_date is not null
group by id,salesperson
)x order by 6 desc
However,I would appreciate an efficient way to write this query to minimize resource consumption.

count row with total

From tbl Department, I am trying to write a stored procedure to display output as shown below where I can find the count from each row based on following conditions:
Total = 100
Total >100 and <=200
Total >200 and <=300
Total >300
set #select = 'select count(*) as Orders, sum (tbl.Expenses) as Total from tbl group by tbl.Department'
So, how can I dynamically get the output for 4 conditions as shown above based on my #select statement.
I think you just want conditional aggregation:
select sum(case when total = 100 then 1 else 0 end) as condition1,
sum(case when total > 100 and total <= 200 then 1 else 0 end) as condition2,
sum(case when total > 200 and total <= 300 then 1 else 0 end) as condition3,
sum(case when total > 300 then 1 else 0 end) as condition4
from department d;
Hope that it would be helpful to you,
Select total,
Sum (Case when total = 100 then NumberOfOrders_Created end ) As "Condition1",
Sum (Case when total > 100 and total <= 200 then NumberOfOrders_Created end ) As "Condition2",
Sum (Case when total > 200 and total <= 300 then NumberOfOrders_Created end ) As "Condition3",
Sum (Case when total > 200 and total <= 300 then NumberOfOrders_Created end ) As "Condition4",
From Department
where
Orders_date between '2013-01-01 00:00:00' and '2013-12-31 00:00:00'
group by 2
order by 1 Desc

Incremental adding in sql select

I have a table where customer transactions are stored in this format:
Account Tran_type Tran_Amount tran_particular Tran_date
165266 C 5000 deposit 19_SEP-2014
165266 D 3000 withdrawal 20-SEP-2014
165266 C 8000 Deposit 21-SEP-2014
I am attempting to extract the Information for a Statement like this:
select tran_date, tran_particular,
(case when tran_type = 'C' then tran_amt else 0 end) CREDIT,
(case when tran_type = 'D' then tran_amt else 0 end) DEBIT
from tran_table order bby tran_date asc;
Is there a wat to add the Balance column on each row so it would show the Balance after the Transaction? say:
DATE DESC CREDIT DEBIT BALANCE
19-SEP-2014 DEPOSIT 5000 0 5000
20-SEP-2014 WITHDRAWAL 3000 2000
21-SEP-2014 DEPOSIT 8000 0 10000
Please assist.
EDIT I have trie the aswers suggested but it seems my balance is tagged to the date. See the output I have currently:
See the Balance does not change until the date changes.
select tran_date, tran_particular, Credit, Debit,
SUM(Delta) OVER (ORDER BY tran_date) AS Balance
from
(
select tran_date, tran_particular,
Case Tran_Type
When 'C' THEN Tran_Amount
Else 0
End AS Credit,
Case Tran_Type
When 'D' THEN Tran_Amount
Else 0
End AS Debit,
Case Tran_Type
When 'C' THEN Tran_Amount
When 'D' THEN -1 * Tran_Amount
Else 0
End AS Delta
from TRANSACTIONS
order by tran_date
)
Should do it
Select *,Sum( case when type ='C'
then amount
else -amount
end ) over (ORDER BY date ROWS
BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW )'Balance'
from #tt1
That will cost a sub-query:
SELECT tran_date, tran_particular,
(CASE when tran_type = 'C' THEN tran_amt ELSE 0 end) CREDIT,
(CASE when tran_type = 'D' THEN tran_amt ELSE 0 end) DEBIT,
(SELECT
SUM(CASE when type = 'C' tran_amt ELSE (-1) * tran_amt end)
FROM tran_table trn2
WHERE
trn2.Account = trn1.Account
AND trn2.tran_id <= trn1.tran_id
-- AND trn2.tran_date <= trn1.tran_date
)
BALANCE
FROM
tran_table trn1 ORDER BY tran_date asc;
In large scale data, having such a sub-query is not recommended. Having a materialized view is more rational.

How to separate positive and negative numbers into their own columns?

I have a table with the following columns and data:
activity_dt | activity_amt
2009-01-01 | -500
2009-01-01 | 750
Can I write a query that looks at the sign of activity_amt and puts it in the credits column if it's positive, and the debits column if it's negative? (I'm using Sybase)
activity_dt | debits | credits
2009-01-01 | -500 | 750
select activity_dt,
sum(case when activity_amt < 0 then activity_amt else 0 end) as debits,
sum(case when activity_amt > 0 then activity_amt else 0 end) as credits
from the_table
group by activity_dt
order by activity_dt
I'm not sure about the exact syntax in Sybase, but you should be able to group on the date and sum up the positive and negative values:
select
activity_dt,
sum(case when activity_amt < 0 then activity_amt else 0 end) as debits,
sum(case when activity_amt >= 0 then activity_amt else 0 end) as credits
from
theTable
group by
activity_dt
I found a new answer to this problem using the DECODE function.
I hope this turns out to be useful for everyone.
select activity_dt,
sum((DECODE(activity_amt /-ABS(activity_amt), 1, activity_amt, 0))) as credits,
sum((DECODE(activity_amt /-ABS(activity_amt), -1, activity_amt, 0))) as debits
from the_table
group by activity_dt
order by activity_dt;
select (select JV_GroupsHead.GroupTitle
from JV_GroupsHead
whereJV_GroupsHead.Id=jv.GroupId) as 'GroupName'
,jv.Revenue
,jv.AccountNo
,jv.AccountNoTitle
,(case when jv.Revenue < 0 then jv.Revenue else 0 end) as 'debits'
,(case when jv.Revenue> 0 then jv.Revenue else 0 end) as 'credits'
from JVFunction1('2010-07-08','2010-08-08') as jv