Pregunta

Nuestra aplicación tiene un campo CustomerNumber. Tenemos cientos de diferentes personas que utilizan el sistema (cada uno tiene su propio nombre de usuario y su propia lista de CustomerNumbers). Un usuario individual puede tener un máximo de 100.000 clientes. Muchos de ellos tienen menos de 100.

Algunas personas sólo ponen los números reales en sus campos de número de clientes, mientras que otros utilizan una mezcla de cosas. El sistema permite 20 caracteres que pueden ser A-Z, 0-9 o un guión, y almacena estos en un VARCHAR2 (20). minúscula nada se hace en mayúsculas antes de ser almacenado.

Ahora, vamos a decir que tenemos un simple informe que enumera todos los clientes para un usuario concreto, ordenados por número de cliente. por ejemplo.

SELECT CustomerNumber,CustomerName
FROM Customer
WHERE User = ?
ORDER BY CustomerNumber;

Esta es una solución ingenua como las personas que sólo alguna vez utilizan números no quieren ver una especie alfabético normal (donde "10" viene antes de "9").

No deseo pedir al usuario alguna pregunta acerca de sus datos innecesarios.

Estoy usando Oracle, pero creo que sería interesante ver algunas soluciones para otras bases de datos. Por favor incluya la base de datos, que su respuesta trabaja.

¿Qué opinas de la mejor manera de implementar esto es?

¿Fue útil?

Solución

En Oracle 10g:

SELECT  cust_name
FROM    t_customer c 
ORDER BY
    REGEXP_REPLACE(cust_name, '[0-9]', ''), TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+'))

Esto ordenará por la primera aparición de número, no en cuanto a su posición, i. e:.

  1. customer1 < customer2 < customer10
    • cust1omer ? customer1
    • cust8omer1 ? cust8omer2

, donde un ? significa que el orden es indefinido.

Esto basta para la mayoría de los casos.

Para forzar un orden de publicación en caso 2, es posible añadir un REGEXP_INSTR(cust_name, '[0-9]', n) a veces ORDER BY lista n, para obligar a la primera aparición del grupo de dígitos n-ésimo (2nd, 3rd etc.).

Para forzar un orden de publicación en caso 3, es posible añadir un TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+', n)) a veces ORDER BY lista n, orden de n-ésimo forzando. grupo de dígitos.

En la práctica, la consulta que escribí es suficiente.

Es posible crear un índice basado en la función de estas expresiones, pero necesitará para forzarlo con un toque y un SORT ORDER BY de una sola pasada se llevará a cabo de todos modos, como el CBO no confía en los índices de la función de base suficiente para permitir que un ORDER BY en ellos.

Otros consejos

Probablemente la mejor opción es calcular previamente una columna separada y usar eso para ordenar y utilizar el número de cliente para su visualización. Esto probablemente implicará 0-padding cualquier número entero internos a una longitud fija.

La otra posibilidad es hacer su clasificación después de la selección en los resultados devueltos.

Jeff Atwood ha reunido un blog acerca de cómo algunas personas calculan los criterios de ordenación de amistad humanos.

usted podría tener una columna numérica [CustomerNumberInt] que sólo se utiliza cuando el CUSTOMERNUMBER es puramente numérico (NULL lo contrario [1]), entonces

ORDER BY CustomerNumberInt, CustomerNumber

[1] dependiendo de la versión de SQL maneja nulos en ORDER BY es posible que desee por defecto a cero (o infinito!)

Tengo un horrible situación similar y he desarrollado una función adecuadamente horrible para tratar con él (SQLServer)

En mi situación tengo una tabla de "unidades" (este es un sistema de seguimiento de trabajo para los estudiantes, por lo que la unidad en este contexto representa un curso que están haciendo). Las unidades tienen un código, que en su mayor parte es puramente numérico, pero por diversas razones, se hizo un varchar y decidieron anteponer alguna por hasta 5 caracteres. Por lo que esperan 53123237356 para ordenar normalmente, pero también T53, T123, T237, T356

Código de Unidad es un nvarchar (30)

Aquí está el cuerpo de la función:

declare @sortkey nvarchar(30)

select @sortkey = 
    case
        when @unitcode like '[^0-9][0-9]%' then left(@unitcode,1) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-1)
        when @unitcode like '[^0-9][^0-9][0-9]%' then left(@unitcode,2) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-2)
        when @unitcode like '[^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,3) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-3)
        when @unitcode like '[^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,4) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-4)
        when @unitcode like '[^0-9][^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,5) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-5)
        when @unitcode like '%[^0-9]%' then @unitcode
        else left('000000000000000000000000000000',30-len(@unitcode)) + @unitcode
    end 

return @sortkey

quería pegarme un tiro en la cara después de escribir que, sin embargo funciona y parece no matar el servidor cuando se ejecuta.

He utilizado este en SQL SERVER y funcionando muy bien: Aquí la solución es rellenar los valores numéricos con un carácter delante de modo que todos son de la misma longitud de cadena

.

Aquí está un ejemplo utilizando este enfoque:

select MyCol
from MyTable
order by 
    case IsNumeric(MyCol) 
        when 1 then Replicate('0', 100 - Len(MyCol)) + MyCol
        else MyCol
    end

El 100 debe sustituirse con la longitud real de esa columna.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top