复杂的ORDER BY需要对不规则值进行排序

时间:2013-07-06 08:09:10

标签: php mysql

我正在尝试开发一个系统来显示网页上数据库中的产品。通常这没有问题,除了一个制造商有几个我需要正确排序的异常部件号。

通常情况下,我可以使用不可见的列对事物进行排序,但这会使得在两个旧项目之间插入新项目变得更加困难。

例如,以下是部分编号:

1211
1225
14-302
14-303
2015
23157
3507
35280UP
42-3309
42-3312
4241

现在,mfgr的正常顺序产生上述顺序。 它应该是更像这样的东西:

14-302
14-303
42-3309
42-3312
1211
1225
2015
3507
4241
23157
35280UP

在正确排序时,最好的选择是什么?如果它们只是在csv文件中制作并在之后上传,那么这将不是问题。但由于数据库自动更改,服务器将实时修改值。因此,手动更新它是不可能的。这意味着将需要后端插入新项目,但是我可以通过什么方法在另一个项目之间插入项目?我宁愿不使用像小数这样的东西给我两个值之间的X(就像我有1.00和2.00而我想把它们放在它们之间,所以我把它设为1.50)。

任何帮助都将不胜感激。

修改

我想对它进行排序的方式是这样的: 如果它有一个连字符,即14-302,它按14排序,然后任何14-xxx按连字符后面的数字排序。 然后,只是数字将按实际数字排序,802在45768之前。 然后任何带有字母的数字将按数字排序,字母123b在123b之前但在122之后.123b在124c之前。 最后,任何以M-开头的东西都会被排序,最后是连字符。

1 个答案:

答案 0 :(得分:1)

根据调整后的问题,原则仍然相同。 我的第一直觉是使用额外的字段但你可以使用存储的函数。 你仍然需要将你的部分编号分成3部分(我认为它不超过那部分)。

  • Part1是一个INTEGER,并且如果现有的则使用maxint填充第一个数字(对于part1最大)。
  • 第2部分是CHAR,如果存在,则包含字母。
  • Part3是一个INTEGER,包含第二个数字(如果存在)。

您可以通过调用这些值的函数进行排序。

以下是完整的来源: 为方便起见,指向工作SQL Fiddle的链接。 它真的是草率/快速编程,但它的工作原理。在很短的时间内放在一起,我确信有一点需要改进。你可以自己调整一下。稍后您可以从视图中删除part1,part2和part3。 (但保留在order by)这只是为了说明排序是如何完成的。

DROP PROCEDURE IF EXISTS `uGetParts`//
DROP FUNCTION IF EXISTS `uExtractPart1`//
DROP FUNCTION IF EXISTS `uExtractPart2`//
DROP FUNCTION IF EXISTS `uExtractPart3`//

CREATE PROCEDURE `uGetParts`(
  IN ins varchar(50),
  OUT num1 int unsigned,
  OUT num2 int unsigned,
  OUT num3 int unsigned)
NO SQL
BEGIN
  SET num1=0;
  SET num2=0;
  SET num3=0;
  WHILE (num1<length(ins)) AND
    (SUBSTRING(ins,num1+1,1) REGEXP('(^[0-9]+$)')=1) DO
      SET num1=num1+1;
  END WHILE;
  SET num2=num1;
  WHILE (num2<length(ins)) AND
    (SUBSTRING(ins,num2+1,1) REGEXP('(^[0-9]+$)')=0) DO
      SET num2=num2+1;
  END WHILE;
  SET num3=num2;
  WHILE (num3<length(ins)) AND
    (SUBSTRING(ins,num3+1,1) REGEXP('(^[0-9]+$)')=1) DO
      SET num3=num3+1;
  END WHILE;
END//

CREATE FUNCTION `uExtractPart1`(ins varchar(50))
RETURNS int unsigned NO SQL
BEGIN
  DECLARE num1 INT default 0;
  DECLARE num2 INT default 0;
  DECLARE num3 INT default 0;
  call uGetParts(ins,num1,num2,num3);
  IF num1>0 THEN       
    RETURN CAST(SUBSTRING(ins,1,num1) AS UNSIGNED);
  ELSE
    RETURN ~0 >> 32;
  END IF;  
END//

CREATE FUNCTION `uExtractPart2`(ins varchar(50))
RETURNS varchar(50) NO SQL
BEGIN
  DECLARE num1 INT default 0;
  DECLARE num2 INT default 0;
  DECLARE num3 INT default 0;
  call uGetParts(ins,num1,num2,num3);
  IF num2>num1 THEN       
    RETURN SUBSTRING(ins,num1+1,num2-num1);
  ELSE
    RETURN '';
  END IF;  
END//      

CREATE FUNCTION `uExtractPart3`(ins varchar(50))
RETURNS int unsigned NO SQL
BEGIN
  DECLARE num1 INT default 0;
  DECLARE num2 INT default 0;
  DECLARE num3 INT default 0;
  call uGetParts(ins,num1,num2,num3);
  IF num3>num2 THEN       
    RETURN CAST(SUBSTRING(ins,num2+1,num3-num2) AS UNSIGNED);
  ELSE
    RETURN 0;
  END IF;  
END//

您可以这样称呼它:

SELECT 
  id,
  TYPE,
  uExtractPart1(TYPE) as part1,
  uExtractPart2(TYPE) as part2,
  uExtractPart3(TYPE) as part3
FROM Article
ORDER BY 
  uExtractPart1(TYPE),
  uExtractPart2(TYPE),
  uExtractPart3(TYPE)