How to calculate percentage between two numbers using SQL on BigQuery? - sql

Since there is no build-in SQL function that can calculate percentage diffrance between two numbers I want to write the calculation in my own query.
The calculation is:
As listed here
This is my query:
select
( ( cast ( 30.245358139534886 - 25.92631649122807 ) as FLOAT64 )
/
( (cast ( 30.245358139534886 + 25.92631649122807 ) as FLOAT64) / 2.0) ) * 100
However this doesn't work it gives:
Syntax error: Unexpected ")" at [3:52]
*Casting is needed as not always numbers will be float.
The result of this query should be: 15.378
The calculation can be seen here
What is wrong with my query?

Your expression would look like this in BigQuery:
select 100 * abs( 30.245358139534886 - 25.92631649122807 ) /
( (30.245358139534886 + 25.92631649122807) / 2)

Answering your specific question why it fails .. you are missing parentheses and using wrong the cast.
select
cast ((30.245358139534886 - 25.92631649122807) as FLOAT64 )
/
( (cast ( (30.245358139534886 + 25.92631649122807 ) as FLOAT64) / 2.0) ) * 100
How use cast
cast (value as datatype)

Percent Difference and Percent Change are both defined in the big query community utils. Check out the example below!
Percent Difference example:
SELECT bqutil.fn.percentage_difference(1, 0.1)
Returns
1.6364
Percent Change example:
SELECT bqutil.fn.percentage_change(1, 0.1)
Returns
0.9

Try:
select
( ABS( cast ( 30.245358139534886 - 25.92631649122807 as FLOAT) )
/ ( (cast ( 30.245358139534886 + 25.92631649122807 as FLOAT) ) / 2.0) ) * 100 FROM DUAL;

Related

How can I Roundoff in SQL with a sum function

In My SQL Code I am trying to round the value to 2 decimal point with sum
select ((SUM(Round((CAST(PE.GstTotal as float) * PE.Quantity) / 2 ),2))) FROM [dbo].[PharmacyEntry] PE
But I am getting an error. Could someone correct me on this.
Error
It's sometimes helpful to vertically align all your parenthesis pairs to see where you've got one wrong:
select
(
(
SUM
(
Round
(
(
CAST
(
PE.GstTotal as float
)
*
PE.Quantity
)
/
2
),
2
)
)
)
FROM [dbo].[PharmacyEntry] PE
You're providing 2 as a second parameter to sum instead of round. Try this:
select SUM(Round((CAST(PE.GstTotal as float) * PE.Quantity) / 2 , 2))
FROM [dbo].[PharmacyEntry] PE

How to Print decimal Values

select total_hours, total_hour_present,
(total_hour_present / total_hours) * 100 as total_hour_present
from attendancereport_subject
where roll_no = '08ME001'
try this
select total_hours,
total_hour_present,
(cast (total_hour_present as decimal) / total_hours) * 100 as total_hour_present
from attendancereport_subject
where roll_no = '08ME001'
This is a guess, but if the 2 hour columns are integers then you will most probably get zero, since the result will always be less than 1. So try something like this:
convert(decimal(10,2),(convert(decimal(10,2),total_hour_present) / total_hours) * 100) as total_hour_present
If you're missing decimals in the result, then that leads to the assumption that both "total_hour_present" and "total_hours" are integers.
Because in SQL Server, when an INT is divided by an INT then it returns an INT.
So you could cast or convert the total_hours to a float or a decimal.
So that the division returns a number with decimal values.
Example 1
(total_hour_present / cast(total_hours as decimal(10,0))) * 100 as percentage_hour_present
Example 2
(total_hour_present / convert(float, total_hours)) * 100 as percentage_hour_present
below should work
select total_hours, total_hour_present,
((total_hour_present*1.00) / (total_hours*1.00)) * 100.000 as total_hour_present
from attendancereport_subject
where roll_no = '08ME001'
you need to cast the value to decimal, Try this:
select total_hours, total_hour_present,
(cast(total_hour_present as decimal(18,0)) / total_hours) * 100 as
total_hour_present
from attendancereport_subject
where roll_no = '08ME001'

