MySQL存储过程表现不可预测

时间:2015-03-21 08:02:19

标签: mysql

编写存储过程以解析格式的名称' last first mid'并且'最后一个中间后缀'进入一张桌子。


CREATE PROCEDURE parse_full_name(full_name TEXT)
  BEGIN
    SET @last_name = SUBSTRING_INDEX(full_name, ' ', 1);
    SET @middle_name = SUBSTRING_INDEX(full_name, ' ', -1);
    SET @first_name = SUBSTR(full_name, LOCATE(' ', full_name), LENGTH(full_name) - LENGTH(@middle_name) - LENGTH(@last_name));

    SET @query = CONCAT('SELECT ''', @last_name,''' as last_name, ''', @first_name,''' as first_name, ''', @middle_name,''' as middle_name;');
    PREPARE stmt FROM @query;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
  END;

CALL parse_full_name('last first middle');

>>>  last_name | first_name | middle_name
>>> -----------|------------|-------------
>>>  last      | first      | middle

CALL parse_full_name('last first middle suffix');

>>>  last_name | first_name   | middle_name
>>> -----------|--------------|-------------
>>>  last      | first middle | suffix

到底是什么预期的。现在让我们处理后缀:

CREATE PROCEDURE parse_full_name(full_name TEXT)
  BEGIN # assume full_name is 'last first middle' until proven not
    SET @last_name = SUBSTRING_INDEX(full_name, ' ', 1);
    SET @middle_name = SUBSTRING_INDEX(full_name, ' ', -1);
    SET @first_name = SUBSTR(full_name, LOCATE(' ', full_name), LENGTH(full_name) - LENGTH(@middle_name) - LENGTH(@last_name));

    # check if full_name is actually 'last first mid suffix'
    # if so then first_name will contain 'first middle'
    IF LOCATE(' ', @first_name) THEN # this if statement always evaluates to true
      SET @last_name = CONCAT(@last_name, ' ', @middle_name);
      SET @middle_name = SUBSTRING_INDEX(@first_name, ' ', -1); # mysql seems to skip this line of code
      SET @first_name = SUBSTRING_INDEX(@first_name, ' ', 1);   # this line too
    END IF;

    SET @query = CONCAT('SELECT ''', @last_name,''' as last_name, ''', @first_name,''' as first_name, ''', @middle_name,''' as middle_name;');
    PREPARE stmt FROM @query;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
  END;

结果:

CALL parse_full_name('last first middle jr');

期待:

>>>  last_name | first_name | middle_name
>>> -----------|------------|-------------
>>>  last jr   | first      | middle

但是得到:

>>>  last_name | first_name | middle_name
>>> -----------|------------|-------------
>>>  last jr   |            |

甚至更好:

CALL parse_full_name('last first middle');

>>>  last_name   | first_name | middle_name
>>> -------------|------------|-------------
>>>  last middle |            |

那么,问题出在哪里?我不是MySQL专家,但所有内容在逻辑上和直觉上都是正确的。

2 个答案:

答案 0 :(得分:1)

菜鸟错误。只需修剪弦乐。

SET @len_first_name = LENGTH(full_name) - LENGTH(@middle_name) - LENGTH(@last_name));
SET @first_name = SUBSTR(full_name, LOCATE(' ', full_name), @len_first_name);

@len_first_name抓住第一个和中间的空格,因此@first_name最终返回' first middle',这可以解释为什么LOCATE(' ', @first_name)总是返回true。


SET @last_name = TRIM(SUBSTRING_INDEX(full_name, ' ', 1));
SET @middle_name = TRIM(SUBSTRING_INDEX(full_name, ' ', -1));
SET @len_first_name = LENGTH(full_name) - LENGTH(@middle_name) - LENGTH(@last_name);
SET @first_name = TRIM(SUBSTR(full_name, LOCATE(' ', full_name), @len_first_name));

它正在工作。

答案 1 :(得分:0)

任务无法解决。

  • “Mary Jane”是一个常见的first_name - 不是的第一个和中间的。
  • 很多英国人都有2个字的姓氏。
  • 我见过“亲爱的Iii先生”和“亲爱的史密斯先生Iii”。从技术上讲,“III”应该全部为大写,并以逗号开头。
  • 你会搞乱这个案子吗? (麦当劳 - >麦克唐纳?)或撇号(O'Henry)。
  • 有些人有多个middle_name。

你正在努力让那些名字不符合简单解析规则的人烦恼。

为什么需要解析名称?你不能简单地存储和反刍full_name吗?