How to calculate in SQL - sql

How to calculate in SQL
SELECT NO
, SUM(COST)*1.05
FROM TR
WHERE NO in (SELECT NO FROM USERS)
AND TR.TYPE = 'A'
OR TR.TYPE = 'B'
GROUP
BY NO
I would like to calculate the COST:
WHEN TR.TYPE IS A I want to add to the total cost.
WHEN TR.TYPE IS B I want to subtract the cost value from the total.
TR_TABLE
NO,COST,TYPE
1,1000,A
1,500, B
1,200, A
2,100, A
Ideal
No1 COST 700
No2 COST 100

I think that you want a conditional expression within the aggregation function:
select
no,
sum(case when type = 'A' then cost else -cost end) * 0.25 as fuyogaku
from tr
where
tr.type in ('A', 'B')
and exists (select 1 from users u where u.no = c.card_no)
group by no
Note that I rewrote the in condition as an exists condition - both are equivalent here, but exists usually scales better when there is a large number of rows in the subquery.

Related

Counting Booleans for Distinct and Non Distinct ID numbers

I have a simple table that looks like the following PNG file from the following join:
SELECT *
FROM tableA A
JOIN tableB B ON B.Main_SPACE_ID = A.Main_SPACE_ID
Table A contains Guest_ON and User_Controls (last 2 columns) and Table B contains Trigger_ON and DOCX_ON.
Issue:
What I am trying to do is count all the True's for each tableB.Subspace_ID and the DISTINCT trues for tableA.Main_SPACE_ID.
The problem is that subspace_ID from table B lives within the main_space_id from table A and therefore creates a situation where I am double counting.
I only want to count the trues for a distinct Main_space ID
Current Data Model
Desired Output:
From the above screenshot, I am trying to get a count of true values without double counting in the case for tableA_MAIN_SPACE_ID.
As you can see, each row is counted for true values as it relates to the subspace_ID (table B) for totals of 12 and 8 (1 if True, 0 if False) and for tableA, I am only counting distinct values so we only count Trues for a single MainspaceID and avoid recounting them.
If someone can advise on how to get this output from my current data model that would be very helpful!
My attempt as follows double counts trues for the Main space ID column..
SELECT
count(CASE WHEN B.TRIGGER_ON THEN 1 END) as TRIGGER_ON,
count(CASE WHEN B.DOCX_ON THEN 1 END) as DOCX_ON,
count(CASE WHEN A.GUEST_ON THEN 1 END) as SPRINTS,
count(CASE WHEN A.USER_CONTROLS THEN 1 END) as SPRINTS
FROM DataModel
What I am trying to do is count all the True's for each tableB.Subspace_ID and the DISTINCT trues for tableA.Main_SPACE_ID.
You can use conditional aggregation. In Snowflake, you can use the convenient COUNT_IF() for the first two columns. However, for the second two, you need COUNT(DISTINCT) with conditional logic:
SELECT COUNT_IF( B.Trigger_on ) as Trigger_On,
COUNT_IF( B. DOCX_ON ) as DOCX_ON,
COUNT(DISTINCT CASE WHEN A.GUEST_ON THEN A.Main_SPACE_ID END) as GUEST_ON,
COUNT(DISTINCT CASE WHEN A. USER_CONTROLS THEN A.Main_SPACE_ID END) as USER_CONTROLS
FROM tableA A JOIN
tableB B
ON B.Main_SPACE_ID = A.Main_SPACE_ID;
Mabye:
SELECT
COUNT(CASE WHEN B.TRIGGER_ON THEN 1 END) AS TRIGGER_ON,
COUNT(CASE WHEN B.DOCX_ON THEN 1 END) AS DOCX_ON,
(SELECT COUNT(*) FROM (SELECT DISTINCT A.MAIN_SPACE_ID, A.GUEST_ON FROM DataModel WHERE A.GUEST_ON = TRUE) A) AS GUEST_ON
(SELECT COUNT(*) FROM (SELECT DISTINCT A.USER_CONTROLS, A.GUEST_ON FROM DataModel WHERE A.USER_CONTROLS = TRUE) A) AS USER_CONTROLS
FROM DataModel

Select percentage of another column in postgresql

I would like to select, grouped by avfamily, the amount of records that have livingofftheland value equalling true and return it as the perc value.
Essentially column 3 divided by column 2 times 100.
select
avclassfamily,
count(distinct(malware_id)) as cc,
sum(case when livingofftheland = 'true' then 1 else 0 end),
(100.0 * (sum(case when livingofftheland = 'true' then 1 else 0 end) / (count(*)) ) ) as perc
from malwarehashesandstrings
group by avclassfamily having count(*) > 5000
order by perc desc;
Probably quite simple but my brains drawing a blank here.
select, grouped by avfamily, the amount of records that have livingofftheland value equalling true and return it as the perc value.
You could simply use avg() for this:
select
avclassfamily,
count(distinct(malware_id)) as cc,
avg(livingofftheland::int) * 100 as perc
from malwarehashesandstrings
group by avclassfamily
having count(*) > 5000
order by perc desc
livingofftheland::int turns the boolean value to 0 (false) or 1 (true). The average of this value gives you the ratio of records that satisfy the condition in the group, as a decimal number between 0 and 1, thatn you can then multiply by 100.
I would express this as:
select avclassfamily,
count(distinct malware_id) as cc,
count(*) filter (where livingofftheland = 'true'),
( count(*) filter (where livingofftheland = 'true') * 100.0 /
count(distinct malware_id)
) as perc
from malwarehashesandstrings
group by avclassfamily
having count(*) > 5000
order by perc desc;
Note that this replaces the conditional aggregation with filter, a SQL standard construct that Postgres supports. It also puts the 100.0 right next to the /, just to be sure Postgres doesn't decide to do integer division.