Lots of WHEN conditions in CASE statement (binning)

How can I do binning in SQL Server 2008 if I need about 100 bins? I need to group records depending if a binning variable belongs to one of 100 equal intervals.
For example if there is continious variable age I could write:
CASE
WHEN AGE >= 0 AND AGE < 1 THEN '1'
WHEN AGE >= 1 AND AGE < 2 THEN '2'
...
WHEN AGE >= 99 AND AGE < 100 THEN '100'
END [age_group]
But this process would be timeconsuming? Are there some other ways how to do that?
Try This Code Once:
SELECT CASE
WHEN AGE = 0 THEN 1
ELSE Ceiling([age])
END [age_group]
FROM #T
Here CEILING function returns the smallest integer greater than or equal to the specified numeric expression.i.e select CEILING(0.1) SQL Returns 1 As Output
But According to Your Output Requirement Floor(age)+1 is enough to get Required Output.
SELECT Floor([age]) + 1 [age_group]
FROM #T
Here Floor Function Returns the largest integer less than or equal to the specified numeric expression.
Try this based upon your comment about the segments being 1200:
;With Number
AS
(
SELECT *
FROM (Values(1),(2), (3), (4), (5), (6), (7), (8), (9), (10))N(x)
),
Segments
As
(
SELECT (ROW_NUMBER() OVER(ORDER BY Num1.x) -1) * 1200 As StartNum,
ROW_NUMBER() OVER(ORDER BY Num1.x) * 1200 As EndNum
FROM Number Num1
CROSS APPLY Number Num2
)
SELECT *
FROM Segments
SELECT *
FROM Segments
INNER JOIN MyTable
ON MyTable.Price >= StartNum AND MyTable.Price < EndNum
Mathematics, I guess. In this case,
Ceiling(Age) AS [age_group]
cast as necessary into character type of your choice. Ceiling is the 'round up to an integer' function in SQL Server.
You can use arithmetic for this purpose. Something like this:
select floor(bins * (age - minage) / (range + 1)), count(*)
from t cross join
(select min(age) as minage, max(age) as maxage,
1.0*(max(age) - min(age)) as range, 100 as bins
from t
) m
group by floor(bins * (age - minage) / (range + 1))
However, this is overkill for your example, which doesn't need a case at all.
If your interval for the groups are fixed - for example 1200, you can just do an integer division to get the index with that grouping.
For example:
SELECT 1000 / 1200 equals 0
SELECT 2200 / 1200 equals 1
Remember - you need to cast to int to get the result if you're using a decimal datatype. Integer division requires int on both sides of the operator.
And then add 1 to get the group

AS400 DB2 query math expression in Select

I have not done DB2 queries for a while so I am having issues with a math expression in my Select statement. It does not throw an error but I get the wrong result. Can someone tell me how DB2 evaluates the expression?
Part of my Select is below.
The values are:
t1.Points = 100
t2.Involvepoints = 1
(current date - t1.fromdt) in days is 1268 (so it would be current
date 7/19/2013 - 01/28/2010 in days)
It should read like (100 * 1) * (1 - (.000274 * 1268)) = 65.2568
SELECT Value1,
value2,
(CASE
WHEN (T1.POINTS * T2.INVOLVEPOINTS) * (1 - .000274 * DAYS(CURRENT DATE) - DAYS(T1.FROMDT)) >= 0 THEN (T1.POINTS * T2.INVOLVEPOINTS) * (1 - .000274 * DAYS(CURRENT DATE) - DAYS(T1.FROMDT))
ELSE 0
END) AS POINTSTOTAL
FROM TABLE1;
The parenthesis are not enforcing the correct precedence of operations and the join declaration is missing. In addition you can use the MAX scalar function instead of the repetitive CASE statement.
Here is a proof using common table expressions to simulate the source data:
with
t1 (value1, points, fromdt)
as (select 1, 100, '2010-01-28' from sysibm.sysdummy1),
t2 (value2, involvepoints)
as (select 2, 1 from sysibm.sysdummy1)
select value1, value2,
max(0, t1.points * t2.involvepoints *
(1 - .000274 * (DAYS('2013-07-19') - DAYS(t1.fromdt)))) as pointstotal
from t1, t2;
The result is:
VALUE1 VALUE2 POINTSTOTAL
------ ------ -----------
1 2 65.256800
Did you mean this?
...
(T1.POINTS * T2.INVOLVEPOINTS) * (1 - .000274 * ( DAYS(CURRENT DATE) - DAYS(T1.FROMDT) ) )
...
Note the extra pair of parentheses around the subtraction of dates. Normally multiplication takes precedence over addition, so in your original query you multiply today's date by 0.000274, subtract that from 1, then subtract the value of FROMDT from the result.
Curiously, you have those parentheses in your explanation, but not in the actual formula.

