SQL money round to closest 0.05 cents - mysql

I'm trying to round money in MySQL SELECT to the closest 0.05 cents.
so numbers like:
140.70 should become 140.70
140.71 should become 140.70
140.72 should become 140.70
140.73 should become 140.75
140.74 should become 140.75
140.75 should become 140.75
140.76 should become 140.75
140.77 should become 140.75
140.78 should become 140.80
140.79 should become 140.80
So more in detail
0.00 = 0.00
0.01 = 0.00
0.02 = 0.00
0.022 = 0.00 // here the magic should happen 0.022 is closer to 0, so result is 0
0.023 = 0.05 // but 0.023 should be rounded to 0.05! cause first round 0.023 to 0.025 which should then be rounded up to 0.05
0.03 = 0.05
I've tried some different things with MySQL CEIL() and MySQL FLOOR() but couldn't get the right result.
Created a SQL Fiddle here
With a table which makes no sense, except we need one to SELECT from:
CREATE TABLE hello ( world varchar(255) );
INSERT INTO hello (world) VALUES ('blubb');
This is the select Query:
SELECT
CEILING ( 0.05 / 0.05 ) * 0.05 AS CEIL_1,
CEILING ( 0.06 / 0.05 ) * 0.05 AS CEIL_2,
CEILING ( 0.07 / 0.05 ) * 0.05 AS CEIL_3,
CEILING ( 0.08 / 0.05 ) * 0.05 AS CEIL_4,
CEILING ( 0.09 / 0.05 ) * 0.05 AS CEIL_5
FROM hello;
Anyone here telling me how to do it right?

SELECT ROUND(140.77/5,2) * 5;
+-----------------------+
| ROUND(140.77/5,2) * 5 |
+-----------------------+
| 140.75 |
+-----------------------+

Related

ANOVA table in R: F-value does not "match the math"

I was playing around with a simple linear models when I noticed that, in the ANOVA table, the ratio MSreg/MSres does not exactly correspond to the F-value. Indeed, the two values are very similar but not the same.
Here my script
#quick view of the dataset
> head(my_data)
Diameter Height
1 0.325 0.080
2 0.320 0.100
3 0.280 0.110
4 0.125 0.040
5 0.400 0.135
6 0.335 0.100
#setting up the lm()
> ls1 <- lm(Diameter~Height, data=my_data)
> anova(ls1)
Analysis of Variance Table
Response: Diameter
Df Sum Sq Mean Sq F value Pr(>F)
Height 1 0.82415 0.82415 602.63 < 2.2e-16 ***
Residuals 98 0.13402 0.00137
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Here 0.82415/0.00137=601.5693 which is not the F value in the table. Is there a particular reason for that?

How to write a MySQL statement with multiple conditionals?

