Implementation of NORMSINV function in MySQL - mysql

I need to use the inverse normal cumulative distribution function (what in Excel is NORMSINV function) in MySQL, but there is no such function there. Maybe any of you has an implementation of it for MySQL?
Many thanks for your time.

Well, I've finally found this. It's not perfect but a quite good aproximation. The code isn't mine, its author is Geoffrey C. Barnes. I've just transformed it from VB.NET to MySQL.
DROP FUNCTION IF EXISTS NORMSINV;
DELIMITER //
CREATE FUNCTION NORMSINV (p DOUBLE) RETURNS DOUBLE
BEGIN
DECLARE q, r DOUBLE;
DECLARE A1, A2, A3, A4, A5, A6 DOUBLE;
DECLARE B1, B2, B3, B4, B5 DOUBLE;
DECLARE C1, C2, C3, C4, C5, C6 DOUBLE;
DECLARE D1, D2, D3, D4 DOUBLE;
DECLARE P_LOW, P_HIGH DOUBLE;
/* coefficients in rational approximations */
SET A1 = -39.696830286653757;
SET A2 = 220.9460984245205;
SET A3 = -275.92851044696869;
SET A4 = 138.357751867269;
SET A5 = -30.66479806614716;
SET A6 = 2.5066282774592392;
SET B1 = -54.476098798224058;
SET B2 = 161.58583685804089;
SET B3 = -155.69897985988661;
SET B4 = 66.80131188771972;
SET B5 = -13.280681552885721;
SET C1 = -0.0077848940024302926;
SET C2 = -0.32239645804113648;
SET C3 = -2.4007582771618381;
SET C4 = -2.5497325393437338;
SET C5 = 4.3746641414649678;
SET C6 = 2.9381639826987831;
SET D1 = 0.0077846957090414622;
SET D2 = 0.32246712907003983;
SET D3 = 2.445134137142996;
SET D4 = 3.7544086619074162;
/* define break points */
SET P_LOW = 0.02425;
SET P_HIGH = 1 - P_LOW;
IF (p > 0 AND p < P_LOW) THEN
/* rational approximation for lower region */
SET q = SQRT(-2 * LOG(p));
RETURN (((((C1 * q + C2) * q + C3) * q + C4) * q + C5) * q + C6) /
((((D1 * q + D2) * q + D3) * q + D4) * q + 1);
ELSEIF (p >= P_LOW AND p <= P_HIGH) THEN
/* rational approximation for central region */
SET q = p - 0.5;
SET r = q * q;
RETURN (((((A1 * r + A2) * r + A3) * r + A4) * r + A5) * r + A6) * q /
(((((B1 * r + B2) * r + B3) * r + B4) * r + B5) * r + 1);
ELSEIF (p > P_HIGH AND p < 1) THEN
/* rational approximation for upper region */
SET q = SQRT(-2 * LOG(1 - p));
RETURN -(((((C1 * q + C2) * q + C3) * q + C4) * q + C5) * q + C6) /
((((D1 * q + D2) * q + D3) * q + D4) * q + 1);
/* on error returning 0 */
ELSE
RETURN 0;
END IF;
END//
DELIMITER ;

