I have two months with two values, for example:
July-2013 1838.08
Aug-2013 3500.08
How can I calculate the percentage difference in August compared with July?
The formula for this is easy it's (Curr-Prev)*100.0/Prev, what's not clear is how to apply it since we do not know your table definition, contents or keys, and thus do not know how to generically select one month and it's previous value. But, hard-coding it would be like this:
SELECT
100.0*(curr.Val - prev.Val) / prev.Val As PercentDiff
FROM yourTable As curr
JOIN yourTable As prev
ON curr.MonthStr = 'Aug-2013' AND prev.MonthStr = 'July-2013'
The problem with working out percentage changes is that you need to be careful of when the 'old value' is 0 or you will get an error.
One approach is using nullif(old_Value, 0) but then the problem with that is when old values are 0 you are asking for New_Value/NULL which is the new value. (definitely not the % change)
I worked around it like this:
(case
when
OldValue = 0 and NewValue = 0
then
cast(0 as Decimal(10,2))
when
OldValue = 0
then
'Na'
else
cast(cast(
(
(
(cast(NewValue as decimal(11,3)) -
cast(OldValue as decimal(11,3))
)*100
)/cast(OldValue as decimal(11,3))
) as decimal(20,3)
) as varchar
)
end) '% Change'
I probably threw a lot more casts than necessary but it works well for me. Gives Na when necessary and 0 when necessary.
SELECT VAR(Bonus) 'Variance',
STDEVP(Bonus) 'Standard Deviation',
STDEV(Bonus) 'Standard Deviation',
VARP(Bonus) 'Variance for the Population'
FROM Sales.SalesPerson;
giving credit to fololwing post
http://blog.sqlauthority.com/2008/01/20/sql-server-introduction-to-statistical-functions-var-stdevp-stdev-varp/
to handle zeroes in the denominator, i use:
case
when oldVal<>0 then ((newVal-oldVal)*100.0)/oldVal
else
case when newVal=0 then 0 else Null end
end
this will return 0 if newVal and oldVal are both 0, and Null if oldVal is zero but newVal is non-zero.
multiplying by 100.0 (as opposed to 100) will implicitly convert int fields into decimal. i find it cleaner than try_convert().
Related
I am trying to add a column, YES/No, based on text involved. If the Value column contains BALL, we mark it as Yes in the column. But if the 'BALL' is attached with any text/string, it should return it as 'NO'. There are some cases which I have attached
How do I form the case statement so that if any text/string is attached to the 'BALL' without a space should be No, and rest all the cases should be 'Yes'. I tried using like %BALL%, but it does not satisfy all the examples in the above screenshot.
Just insist that the previous and next characters are not letters:
(case when value regexp '([^a-zA-Z]|^)BALL([a-zA-Z]|$)'
then 'YES' else 'NO'
end)
Here is a db<>fiddle.
Set #val variable with value need to lookup:
SET #val := 'BALL';
Run query with two type of checking:
Use LOCATE to find #val value in the table; will return numerical position of the first character of the searched value.
Use SUBSTRING to get two sets of value from string_val column; using the numerical position that was obtained using LOCATE:
val1 will return the value of string_val before the searched value of #val (the LOCATE result need to have a deduction of 1).
val2 will return the value of string_val that matches #val and anything after it.
In the outer query, chk1 checks the last character extracted to val1 against alphabets using REGEXP. In this case GOBALL will return true (1) while 9232BALL and 9232BALLV will return false (0). Here we'll look at whatever false.
chk2 checks if val2 matches the searched #val. Therefore, the separated value of 9232BALL which end up getting BALL for val2 will return true (1) while 9232BALLV which end up getting BALLV for val2 will return false (0). Here we'll look at whatever is true.
The last filter is checking the addition of chk1+chk2. The result we're looking for is 1 because chk1 need to be false (0) and chk2 need to be true (1).
SELECT String_val AS 'Value',
CASE WHEN chk1+chk2=1 THEN 'Yes' ELSE 'No' END AS 'Yes/No'
FROM
(SELECT *,
RIGHT(val1,1) REGEXP '[a-zA-Z]' AS chk1,
val2=#val AS chk2
FROM
(SELECT string_val,
SUBSTRING(string_val,1,LOCATE(#val,string_val)-1) val1,
SUBSTRING(string_val,LOCATE(#val,string_val)) val2
FROM mytable) A) B
Alternative option 1:
SELECT string_val,
CASE WHEN
REGEXP_REPLACE(CASE WHEN val1 REGEXP '[a-zA-Z]$' = 1
THEN CONCAT(val1,val2) ELSE val2 END,'[0-9]','')=#Val
THEN 'Yes' ELSE 'No' END AS 'Yes/No'
FROM
(SELECT string_val,
SUBSTRING(string_val,1,LOCATE(#val,string_val)-1) val1,
SUBSTRING(string_val,LOCATE(#val,string_val)) val2
FROM mytable) A;
Alternative option 2:
My further testing shows that it's possible to get the result using REGEXP_SUBSTR with a much shorter query:
SET #val := 'BALL';
SELECT string_val,
REGEXP_SUBSTR(string_val, '[a-zA-Z]+[BALL]+[a-zA-Z]') AS vals,
IF(((SELECT vals))=#val,'YES','NO') AS 'Yes/No'
FROM mytable;
Demo
Take a look at the following query. How do you display Column 'Action' as text.
If the result of 'Action' is LEQ 0 then dipslay the text "Crash" and if 'Action'
is GRT 0 display the text "Hold"?
SELECT col1 AS Action
FROM vdk
WHERE t_stamp Between "{StartTime}" AND "{EndTime}"
Refactoring the answer above, since i don't see the necessity to add a query to an alias table. I think this should work the other answer should work too btw, but its a little more complicated query for no given reason.
SELECT (CASE WHEN col1 <= 0 THEN 'Crash' ELSE 'Hold' END) AS Action
FROM vdk
WHERE t_stamp Between "{StartTime}" AND "{EndTime}"
Use CASE WHEN ... ELSE ... END and select from your set (query):
SELECT *, (CASE WHEN Action <= 0 THEN 'Crash' ELSE 'Hold' END) as ActionText
FROM (
SELECT col1 AS Action
FROM vdk
WHERE t_stamp Between "{StartTime}" AND "{EndTime}"
) q
This application is similar to my first question and I thought it might help someone else down the the road.
User can select from a Table's Drop Down List a set of options to enter a value into the Database.
Using Ignition's Power Table Component's Extension Function configureEditor with the following script.
This script sets up the Drop Down List.
if colName == 'Action':
return {options': [(0, 'Null'), (1, 'HOLD'), (2, 'CRASH')]}
Along with the same Power Table's Extension Function onCellEdited script.
This script enters the selection as a value into the database.
#onCellEdited Upadte Query
row = rowIndex
col = colIndex
colName = colName
value = newValue
ndx = self.data.getValueAt(row,0)
query = "UPDATE vdk SET %s = ? WHERE ndx = ?" % colName
system.db.runPrepUpdate(query,[value,ndx],'history')
system.db.refresh(self.data)
I am trying to use CASE in my query. I have to calculate the difference between required_number and vehicle_quantity. If it is less than or equal to 0 then I need value 0 otherwise the difference value. I am trying following code directly in phpmyadmin. But I am getting error:
Notice in ./libraries/sql-parser/src/Utils/Query.php#427
Undefined property: SqlParser\Components\CaseExpression::$expr
This is the query I have tried so far.
SELECT
required_number,
vehicle_quantity,
CASE
WHEN (
required_number - vehicle_quantity
) <= 0 THEN
'0'
ELSE
(
required_number - vehicle_quantity
)
END AS income_amt
FROM
vehicles
WHERE
id = 22
Can anybody help me what mistake I did in my query. Thank You.
Try this:
SELECT required_number,
vehicle_quantity,
(CASE
WHEN ((required_number - vehicle_quantity) <=0) THEN 0
ELSE (required_number - vehicle_quantity)
END) AS extra
FROM vehicles
WHERE mun_id=22
TRY THIS: you have to use 0 instead of '0' because you are doing integer based calculation so you can't define string instead
SELECT
required_number,
vehicle_quantity,
CASE WHEN (required_number - vehicle_quantity) <= 0 THEN
0
ELSE
(required_number - vehicle_quantity)
END AS income_amt
FROM vehicles
WHERE id = 22
I would like to round up a value to the next nearest power of 2 in a mysql query, so
select RoundUpToNearestPowerOfTwo(700) -- Should give 1024
I need this solution as part of a much larger query to generate and read some bitmask. Using custom stored functions is not an option, since I cannot use those in our production environment, so I'm looking for a smart way to do this inline in the query.
[Edit]
One possible way I can think of, is creating some enumerator, use a power in that, and choose the smallest value larger than my value:
select
min(BOUND)
from
(select 700 as VALUE) v
inner join
(select
POW(2, #pow := #pow + 1) as BOUND
from
(select #pow := 0) x,
MY_RANDOM_TABLE t
) x on x.BOUND > v.VALUE
But as you can tell, it's pretty verbose, so a leaner solution would be welcome.
Try this.
FLOOR(POW(2,CEIL(LOG2(1025))))
The CEIL and FLOOR cope with the boundary conditions correctly.
Try this:
select power(2, 1 + floor(log2(XXX)))
MySQL conveniently has the log2() function, which does most of the work.
EDIT:
I think this may be what you want:
select (case when floor(log2(XXX)) <> log2(XXX)
then power(2, 1 + floor(log2(XXX)))
else power(2, floor(log2(XXX)))
end)
Or something like:
select power(2, 1 + floor(log2(XXX*0.999999)))
There is a boundary condition on actual powers of 2.
If you are using SQL Server then you can try this...just change value in variable #value for any value to get the next nearest power of 2
declare #count int = 1
declare #value int = 700
while (#value <> 1)
BEGIN
set #value = #value / 2
set #count = #count + 1
END
select power(2, #count)
Previously, the following query was limited based on work_category_id. Turns out we need information from as subclass of another work_category_id, so now I'm limiting on job_code_id instead. Job_code_id 29 is work_category_id 88, all other job_code_ids shown are work_category_id 36.
I need hours and performance for each of these job_code_ids, but specifically for the 'cases_per_hr' calculation, I only want to divide cases by all hours except those from job_code_id 29. I tried a nested case when, but that didn't seem to make much sense. Please help!
SELECT
d.user_id as 'employee_ID',
round((sum(d.goal_hours)/sum(d.worked_hours)),2)*100 as 'performance',
round(sum(d.goal_hours),2) as 'goal_hrs',
round(sum(d.worked_hours),2) as 'hrs_worked',
sum(d.cases) as 'total_cases_slctd',
round(sum(d.cases)/sum(d.worked_hours),0) as 'cases_per_hr',
d.metric_dt
FROM
roster r,
prod_detail d
WHERE
d.process_level = r.process_level
and d.accounting_unit = r.accounting_unit
and d.job_code_id in ('29','322','304','303','302','305','181')
-- and d.work_category_id in('36')
If you only want to exclude job_code_id = '29' from your cases_per_hr calculation, you could do the following. It does use CASE WHEN.
SELECT d.user_id as 'employee_ID',
round((sum(d.goal_hours)/sum(d.worked_hours)),2)*100 as 'performance',
round(sum(d.goal_hours),2) as 'goal_hrs',
round(sum(d.worked_hours),2) as 'hrs_worked',
sum(d.cases) as 'total_cases_slctd',
round(
sum(CASE WHEN d.job_code_id <> '29' THEN d.cases ELSE 0 END)
/
sum(CASE WHEN d.job_code_id <> '29' THEN d.worked_hours ELSE 0 END)
,0) as 'cases_per_hr',
d.metric_dt
FROM roster r,
prod_detail d
WHERE
d.process_level = r.process_level
and d.accounting_unit = r.accounting_unit
and d.job_code_id in ('29','322','304','303','302','305','181')