I have the following table:
id (integer, primary key)
amount_low (integer)
amount_high (integer)
fixedprice (decimal 4,2 Null)
percentadjust (decimal 4,2 Null)
itemname (varchar 50)
A record will have a value in either the "fixedprice" or "percentadjust" field, but not both. One will be NULL, and the other will have a value.
I need to get records based on a single input amount, "X":
If the "fixedprice" field has a value, I need to get the record if X is >= (fixedprice * amount_low) AND X is <= (fixedprice * amount_high).
If the "percentadjust" field has a value, I need to get the record if X is >= ((((percentadjust / 100) + 1) * 3.5) * amount_low) AND X is <= ((((percentadjust / 100) + 1) * 3.5) * amount_high).
The "3.5" is a value that changes on occasion and I'm not too concerned about that part.
What is a good way to do this in MySQL?
Sample data: (also see http://sqlfiddle.com/#!9/922a0 )
id amount_low amount_high fixedprice percentadjust itemname
-----------------------------------------------------------------
1 20 25 2.25 NULL A
2 50 75 2.38 NULL B
3 23 32 NULL 9.75 C
4 14 22 NULL 9.12 D
5 96 112 2.58 NULL E
Assuming your X was entered as 111 it would be
select * from tblItems
where (fixedprice is not null and 111>=(fixedprice * amount_low) and 111 <= (fixedprice * amount_high) )
OR (percentadjust is not null and 111>=((((percentadjust / 100) + 1) * 3.5) * amount_low) AND 111<=((((percentadjust / 100) + 1) * 3.5) * amount_high))
Note you can always write it as where xyz between A and B to simplify somethings slightly.
Remember that a lot of time can be wasted debugging logic operators when AND and OR are used and safe wrappers with parentheses are not used. So, if you intermingle AND with OR, wrap things well.

MySQL - how to compute incremental charges?

Assume a service is billed in the following manner:
The first 60 seconds is charged at $1.00
Subsequent charges are billed at $0.25 per 10 second
The following are example computations:
32 seconds = $1.00
59 seconds = $1.00
60 seconds = $1.00
61 seconds = $1.25
69 seconds = $1.25
70 seconds = $1.25
71 seconds = $1.50
Is it possible to do this kind of computation in MySQL alone?
EDIT 1:
Does something like this work:
SELECT `call_length`,
( 1.00 + ( Round(( `call_length` - 30 ) / 10) * .25 ) ) AS `cost`
FROM `service`
SqlFiddleDemo
CREATE TABLE sec(val INT);
INSERT INTO sec
VALUES (32), (59), (60), (61), (69), (70), (71);
SELECT
val,
1.0 + CASE
WHEN val <= 60.0 THEN 0
WHEN val MOD 10 = 0 THEN 0.25 *((val - 60) DIV 10)
ELSE 0.25 * (((val - 60) DIV 10) + 1)
END AS charge
FROM sec;
EDIT:
Without CASE:
SqlFiddleDemo2
SELECT
call_length,
1.0 + IF( call_length <= 60, 0, 0.25 * CEIL((call_length - 60)/10)) AS cost
FROM service;
This is not much of a MySQL problem, unless the setting in which you need to perform the calculation is somehow difficult(?).
UPDATE ... SET cost_cents = 100 + CEIL(GREATEST(0, duration - 60)/10) * 25;
As a SELECT to match your edit,
SELECT `call_length`,
100 + CEIL(GREATEST(0, `call_length` - 60)/10) * 25 AS `cost`
FROM `service`
Note that this returns cents. For dollars, divide the result by 100...
SELECT `call_length`,
(100 + CEIL(GREATEST(0, `call_length` - 60)/10) * 25) / 100 AS `cost`
FROM `service`

How To Generate A Random Decimal Value In Mysql

I am trying to generate a random value between 0.01 - 0.50 to enter into mysql. I have 2.7 million rows that I need to execute this on.
Here is my script:
UPDATE FBAInventory SET buyBox = ROUND( 0.01 + RAND( ) * 8,2 );
It is generating values such as 4.20, 3.89 etc. I only want it to span from 0.01 - 0.50 and not to exceed this.
Does anyone know how to do this?
Thanks!
How about...
round(rand() * 0.49 + 0.01, 2);
You can use the floor function to generate a range of random numbers.
FLOOR(RAND() * (<max> - <min> + 1)) + <min>
where the max and min are inclusive. So in your case you would want
FLOOR(RAND() * 1.49 ) + 0.01

Get frequency distribution of a decimal range in MySQL

I'm looking for an elegant way (in terms of syntax, not necessarily efficient) to get the frequency distribution of a decimal range.
For example, I have a table with ratings column which can be a negative or positive. I want to get the frequency of rows with a rating of certain range.
- ...
- [-140.00 to -130.00): 5
- [-130.00 to -120.00): 2
- [-120.00 to -110.00): 1
- ...
- [120.00 to 130.00): 17
- and so on.
[i to j) means i inclusive to j exclusive.
Thanks in advance.
You could get pretty close using 'select floor(rating / 10), count(*) from (table) group by 1'
I was thinking of seomthing that could do many levels like
DELIMITER $$
CREATE PROCEDURE populate_stats()
BEGIN
DECLARE range_loop INT Default 500 ;
simple_loop: LOOP
SET the_next = range_loop - 10;
Select sum(case when range between range_loop and the_next then 1 else 0 end) from table,
IF the_next=-500 THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END $$
usage: call populate_stats();
Would handle 100 ranges from 500-490, 490-480, ... -480 - -490, -490 - -500
assuming a finite number of ranges.
Select
sum(case when val between -140 to -130 then 1 else 0 end) as sum-140_to_-130,
sum(Case when val between -130 to -120 then 1 else 0 end) as sum-130_to_-140,
...
FROM table
and if not, you could use dynamic SQL to generate the select allowing a number of ranges however you may run into a column limitation.
Just put your desired ranges into a table, and use that to discriminate the values.
-- SET search_path='tmp';
DROP TABLE measurements;
CREATE TABLE measurements
( zval INTEGER NOT NULL PRIMARY KEY
);
INSERT INTO measurements (zval)
SELECT generate_series(1,1000);
DELETE FROM measurements WHERE random() < 0.20 ;
DROP TABLE ranges;
CREATE TABLE ranges
( zmin INTEGER NOT NULL PRIMARY KEY
, zmax INTEGER NOT NULL
);
INSERT INTO ranges(zmin,zmax) VALUES
(0, 100), (100, 200), (200, 300), (300, 400), (400, 500),
(500, 600), (600, 700), (700, 800), (800, 900), (900, 1000)
;
SELECT ra.zmin,ra.zmax
, COUNT(*) AS zcount
FROM ranges ra
JOIN measurements me
ON me.zval >= ra.zmin AND me.zval < ra.zmax
GROUP BY ra.zmin,ra.zmax
ORDER BY ra.zmin
;
Results:
zmin | zmax | zcount
------+------+--------
0 | 100 | 89
100 | 200 | 76
200 | 300 | 76
300 | 400 | 74
400 | 500 | 86
500 | 600 | 78
600 | 700 | 75
700 | 800 | 75
800 | 900 | 80
900 | 1000 | 82
(10 rows)