Below is an equivalence of Excel's NORMINV function.
CREATE FUNCTION NORMINV(p double, mu double, sigma double)
RETURNS decimal(20,6)
begin
declare q double;
declare r double;
declare val double;
BEGIN
IF p < 0 OR p > 1 THEN
signal sqlstate '20100' set message_text= 'The probality p must be bigger than 0 and smaller than 1';
END IF;
IF sigma < 0 THEN
signal sqlstate '20100' set message_text= 'The standard deviation sigma must be positive';
END IF;
IF p = 0 THEN
RETURN to_binary_double('-INF');
END IF;
IF p = 1 THEN
RETURN to_binary_double('INF');
END IF;
IF sigma = 0 THEN
RETURN mu;
END IF;
set q:= p - 0.5;
IF(ABS(q) <= .425) THEN
set r:= .180625 - q * q;
set val :=
q * (((((((r * 2509.0809287301226727 +
33430.575583588128105) * r + 67265.770927008700853) * r +
45921.953931549871457) * r + 13731.693765509461125) * r +
1971.5909503065514427) * r + 133.14166789178437745) * r +
3.387132872796366608)
/ (((((((r * 5226.495278852854561 +
28729.085735721942674) * r + 39307.89580009271061) * r +
21213.794301586595867) * r + 5394.1960214247511077) * r +
687.1870074920579083) * r + 42.313330701600911252) * r + 1);
ELSE
/* r = min(p, 1-p) < 0.075 */
IF q > 0 THEN
set r:= 1 - p;
ELSE
set r:= p;
END IF;
set r:= SQRT(-LN(r));
/* r = sqrt(-log(r)) <==> min(p, 1-p) = exp( - r^2 ) */
IF (r <= 5) THEN
set r:= r - 1.6;
set val := (((((((r * 7.7454501427834140764e-4 +
.0227238449892691845833) * r + .24178072517745061177) *
r + 1.27045825245236838258) * r +
3.64784832476320460504) * r + 5.7694972214606914055) *
r + 4.6303378461565452959) * r +
1.42343711074968357734)
/ (((((((r *
1.05075007164441684324e-9 + 5.475938084995344946e-4) *
r + .0151986665636164571966) * r +
.14810397642748007459) * r + .68976733498510000455) *
r + 1.6763848301838038494) * r +
2.05319162663775882187) * r + 1);
ELSE /* very close to 0 or 1 */
set r := r - 5;
set val := (((((((r * 2.01033439929228813265e-7 +
2.71155556874348757815e-5) * r +
.0012426609473880784386) * r + .026532189526576123093) *
r + .29656057182850489123) * r +
1.7848265399172913358) * r + 5.4637849111641143699) *
r + 6.6579046435011037772)
/ (((((((r *
2.04426310338993978564e-15 + 1.4215117583164458887e-7) *
r + 1.8463183175100546818e-5) * r +
7.868691311456132591e-4) * r + .0148753612908506148525)
* r + .13692988092273580531) * r +
.59983220655588793769) * r + 1);
END IF;
IF q < 0.0 THEN
set val := -val;
END IF;
END IF;
RETURN mu + sigma * val;
END;
END
It has been adapted from [https://forums.mysql.com/read.php?98,411441,411458#msg-411458] which is Oracle equivalence.
Have used it, so far so good.
Hope it assists someone.

Related

Subset a table such that the samples are normally distributed around a value in a column

I have the following table called original_table:
name height age
personA 180 21
personB 190 37
personC 168 27
personD 182 56
...
My goal is to create two random samples of size 100 from the original_table such that the mean of age is normally distributed around 25, and height average is close to 175. Basically, a person with age 25 and height 175 has the highest chance of being in the tables, but not guaranteed.
The trick is to find the normal distribution function from other languages, and then convert it to mysql syntax. For example, convert from the following java code to mysql
//java.util.Random
synchronized public double nextGaussian() {
// See Knuth, ACP, Section 3.4.1 Algorithm C.
if (haveNextNextGaussian) {
haveNextNextGaussian = false;
return nextNextGaussian;
} else {
double v1, v2, s;
do {
v1 = 2 * nextDouble() - 1; // between -1 and 1
v2 = 2 * nextDouble() - 1; // between -1 and 1
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
}
with recursive t0(v1, v2, s, num1, num2, rn) as (
select #v1:= rand() * 2 - 1,
#v2:= rand() * 2 - 1,
#s:= #v1*#v1 + #v2*#v2,
sqrt(-2 * log(#s) / (#s)) * #v1,
sqrt(-2 * log(#s) / (#s)) * #v2,
#rn:=case when #s < 1 and #s > 0 then 1 else 0 end
union all
select #v1:= rand() * 2 - 1,
#v2:= rand() * 2 - 1,
#s:= #v1*#v1 + #v2*#v2,
sqrt(-2 * log(#s) / (#s)) * #v1,
sqrt(-2 * log(#s) / (#s)) * #v2,
#rn:=case when #s < 1 and #s > 0 then 1 else 0 end + #rn
from t0
where #rn < 100
)
select 175 + t1.num1 * 10,
175 + t1.num2 * 10,
25 + t1.num1 * 8,
25 + t1.num2 * 8
from t0 t1
where t1.num1 is not null
order by t1.num1
;

How to draw Triangle star pattern with MySQL without using Stored Procedure?

Triangular pattern example The above pattern is for p(5). How to write a query to print the pattern P(n) (where n is Integer defining the number of rows) using MySQL without using Stored Procedure. I had one code example for MS SQL Server i.e.
DECLARE #i INT = 20
WHILE (#i > 0)
BEGIN
PRINT REPLICATE('* ', #i)
SET #i = #i - 1
END
SET #NUMBER = 21;
SELECT REPEAT('* ', #NUMBER := #NUMBER - 1)
FROM information_schema.tables LIMIT 20;
OR
SET #NUMBER = 21;
SELECT REPEAT('* ', #NUMBER := #NUMBER - 1)
FROM information_schema.tables WHERE #NUMBER > 1;
SET #NUMBER = 21;
SELECT REPEAT('* ', #NUMBER := #NUMBER - 1)
FROM information_schema.tables;
The below query to print the pattern P(20).
*
* *
* * *
* * * *
* * * * *
WITH RECURSIVE cte AS
(
SELECT 1 AS n, CAST('*' AS CHAR(100)) AS str
UNION ALL
SELECT n + 1, concat('* ',str) FROM cte WHERE n < 20
)
SELECT str FROM cte;
also for this pattern:
*
* *
* * *
* * * *
* * * * *
...
the query:
SET #i = 0;
SELECT REPEAT('* ', #i := #i + 1)
FROM information_schema.tables
where #i < 20; --p(20)

Using UNION to concatenate query results

I'm trying to execute queries and append the results into another query result, to maintain order. So I calculating the distance and at the end ordering by a "fake var" and then by distance.
Here's the query:
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `Test`(IN basic_user_id INT, IN max_dist INT, IN q VARCHAR(255), IN index_start INT, IN index_end INT)
BEGIN
DECLARE mylon DOUBLE;
DECLARE mylat DOUBLE;
DECLARE lon1 FLOAT;
DECLARE lon2 FLOAT;
DECLARE lat1 FLOAT;
DECLARE lat2 FLOAT;
SET #location_id = (SELECT location_id from basicuser where id = basic_user_id);
SET #group_id = (SELECT group_id from basicuser where id = basic_user_id);
SET #subgroup_id = (SELECT subgroup_id from basicuser where id = basic_user_id);
SET #tertiarygroup_id = (SELECT tertiarygroup_id from basicuser where id = basic_user_id);
-- get the original lon and lat for the userid
SELECT longitude, latitude into mylon, mylat from location where id = #location_id;
set lon1 = mylon - max_dist / abs(cos(radians(mylat)) * 69);
set lon2 = mylon + max_dist / abs(cos(radians(mylat)) * 69);
set lat1 = mylat - (max_dist / 69);
set lat2 = mylat + (max_dist / 69);
select #group_id, #subgroup_id, #tertiarygroup_id;
(
SELECT 1 as `temp`, `inradar_ad`.*, 3956 * 2 * ASIN(SQRT(POWER(SIN((orig.latitude - dest.latitude) * pi()/180 / 2), 2) + COS(orig.latitude * pi()/180) * COS(dest.latitude * pi()/180) * POWER(SIN((orig.longitude - dest.longitude) * pi()/180 / 2), 2))) as distance
FROM
location AS dest
LEFT OUTER JOIN `inradar_ad` ON (`inradar_ad`.location_id = dest.id)
LEFT OUTER JOIN `inradar_ad_company` ON (`inradar_ad`.`id` = `inradar_ad_company`.`inradarad_ptr_id`)
LEFT OUTER JOIN `inradar_ad_person` ON (`inradar_ad`.`id` = `inradar_ad_person`.`inradarad_ptr_id`)
LEFT OUTER JOIN `inradar_category` ON (`inradar_ad`.`category_id` = `inradar_category`.`id`)
LEFT OUTER JOIN `inradar_subcategory` ON (`inradar_ad`.`subcategory_id` = `inradar_subcategory`.`id`)
LEFT OUTER JOIN `basicuser` ON (`inradar_ad`.`owner_id` = `basicuser`.`id`)
LEFT OUTER JOIN `auth_user` ON (`basicuser`.`user_id` = `auth_user`.`id`)
LEFT OUTER JOIN `inradar_ad_multiple` ON (`inradar_ad`.`multiple_advertiser_id` = `inradar_ad_multiple`.`id`),
location AS orig
WHERE orig.id = #location_id AND
(
(
`inradar_ad_multiple`.`id` IS NULL AND
(
`inradar_ad_company`.`corporate_name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_ad_person`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_category`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_subcategory`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_ad`.`description` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`auth_user`.`first_name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`auth_user`.`last_name` LIKE REPLACE('%$$**$$%', '$$**$$', q)
)
)
) AND
`basicuser`.`tertiarygroup_id` = #tertiarygroup_id AND
dest.longitude BETWEEN lon1 AND lon2 AND dest.latitude BETWEEN lat1 AND lat2
HAVING distance < max_dist
) UNION (
SELECT 2 as `temp`, `inradar_ad`.*, 3956 * 2 * ASIN(SQRT(POWER(SIN((orig.latitude - dest.latitude) * pi()/180 / 2), 2) + COS(orig.latitude * pi()/180) * COS(dest.latitude * pi()/180) * POWER(SIN((orig.longitude - dest.longitude) * pi()/180 / 2), 2))) as distance
FROM
location AS dest
LEFT OUTER JOIN `inradar_ad` ON (`inradar_ad`.location_id = dest.id)
LEFT OUTER JOIN `inradar_ad_company` ON (`inradar_ad`.`id` = `inradar_ad_company`.`inradarad_ptr_id`)
LEFT OUTER JOIN `inradar_ad_person` ON (`inradar_ad`.`id` = `inradar_ad_person`.`inradarad_ptr_id`)
LEFT OUTER JOIN `inradar_category` ON (`inradar_ad`.`category_id` = `inradar_category`.`id`)
LEFT OUTER JOIN `inradar_subcategory` ON (`inradar_ad`.`subcategory_id` = `inradar_subcategory`.`id`)
LEFT OUTER JOIN `basicuser` ON (`inradar_ad`.`owner_id` = `basicuser`.`id`)
LEFT OUTER JOIN `auth_user` ON (`basicuser`.`user_id` = `auth_user`.`id`)
LEFT OUTER JOIN `inradar_ad_multiple` ON (`inradar_ad`.`multiple_advertiser_id` = `inradar_ad_multiple`.`id`),
location AS orig
WHERE orig.id = #location_id AND
(
(
`inradar_ad_multiple`.`id` IS NULL AND
(
`inradar_ad_company`.`corporate_name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_ad_person`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_category`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_subcategory`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_ad`.`description` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`auth_user`.`first_name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`auth_user`.`last_name` LIKE REPLACE('%$$**$$%', '$$**$$', q)
)
)
) AND
`basicuser`.`subgroup_id` = #subgroup_id AND
dest.longitude BETWEEN lon1 AND lon2 AND dest.latitude BETWEEN lat1 AND lat2
HAVING distance < max_dist
) UNION (
SELECT 3 as `temp`, `inradar_ad`.*, 3956 * 2 * ASIN(SQRT(POWER(SIN((orig.latitude - dest.latitude) * pi()/180 / 2), 2) + COS(orig.latitude * pi()/180) * COS(dest.latitude * pi()/180) * POWER(SIN((orig.longitude - dest.longitude) * pi()/180 / 2), 2))) as distance
FROM
location AS dest
LEFT OUTER JOIN `inradar_ad` ON (`inradar_ad`.location_id = dest.id)
LEFT OUTER JOIN `inradar_ad_company` ON (`inradar_ad`.`id` = `inradar_ad_company`.`inradarad_ptr_id`)
LEFT OUTER JOIN `inradar_ad_person` ON (`inradar_ad`.`id` = `inradar_ad_person`.`inradarad_ptr_id`)
LEFT OUTER JOIN `inradar_category` ON (`inradar_ad`.`category_id` = `inradar_category`.`id`)
LEFT OUTER JOIN `inradar_subcategory` ON (`inradar_ad`.`subcategory_id` = `inradar_subcategory`.`id`)
LEFT OUTER JOIN `basicuser` ON (`inradar_ad`.`owner_id` = `basicuser`.`id`)
LEFT OUTER JOIN `auth_user` ON (`basicuser`.`user_id` = `auth_user`.`id`)
LEFT OUTER JOIN `inradar_ad_multiple` ON (`inradar_ad`.`multiple_advertiser_id` = `inradar_ad_multiple`.`id`),
location AS orig
WHERE orig.id = #location_id AND
(
(
`inradar_ad_multiple`.`id` IS NULL AND
(
`inradar_ad_company`.`corporate_name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_ad_person`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_category`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_subcategory`.`name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`inradar_ad`.`description` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`auth_user`.`first_name` LIKE REPLACE('%$$**$$%', '$$**$$', q) OR
`auth_user`.`last_name` LIKE REPLACE('%$$**$$%', '$$**$$', q)
)
)
) AND
`basicuser`.`group_id` = #group_id AND
dest.longitude BETWEEN lon1 AND lon2 AND dest.latitude BETWEEN lat1 AND lat2
HAVING distance < max_dist
)
ORDER by `temp` ASC, distance ASC;
END
But that returns duplicated entries, like this:
# temp, id, seller_id, owner_id, description, category_id, subcategory_id, video_url, logo, location_id, business_hours, subscription_plan_id, tags, advertiser_occupation, advertiser_group_message, email, email_contact_form, website, e_commerce, phone, phone2, blap_phone, delivery, comment_votes, comment_quantity, multiple_advertiser_id, user_type, additional_info, advertiser_available, used_free_coupom, distance
1 37294 40 35 2 37667 (62) 3523-9609 0 0 company 0 0 105.60177674937776
1 37256 36 35 1 37557 (19)4141-5857 0 0 0 company 0 0 233.5020148948106
1 37254 40 35 1 37555 (16) 3624-8409 0 0 company 0 0 297.9775326093067
1 37264 40 35 1 37579 (67) 3251-1186 0 0 company 0 0 829.305941965672
2 37294 40 35 2 37667 (62) 3523-9609 0 0 company 0 0 105.60177674937776
2 37255 52 35 1 37556 (11) 5669-0169 0 0 company 0 0 218.0241298958371
2 37256 36 35 1 37557 (19)4141-5857 0 0 0 company 0 0 233.5020148948106
2 37254 40 35 1 37555 (16) 3624-8409 0 0 company 0 0 297.9775326093067
2 37264 40 35 1 37579 (67) 3251-1186 0 0 company 0 0 829.305941965672
3 37294 40 35 2 37667 (62) 3523-9609 0 0 company 0 0 105.60177674937776
3 37255 52 35 1 37556 (11) 5669-0169 0 0 company 0 0 218.0241298958371
3 37256 36 35 1 37557 (19)4141-5857 0 0 0 company 0 0 233.5020148948106
3 37254 40 35 1 37555 (16) 3624-8409 0 0 company 0 0 297.9775326093067
3 37264 40 35 1 37579 (67) 3251-1186
0 0 company 0 0 829.305941965672
What am I doing wrong, there?
Thanks very much in advance.
You can get rid of the UNION and do the whole thing in one SELECT.
CASE statement
Select everything you want and set your fake var within the SELECT clause.
SELECT CASE
WHEN `basicuser`.`tertiarygroup_id` = #tertiarygroup_id THEN 1
WHEN `basicuser`.`subgroup_id` = #subgroup_id THEN 2
WHEN `basicuser`.`group_id` = #group_id THEN 3
END as temp, ...
...
WHERE (
`basicuser`.`tertiarygroup_id` = #tertiarygroup_id OR
`basicuser`.`subgroup_id` = #subgroup_id OR
`basicuser`.`group_id` = #group_id
) AND ...
ORDER BY booleans
If you have a tree-like structure for your tertiary/secondary/groups, you can leverage the boolean order in the ORDER BY clause
ORDER BY cond1 DESC, cond2 DESC, cond3 DESC, distance ASC

mysql - updating a table setting a column with a complex condition

I have been working on this for a while now and this seems to be too complex. What I want to do is to update a column (x) with the operation: (p * (100/c) ) / 100.
p corresponds to a value of a date x and c corresponds to a value of date x minus one day.
I tried to create a stored procedure with loop but select statement doesnt work for me in the loop statement.
Here is my procedure which update nothing :
BEGIN
DECLARE firstqDate,date2 date;
DECLARE p, c float;
DECLARE cpt, val int;
SET #val = 0;
SET #cpt = (select count(*)-1 from quotes);
WHILE (val < 3) DO
SET #firstqDate = (select qDate from quotes ORDER BY YEAR(qDate) ASC, MONTH(qDate) ASC, DAY(qDate) ASC limit 1,1);
SET date2 = (select qDate from quotes where qDate like DATE_ADD(#firstqDate, INTERVAL 1 DAY );
SET p = (select qOp from quotes where qDate like date2);
SET c = (select qCl from quotes where qDate like DATE_SUB(date2, INTERVAL val DAY));
update quotes
set qCh = (p * (100/c) ) / 100;
set val = val + 1;
end while;
END
EDIT : I did some updates to the stored procedure but still updating no lines!
BEGIN
DECLARE firstqDate,date2 date;
DECLARE p, c float;
DECLARE cpt, val int;
SET #val = 0;
SET #cpt = (select count(*)-1 from quotes);
SET firstqDate = (select qDate from quotes ORDER BY YEAR(qDate) ASC, MONTH(qDate) ASC, DAY(qDate) ASC limit 1,1);
WHILE (val < 3) DO
SET date2 = (select qDate from quotes where qDate like DATE_ADD(#firstqDate, INTERVAL val DAY ));
SET p = (select qOp from quotes where qDate like date2);
SET c = (select qCl from quotes where qDate like DATE_SUB(date2, INTERVAL val+1 DAY));
set val = val + 1;
update quotes
set qCh = (p * (100/c) ) / 100
where qOp = p AND qCl = c;
end while;
END
I did some updates again to the stored procedures but no changes. i used some functions.
BEGIN
DECLARE p, c float;
DECLARE cpt, val int;
SET #val = 0;
SET #cpt = (select count(*)-1 from quotes);
WHILE (#val < 3) DO
SET p = getp(#val, getd());
SET c = getc(#val+1, getd());
set #val = #val + 1;
update quotes
set qCh = (#p * (100/#c) ) / 100
where qOp = #p AND qCl = #c;
end while;
END
functions :
get p:
BEGIN
declare d date;
select qDate into d from quotes ORDER BY YEAR(qDate) ASC, MONTH(qDate) ASC, DAY(qDate) ASC limit 1,1;
return d;
END
get c:
BEGIN
DECLARE c float;
DECLARE qDa date;
select qDate into qDa from quotes where qDate like DATE_SUB(qD, INTERVAL v DAY );
SELECT qCl INTO c FROM quotes WHERE qDate = qDa;
RETURN c;
END
getd:
BEGIN
declare d date;
select qDate into d from quotes ORDER BY YEAR(qDate) ASC, MONTH(qDate) ASC, DAY(qDate) ASC limit 1,1;
return d;
END
this stored procedure must calculate all qCh from p of qDate and c of the qDate minus one day.
Thank you!
EDIT - Solved
Ouf! I finally managed to write this stored procedure :
BEGIN
DECLARE p, c float;
DECLARE cpt, val int;
SET #val = 0;
SET #cpt = (select count(*)-1 from quotes);
WHILE (#val <= 2) DO
SET p := getp(#val, getd());
SET c := getc(#val+1, getd());
set #val := #val + 1;
update quotes q
set q.qCh = (getp(#val, getd()) * (100/getc(#val-1, getd())) ) / 100
where q.qOp = getp(#val, getd());
end while;
END
new getC
BEGIN
DECLARE c float;
DECLARE qDa date;
select qDate into qDa from quotes where qDate like DATE_ADD(qD, INTERVAL v DAY );
SELECT qCl INTO c FROM quotes WHERE qDate = qDa;
RETURN c;
END
I changed the code of function getC to add (-1) in the first iteration. now it is working!
Thank you everyone for your help!
Your update cycle looks ok, even if i don't understand why you make 3 cycles. Shouldn't you use:
WHILE (#val < 3) DO
Instead of
WHILE (val < 3) DO
? Hope it helps
EDIT:
You need to debug your cycle to know where the problem is.
Try this:
BEGIN
DECLARE #p, #c float;
DECLARE #cpt, #val int;
SET #val = 0;
SET #cpt = (select count(*)-1 from quotes);
SELECT 'Enter Cycle';
WHILE (#val < 3) DO
SELECT 'In Cyle';
SET #p = getp(#val, getd());
SELECT #p;
SET c = getc(#val+1, getd());
set #val = #val + 1;
update quotes
set qCh = (#p * (100/#c) ) / 100
where qOp = #p AND qCl = #c;
end while;
END
Does you SP prints 'Enter Cycle' and 'In Cyle'? Does the value of p Variable prints? It is correct?

Calculating an Equation from a MySql Query

How can i select as result of an equation like this ( decimalnumber_1 / (100+decimalnumber_2) * 100 ) with a mysql query
decimalnumber_1 = //SELECT table_1.a_decimalnumber_1 AS decimalnumber_1 FROM table_1 WHERE table_1.another_coloumn_name = z
decimalnumber_2 = //SELECT table_2.a_decimalnumber_2 AS decimalnumber_2 FROM table_2 WHERE table_2.an_another_coloumn_name = x
result = //SELECT ( decimalnumber_1 / (100+decimalnumber_2) * 100 ) AS result
CREATE PROCEDURE #eqresult
#result int output
AS
DECLARE #decNum1 int,#decNum2 int
SET #decNum1=(SELECT table_1.a_decimalnumber_1 AS decimalnumber_1 FROM table_1
WHERE table_1.another_coloumn_name = z)
SET #decNum1=(SELECT table_2.a_decimalnumber_2 AS decimalnumber_2 FROM table_2
WHERE table_2.another_coloumn_name = x)
SET #result=( #decNum1 / (100+#decNum2) * 100 )
RETURN #result
Try
SELECT ( (SELECT table_1.a_decimalnumber_1 AS decimalnumber_1 FROM table_1 WHERE table_1.another_coloumn_name = z
)/ (100+(SELECT table_2.a_decimalnumber_2 AS decimalnumber_2 FROM table_2 WHERE table_2.an_another_coloumn_name = x
)) * 100 ) AS result