计算自然排序值以存储在DB中以进行字符串排序

时间:2012-06-26 17:55:45

标签: php algorithm sorting

以下是一些字符串示例(主要是地址):

12
20
43-B
43-C
123
2500

现在我把它们放在我认为是“正确”的顺序中。如果我要在数据库表的列中包含这些值并在MySQL搜索中返回这些值,我会得到:

12
123
20
2500
43-B
43-C

显然这是不正确的 - 20不大于123

如果我可以保证该值由纯整数组成,但是当你引入43-B43-C(或甚至12A或其他)时,很容易弄明白这一点,然后我们开始遇到问题。但是,我不能简单地删除数字!我现在还不完全确定它代表什么,但我确实有40W1等值。

就我个人而言,我认为不到40而不是4000,但这是一种非常罕见的边缘情况,所以我并不太担心这个特定的例子。我需要记住这些字母,因为40B会在40C之前出现 - 但我也希望40-B来到40C之前1}}。整蛊,对吧?我知道。

我愿意只假设字母数字字符(即从字符串中删除-)。

我想要做的是将该字符串转换为一系列绝对可排序的数字。

例如,43-B可能变成类似10000031205(填充)的内容,并与行的其余部分一起存储在数据库中。当我搜索我的地址时,我现在可以按排序列排序,然后按顺序排列所有内容!

我不能做的事情:

  • 在运行时直接比较它们
  • 在MySQL中进行此搜索(需要逐行计算值)
  • 在PHP中使用sort / asort / ksort或任何排序功能

我需要一个可以存储在我的数据库或搜索索引中的值,我可以在以后对其进行排序!

不幸的是,到目前为止我的所有尝试都未能产生我正在寻找的结果。有什么想法吗?

5 个答案:

答案 0 :(得分:2)

我会选择2列sortNumber int, sortText varchar,如果你在sql中使用PHP,intval($string);,则存储在第一列CAST(column as UNSIGNED)中,在另一列中存储不存在< / em>任何符号(一个preg_replace(array('/^-?[0-9]+/','/[^A-Z0-9]/i'),'',$input)运行的结果(我不知道SQL方式......)和SORT BY sortNumber, sortText。如果你需要考虑花车,它会变得更精细,但是不多了。

答案 1 :(得分:2)

我并不认为它是最有效的格式,但它会起作用。我假设没有负数。

我填充到5位数,但填充需要大于数字序列中的最大位数。

$input = '43-B1';
$nat = preg_replace_callback('#\d+#', function($m) {
    return str_pad($m[0], 5, '0', STR_PAD_LEFT);
}, $input);
echo $nat;

演示 http://codepad.viper-7.com/kefb4L

答案 2 :(得分:1)

如下:

preg_match('(\d*)[^a-zA-Z0-9]*(.*)', $houseNumber, $matches);
$sortable = sprintf("%08d%s", $matches[1], $matches[2]);

答案 3 :(得分:1)

create table cmp ( a varchar(255));

insert into cmp values ('12'), ('123'), ('20'), ('2500'), ('43-B'), ('43-C'), 
('4000'), ('40w1');

select a, lpad(cast(a as unsigned), 20, 0) from cmp 
order by lpad(cast(a as unsigned), 20, 0);

+------+----------------------------------+
| a    | lpad(cast(a as unsigned), 20, 0) |
+------+----------------------------------+
| 12   | 00000000000000000012             |
| 20   | 00000000000000000020             |
| 40w1 | 00000000000000000040             |
| 43-B | 00000000000000000043             |
| 43-C | 00000000000000000043             |
| 123  | 00000000000000000123             |
| 2500 | 00000000000000002500             |
| 4000 | 00000000000000004000             |
+------+----------------------------------+
8 rows in set, 6 warnings (0.00 sec)

您可以使用此类示例删除任何非数字,
并自然地排序。

这个警告并不是一个真正的止动器,
考虑到你试图从字符串列中进行数字排序。

答案 4 :(得分:0)

您是否考虑过将数值保存在单独的列中?如果这些是地址,那可能是合理的。并且性能优于散列或处理字符串。