mariadb 存储函数导致除以0错误

shyt4zoc  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(106)

我有这两个函数和一个触发器来处理我正在处理的项目的点计算,与此交互以开始调用所有内容的示例查询是SELECT insertRun(76561198117520501, 99, 0, 757.91015625, 0, TRUE) as run_id。在getRunPointValue函数的某个地方,它导致了除以0的错误,并且在除以0的仅有的两个位置,如果它是0,则我显式地将正在使用的值设置为1,因此正在被divided不应该是0。这个问题已经在我的insertRun函数中被注解掉了UPDATE,但是这个函数调用是必要的,否则新的运行就不会被排名。这个函数99%的时间都能工作,而且它在一些奇怪的边缘情况下,比如你要么排名第一,要么排名最后,它会导致除以0的错误,从我所能观察到的。
我收到的确切错误代码是
1365,被零除
下面是我正在使用的SQL函数和触发器。

CREATE FUNCTION insertRun(userid BIGINT UNSIGNED, mid INT, styleid INT, run_time FLOAT(12,4), type INT, best BOOLEAN)
RETURNS INT
BEGIN
    DECLARE runid INT;
    DECLARE totalPoints INT DEFAULT 0;
    IF best = TRUE THEN
        UPDATE surf_run SET best_run = FALSE WHERE user_id = userid AND map_id = mid AND style = styleid AND run_type = type;
    END IF;
    INSERT INTO surf_run (user_id, map_id, style, time, run_type, best_run) VALUES (userid, mid, styleid, run_time, type, best);
    -- if best_run is true then set all other runs by user_id and map_id to false
    SELECT run_id INTO runid FROM surf_run WHERE user_id = userid AND map_id = mid AND style = styleid AND run_type = type AND best_run = TRUE ORDER BY run_id DESC LIMIT 1;
    --UPDATE surf_run SET points = getRunPointValue(runid) WHERE run_id = runid;
    SELECT SUM(points) INTO totalPoints FROM surf_run WHERE user_id = userid AND best_run=TRUE;
    UPDATE surf_user SET points = totalPoints WHERE user_id = userid;
    RETURN runid;
END;

