0

我有一个 PHP 函数来创建那些著名的 AlphaID 整数表示,如下所示:

function alphaID( $input ) {

    $index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

    $base    = strlen( $index );
    $input  += pow( $base, 4 );
    $output  = '';

    for( $i = floor( log( $input, $base ) ); $i >= 0; $i-- ) {

        $bcp     = bcpow( $base, $i );
        $start   = floor( $input / $bcp ) % $base;
        $output .= substr( $index, $start, 1 );
        $input   = $input - ( $start * $bcp );
    }

    return $output;
}

编码,例如,PHP_MAX_INT常量 (2147483647) 提供的最大整数将返回cwuCBb

但是我认为在整个应用程序图片中它有点太慢了,所以我尝试创建一个 MYSQL 函数,所以理论上,一旦数据在查询时为我准备好,我就不会浪费性能使用 PHP 进行这种转换。

MySQL手册并不完全友好,但在这里和那里搜索我想出了这个:

DROP FUNCTION IF EXISTS ENCODE_ALPHAID;

DELIMITER $$

CREATE FUNCTION ENCODE_ALPHAID( input integer ) RETURNS CHAR( 6 ) DETERMINISTIC

BEGIN

    DECLARE output CHAR( 6 );

    DECLARE letters CHAR( 62 );
    DECLARE base TINYINT( 2 );

    DECLARE iterator TINYINT( 2 );
    DECLARE bcp CHAR( 9 );
    DECLARE start TINYINT( 2 );

    SET output   = '';

    SET letters  = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

    SET base     = CHAR_LENGTH( letters );
    SET input    = input + POW( base, 4 );

    SET iterator = FLOOR( LOG( base, input ) );

    ENCODING: LOOP

        SET bcp      = POW( base, iterator );
        SET start    = FLOOR( input / bcp ) % base + 1;

        SET output   = CONCAT( output, SUBSTR( letters, start, 1 ) );

        SET input    = input - ( start * bcp );

        SET iterator = iterator-1;

        IF iterator < 0 THEN LEAVE ENCODING; END IF;

    END LOOP ENCODING;

    RETURN output;

END $$

DELIMITER ;

但是当我通过我使用的 MySQL 管理器(DBNinja)运行它时,显然没有任何反应。运行查询后,它显示0 行受影响,我不确定这是否是预期的输出。

无论对与否,该函数都不起作用,因为当我尝试在查询中使用它时:

SELECT ENCODE_ALPHAID( `c`.`cid` ) from `table` c WHERE `c.user` = 1

我第一次收到一个错误,说table.ENCODE_ALPHAID不存在。然后我注意到,事实上,我在尝试使用的数据库的不同数据库中创建了该函数。

但是我在正确的数据库中再次创建了它,但出现了同样的错误。

所以这里有问题:

  1. 我做错了什么?这是我第一次尝试做这样的事情,我不确定
  2. 我的 PHP 代码实现是有效的 MySQL 对应物吗?我错过了什么吗?
  3. 我可以将此功能设为“全局”吗?我的意思是,可用于我需要的任何数据库?因为对于我正在处理的应用程序,为了使所涉及的两个子系统保持分离,我创建了两个数据库。

更新

显然,没有创建函数的问题出在 DBNinja 的末尾,因为我直接在 MySQL 控制台中运行了该语句,虽然输出状态相同,0 行受影响,但我能够在语句中有效地使用该函数,所以函数毕竟是创建的。

但是,例程本身有问题,因为当我测试它时,结果字符串是......“一个领先”。

例如,如果我运行以下 PHP 代码:

echo alphaID( 2 );

它会产生baaac,但 MySQL 函数返回baaad,这将是整数3的 AlphaID 表示

这不仅是错误的,而且我认为它还可能溢出达到最大值时使用的 INT 类型 2147483647

4

2 回答 2

1

布鲁诺,您缺少 MySQL 版本:

  1. $input += pow($base, 4);
  2. PHP 中的 SUBSTR 从 0 开始,在 MySQL 中它从 1 开始。
  3. 循环结束条件应该是:

    IF iterator < 0 THEN LEAVE ENCODING; 万一;

  4. 使用 CONCAT 时,请确保不要 CONCAT NULL(您应该初始化参数)

例程总是在一个数据库中创建。您可以通过在查询中包含数据库名称来调用它们中的任何一个(如果您有特权):

call mydb.ENCODE_ALPHAID( 2147483647 );

此外,在声明变量时,您可能希望使用前缀,以免变量与可能的列名/保留字混淆。例如,使用“v_output”代替“输出”。

于 2016-07-11T21:02:09.287 回答
0

好像你错过了 END IF; 不要对变量使用保留字。如果你想走邪恶的路,请确保引用它们。即`table`,。注意反勾号 - 不是单引号。在我的机器上,这段代码返回 null:

CREATE DEFINER=`root`@`localhost` FUNCTION `ENCODE_ALPHAID`(`input` INT)
RETURNS CHAR(6) DETERMINISTIC NO SQL SQL SECURITY DEFINER 
BEGIN     
DECLARE output CHAR(6);
DECLARE `index` CHAR(62); 
DECLARE base TINYINT(2); 
DECLARE iterator TINYINT( 2 );
DECLARE bcp CHAR( 9 ); 
DECLARE start TINYINT( 2 ); SET `index` = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
SET base = CHAR_LENGTH( `index` ); 
SET iterator = FLOOR( LOG( base, input ) ); 
ENCODING: LOOP
SET bcp = POW( base, iterator ); 
SET start = FLOOR( input / bcp ) % base;
SET output = CONCAT( output, SUBSTR( `index`, start, 1 ) ); 
SET input = input - ( start * bcp );
SET iterator = iterator-1;
IF iterator >= 0 THEN LEAVE ENCODING; 
END IF;
   END LOOP ENCODING; 
   RETURN output; 
END;

在此处输入图像描述

PS:在后面打勾使用一个。我不知道如何逃避降价。并且eaid是我使用的较短名称

于 2016-07-11T22:12:02.580 回答