SQL formatting for percentage

Using the SQL code
select table.column, count(*) * 100.0 / sum(count(*)) over()
from table
group by table.column
I would like to use this function for its efficiency since I am working on a large DB. The function generates both values of percentage which sum to 100. I can't figure out a simple way to only generate the true value (1) or value of summed number over number of rows in the column. Is there a simple way I can do this or do I need to use a different function entirely ?
An example data set would be
N, Bit
0 | 0
1 | 0
2 | 1
3 | 0
4 | 0
5 | 1
It is a bit, null table where I am taking the percentage of true bits.
The N just stands for Number.
If you ONLY need to know the percentage of true bits, just do this:
SELECT COUNT(NULLIF(Bit, 0)) / CONVERT(Decimal, COUNT(*))
FROM Table
If you need to know the percentaje of true bits by other column (N in this case), you need something like this:
SELECT N, COUNT(NULLIF(Bit, 0)) / t2.C
FROM Table, (SELECT CONVERT(Decimal, COUNT(*)) C FROM Table) t2
GROUP BY N, C
Use SUM in order to count the True Bits.
SELECT
group_column,
100.0 * SUM(CASE WHEN bit_column<>0 THEN 1 ELSE 0 END) / COUNT(*) AS p
FROM myTable
GROUP BY group_column

doing a group by within a group

i have two columns business_line(with values X,Y) and business_segment(values X,Y,Z same X and Y as business_line) in a table with name "Sometable". I have another column with name type_of_payment(with values A,B,C,D,E) and a final column with name transaction_value. This is what i want to do:
Sum the transactions grouped by business_line and business_segment and also find out what proportion of these payments were from A,C,E. So my output table would be something like this
(last three columns can be named anything
but they specify proportions of A,C,E)
Business_line SUM(transaction_value) A C E
and business seg.
X 100 20% 30% 50%
Y 200 11% 12% 77%
X 300 and so on
Y 170
Z 230
How do i do this??
PS : the sums of A C E need not be 100% as B and D are also present
This is standard SQL, should work on Oracle (but untested):
SELECT
business_line,
business_segment,
grand_total,
A_total * 100.0 / grand_total as A,
C_total * 100.0 / grand_total as C,
E_total * 100.0 / grand_total as E
FROM
(
SELECT
business_line,
business_segment,
SUM(transaction_value) as grand_total,
SUM(CASE WHEN payment_type = 'A' THEN transaction_value END) as A_total,
SUM(CASE WHEN payment_type = 'C' THEN transaction_value END) as C_total,
SUM(CASE WHEN payment_type = 'E' THEN transaction_value END) as E_total
FROM
SomeTable
GROUP BY
business_line,
business_segment
) as t
For Oracle 11g and above, you can use PIVOT
select *
from
(
select sometable.line, paymenttype,total, 100.0*transaction_value/total as percentage
from sometable
inner join
(select line, sum(transaction_value) as total
from sometable
group by line) total
on sometable.line = total.line
)
pivot
(
sum(percentage) for paymenttype in (a,c,e)
)

sql query: subtract from results the corresponding USD, YEN value which has Type='r'

I need help with a query. Consider the following table:
I need to select first the sum of each Code from table. I am doing it with simple sum and group by statement. Then I have to subtract the results from each code sum where type='r'
1) Say for first part of query, we will get 2 rows from SUM (one with total USD and one with total YEN)
2) Now I need to subtract from these results the corresponding USD, YEN value which has Type='r'
I have to do it inside SQL and not a stored procedure.
Why not use a WHERE statement to say WHERE Type != 'r' so that those values never even get added to sum in the first place...
SELECT `Code`, SUM(`Amount`) AS `Total`
FROM `Table`
WHERE `Type` != 'r'
GROUP
BY `Code`;
Something like that.
select code, l.amount - r.amount
from
(select code, sum(amount) as amount from my_table group by code) l
left join (select code, sum(amount) as amount from my_table where type = 'r' group by code) r
on l.code = r.code
You can do this in a single, simple query:
select
code,
sum(case when type = 'r' then (-1 * amount) else amount end) as sum
from
yourtable
group by
code
Basically, you're changing the sign of the rows that have type = 'r', so when you sum all rows for a particular code you'll get the correct answer.
Does it have to be a single query?
I'd say SUM the total, then SUM the subcategory where Type='r', then subtract one from the other.
You could do this in one line of SQL, but I'm pretty sure it would be either joining the table with itself or using a subquery. Either way, it's doing the same amount of work as the above.
Try:
select code,
sum(amount) gross_total,
sum(case when type = 'r' then amount else 0 end) type_r_total,
sum(case when type != 'r' then amount else 0 end) net_total
from yourtable
group by code;
to see the overall totals, type R only totals and non-type R totals for each currency on one row per currency, in a single pass.