Cómo ordenar y visualizar listas mixtas de alfas y números que los usuarios esperan?
-
23-08-2019 - |
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 CustomerNumber
s). 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?
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:.
-
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.