2012-02-18 32 views
5

Estoy trabajando con un conjunto grande de datos heredados (convertido desde un db de archivo plano), donde un campo tiene el formato de los dos últimos dígitos del año se ingresó el registro, seguido de un incremento de 4 dígitos ...MySQL: crear una función definida por el usuario para una ordenación personalizada

por ejemplo, el tercer registro creado en 1998 sería "980003", y el undécimo registro creado en 2004 sería "040011".

no puedo cambiar estos valores: existen a través de su compañía, están registrados con el estado, clientes, etc. Sé que sería genial separar el año y el resto en columnas separadas, pero eso es imposible. Ni siquiera puedo hacerlo "internamente", ya que cada fila tiene alrededor de 300 campos que son todos ordenables, y están muy acostumbrados a trabajar con este campo como un identificador de registro.

así que estoy tratando de implementar una UDF de MySQL (por primera vez) para ordenar. La consulta se ejecuta con éxito y me permite "seleccionar cualquier cosa desde el orden de la tabla por encargo_compilación (lo que sea)", pero el orden no es lo que esperaba.

Aquí es lo que estoy usando:

DELIMITER // 

CREATE FUNCTION custom_sort(id VARCHAR(8)) 
    RETURNS INT 
    READS SQL DATA 
    DETERMINISTIC 
    BEGIN 
     DECLARE year VARCHAR(2); 
     DECLARE balance VARCHAR(6); 
     DECLARE stringValue VARCHAR(8); 
     SET year = SUBSTRING(0, 2, id); 
     SET balance = SUBSTRING(2, 6, id); 
     IF(year <= 96) THEN 
      SET stringValue = CONCAT('20', year, balance); 
     ELSE 
      SET stringValue = CONCAT('19', year, balance); 
     END IF; 
     RETURN CAST(stringValue as UNSIGNED); 
    END// 

Los registros sólo se remontan al 96 (de ahí el arbitrario "si los 2 primeros caracteres son menos de 96, anteponga '20' en otro caso anteponer '19'). No estoy contento con este poco, pero no creo que ahí es donde está el problema central.

Para lanzar otra llave en los trabajos, resulta que 1996 y 1997 son ambos de 5 dígitos, siguiendo el mismo patrón descrito arriba, pero en lugar de un incremento de 4 dígitos, es un incremento de 3 dígitos. De nuevo, sospecho que esto será un problema, pero no es el problema principal.

Un ejemplo de los beneficios que estoy obteniendo con este Custom_Sort:

001471 
051047 
080628 
040285 
110877 
020867 
090744 
001537 
051111 
080692 
040349 
110941 
020931 
090808 
001603 
051175 

que realmente no tienen idea de lo que estoy haciendo aquí y nunca he usado MySQL para una UDF como esto - cualquier ayuda se agradece .

TYIA

/EDIT errata

/EDIT 2 concat necesario "años" valor añadido - que todavía consigue los mismos resultados

+0

¿Cómo sabe MySQL que está realizando un 'UNSIGNED INT', y no por ejemplo' UNSIGNED TINYINT'? ¿Sabe o asume algún tipo numérico predeterminado? – biziclop

+0

no tengo idea :) – momo

+0

¿No es posible agregar una nueva columna a la base de datos con los valores fijos? De todos modos, para el problema de longitud de número diferente, puede usar la función 'LPAD': http://dev.mysql.com/doc/refman/5.1/en/string-functions.html#function_lpad – biziclop

Respuesta

5

Usted tiene algunos problemas con sus subseries, y el elenco a int en el end lo hace ordenar valores con más dígitos al final, no por año. Esto debería funcionar mejor;

DELIMITER // 

CREATE FUNCTION custom_sort(id VARCHAR(8)) 
    RETURNS VARCHAR(10) 
    READS SQL DATA 
    DETERMINISTIC 
    BEGIN 
     DECLARE year VARCHAR(2); 
     DECLARE balance VARCHAR(6); 
     DECLARE stringValue VARCHAR(10); 
     SET year = SUBSTRING(id, 1, 2); 
     SET balance = SUBSTRING(id, 3, 6); 
     IF(year <= 96) THEN 
      SET stringValue = CONCAT('20', year, balance); 
     ELSE 
      SET stringValue = CONCAT('19', year, balance); 
     END IF; 
     RETURN stringValue; 
    END// 

DELIMITER ; 

Esto se puede simplificar un poco a;

DELIMITER // 

CREATE FUNCTION custom_sort(id VARCHAR(8)) 
    RETURNS varchar(10) 
    DETERMINISTIC 
    BEGIN 
     IF(SUBSTRING(id, 1, 2) <= '96') THEN 
      RETURN CONCAT('20', id); 
     ELSE 
      RETURN CONCAT('19', id); 
     END IF; 
    END// 

DELIMITER ; 
+0

probando en este momento ... – momo

+0

¡mucho más cerca!pero creo que la cosa de 5 dígitos frente a 6 dígitos es un problema (por eso estaba tratando de convertir a INT) ... si ordeno ASC obtengo 97001, 97002, 97003, si selecciono DESC obtengo 96323, 96322, 96321. el "primer" registro probablemente debería ser 96 y algo, y el "último" debería ser 12 y algo ... – momo

+0

Un trazador de líneas: 'CONCAT (IF (SUBSTRING (id, 1, 2) <= '96', '20', '19'), id) ' – biziclop

Cuestiones relacionadas