T-SQL average rounded to the closest integer

I'm not sure if this has been asked before, but how do I get the average rounded to the closest integer in T-SQL?
This should do it. You might need a GROUP BY on the End depending on what you are looking for the average of.
SELECT CONVERT(int,ROUND(AVG(ColumnName),0))
FROM
TableName
EDIT: This question is more interesting than I first thought.
If we set up a dummy table like so...
WITH CTE
AS
(
SELECT 3 AS Rating
UNION SELECT 4
UNION SELECT 7
)
SELECT AVG(Rating)
FROM
CTE
We get an integer average of 4
However if we do this
WITH CTE
AS
(
SELECT 3.0 AS Rating
UNION SELECT 4.0
UNION SELECT 7.0
)
SELECT AVG(Rating)
FROM
CTE
We get a decimal average of 4.666..etc
So it looks like the way to go is
WITH CTE
AS
(
SELECT 3 AS Rating
UNION SELECT 4
UNION SELECT 7
)
SELECT CONVERT(int,ROUND(AVG(CONVERT(decimal,Rating)),0))
FROM CTE
Which will return an integer value of 5 which is what you are looking for.
If you are in SQL Server, just use round(avg(column * 1.0), 0).
The reason for * 1.0 is because sql server in some cases returns calculations using the same datatype of the values used in the calculation. So, if you calculate the average of 3, 4 and 4, the result is 3.66..., but the datatype of the result is integer, therefore the sql server will truncate 3.66... to 3, using * 1.0 implicit convert the input to a decimal.
Alternatively, you can convert or cast the values before the average calculation, like cast(column as decimal) instead of using the * 1.0 trick.
If your column it's not a integer column, you can remove the * 1.0.
PS: the result of round(avg(column * 1.0), 0) still is a decimal, you can explicit convert it using convert(int, round(avg(column * 1.0), 0), 0) or just let whatever language you are using do the job (it's a implicit conversion)
Select cast(AVG(columnname) as integer)
This worked for it:
CONVERT(int,ROUND(AVG(CAST(COLUMN-NAME AS DECIMAL)) ,0))
Isn't there a shorter way of doing it though?
T-SQL2018.
CAST(ROUND(COLUMN, 0) AS INT) This code does the job for me and gives the output I require so a 4.8 becomes 5.
whereas
CAST(AVG(COLUMN) AS INT) This code almost does the job but rounds down, so 4.8 becomes a 4 and not 5.
select cast(avg(a+.5) as int) from
(select 1 a union all select 2) b
If you don't like shortcuts, you could use the long way:
select round(avg(cast(a as real)), 0)
from (select 1 a union all select 2) b
The following statements are equivalent:
-- the original code
CONVERT(int, ROUND(AVG(CAST(mycolumn AS DECIMAL)) ,0))
-- using '1e0 * column' implicitly converts mycolumn value to float
CONVERT(int, ROUND(AVG(1e0 * mycolumn) ,0))
-- the conversion to INT already rounds the value
CONVERT(INT, AVG(1e0 * mycolumn))
On SQL 2014,
select round(94,-1)
select round(95,-1)