CREATE FUNCTION getRunPointValue(id INT)
RETURNS INT
exit_getrunpointvalue:BEGIN
    DECLARE points INT DEFAULT 10;
    DECLARE total_completions INT DEFAULT 1;
    DECLARE place INT DEFAULT 1;
    DECLARE run_time FLOAT(12,4);
    DECLARE run_style INT;
    DECLARE type INT;
    DECLARE mapid INT;
    DECLARE maptier INT;
    DECLARE tierMulti FLOAT(3,2) DEFAULT 1.0;

    DECLARE percentile FLOAT(12,4);
    DECLARE total_points INT DEFAULT 3000;
    DECLARE percentile_potential INT;
    DECLARE completionsbonus INT DEFAULT 0;

    DECLARE temp FLOAT;

    DECLARE bracket_min INT DEFAULT 0;
    DECLARE bracket_max INT DEFAULT 0;

    SELECT time INTO run_time FROM surf_run WHERE run_id = id LIMIT 1;
    SELECT style INTO run_style FROM surf_run WHERE run_id = id;
    SELECT run_type INTO type FROM surf_run WHERE run_id = id;
    SELECT map_id INTO mapid FROM surf_run WHERE run_id = id;
    SELECT tier INTO maptier FROM surf_map WHERE map_id = mapid;

    IF type < 0 THEN
        LEAVE exit_getrunpointvalue;
    END IF;

    SELECT COUNT(*) INTO place FROM surf_run WHERE map_id = mapid AND time <= run_time AND style = run_style AND run_type = type AND best_run = TRUE;
    SELECT COUNT(*) INTO total_completions FROM surf_run WHERE map_id = mapid AND style = run_style AND run_type = type AND best_run = TRUE;

    IF total_completions <= 0 THEN
        SET total_completions = 1;
    END IF;
    SET completionsbonus = FLOOR((total_completions / 2) * 0.6);

    IF maptier = 1 THEN
        SET tierMulti = 1.0;
    ELSEIF maptier = 2 THEN
        SET tierMulti = 1.53;
    ELSEIF maptier = 3 THEN
        SET tierMulti = 2.5;
    ELSEIF maptier = 4 THEN
        SET tierMulti = 3.8;
    ELSEIF maptier = 5 THEN
        SET tierMulti = 6.0;
    ELSEIF maptier = 6 THEN
        SET tierMulti = 8.5;
    END IF;

    IF place = 0 THEN
        SET place = 1;
    END IF;

    IF place = 1 THEN
        SET points = 1500 + completionsbonus;
    ELSEIF place = 2 THEN
        SET points = 1250 + completionsbonus;
    ELSEIF place = 3 THEN
        SET points = 1100 + completionsbonus;
    ELSEIF place = 4 THEN
        SET points = 1000 + completionsbonus;
    ELSEIF place = 5 THEN
        SET points = 900 + completionsbonus;
    ELSE

        SET percentile = (place / total_completions);

        IF percentile <= 0.05 THEN
            SET percentile_potential = 800;
            SET points = 600;
            SET bracket_min = 0;
            SET bracket_max = total_completions * 0.05;
        ELSEIF percentile <= 0.10 THEN
            SET bracket_max = total_completions * 0.05 + 1;
            SET bracket_max = total_completions * 0.1;
            SET percentile_potential = 600;
            SET points = 450;
        ELSEIF percentile <= 0.15 THEN
            SET bracket_max = total_completions * 0.1 + 1;
            SET bracket_max = total_completions * 0.15;
            SET percentile_potential = 450;
            SET points = 200;
        ELSEIF percentile <= 0.25 THEN
            SET bracket_max = total_completions * 0.15 + 1;
            SET bracket_max = total_completions * 0.25;
            SET percentile_potential = 200;
            SET points = 10;
        END IF;
        SET points = points + GREATEST(0, ROUND(percentile_potential - percentile_potential * LOG(place, bracket_max))) + completionsbonus;
    END IF;
    RETURN FLOOR(points * tierMulti);
END;

CREATE TRIGGER updateRunPointValue AFTER INSERT ON surf_run FOR EACH ROW
exit_updaterunpoints_trugger:BEGIN

    DECLARE place INT DEFAULT 0;
    DECLARE total INT DEFAULT 1;
    DECLARE runoffset INT DEFAULT 0;

    DECLARE worst_time FLOAT(12,4);

    IF NEW.run_type < 0 THEN
        LEAVE exit_updaterunpoints_trugger;
    END IF;

    SELECT COUNT(*) INTO place FROM surf_run WHERE map_id = NEW.map_id AND time <= NEW.time AND style = NEW.style AND run_type = NEW.run_type AND best_run = TRUE;
    SELECT COUNT(*) INTO total FROM surf_run WHERE map_id = NEW.map_id AND style = NEW.style AND run_type = NEW.run_type AND best_run = TRUE;

    -- if total < 250 then
    --  LEAVE exit_updaterunpoints_trugger;
    -- END IF;

    SET runoffset = (total * 0.25) + 1;

    SELECT time INTO worst_time FROM surf_run WHERE map_id = NEW.map_id AND style = NEW.style AND run_type = NEW.run_type AND best_run = TRUE ORDER BY time DESC LIMIT 1 OFFSET runoffset;
    call rerunPointValue(NEW.map_id, worst_time, NEW.style, NEW.run_type);

END;```
xvw2m8pv

xvw2m8pv1#

我不确定这是怎么发生的,但我怀疑total_completions被设置为NULL而不是0

IF IFNULL(total_completions, 0) <= 0 THEN
    SET total_completions = 1;
END IF

相关问题