Come ordinare e visualizzare elenchi misti di alpha e numeri come gli utenti si aspettano?
-
23-08-2019 - |
Domanda
La nostra applicazione ha un campo CustomerNumber
. Abbiamo centinaia di diverse persone che utilizzano il sistema (ognuno ha il proprio login e la propria lista di CustomerNumber
s). Un singolo utente potrebbe avere al massimo 100.000 clienti. Molti hanno meno di 100.
Alcune persone solo mettere numeri reali nei loro campi di numero di clienti, mentre altri usano una miscela di cose. Il sistema consente di 20 caratteri che possono essere A-Z, 0-9 o un trattino, e memorizza questi in un VARCHAR2 (20). Tutto ciò è reso minuscolo in maiuscolo prima di essere stoccato.
Ora, supponiamo di avere un semplice report che elenca tutti i clienti di un determinato utente, ordinati per cliente. per es.
SELECT CustomerNumber,CustomerName
FROM Customer
WHERE User = ?
ORDER BY CustomerNumber;
Questa è una soluzione ingenua come le persone che sempre e solo usare i numeri non vogliono vedere una sorta alfabetico pianura (dove "10" viene prima di "9").
Non voglio chiedere all'utente tutte le domande inutili sui propri dati.
Sto utilizzando Oracle, ma penso che sarebbe interessante vedere alcune soluzioni per altri database. Si prega di includere il database la risposta funziona su.
Cosa pensa il modo migliore per attuare questo è?
Soluzione
In 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]+'))
In questo modo l'ordinamento in base alla prima occorrenza del numero, non per quanto riguarda la sua posizione, i. e:.
-
customer1 < customer2 < customer10
-
cust1omer ? customer1
-
cust8omer1 ? cust8omer2
-
, dove un ?
significa che l'ordine è indefinito.
Questo è sufficiente per la maggior parte dei casi.
Per forzare l'ordinamento sul caso 2
, si può aggiungere un REGEXP_INSTR(cust_name, '[0-9]', n)
per ORDER BY
volte lista n
, ordine forzatura sulla prima apparizione di n
-esimo (2nd
, 3rd
etc.) gruppo di cifre.
Per forzare l'ordinamento sul caso 3
, si può aggiungere un TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+', n))
per ORDER BY
volte lista n
, ordine di n
-esimo forzatura. gruppo di cifre.
In pratica, la domanda che ho scritto è sufficiente.
È possibile creare un indice basato sulla funzione di queste espressioni, ma avrete bisogno di forzarla con un suggerimento e un SORT ORDER BY
in un solo passaggio verrà eseguita in ogni caso, come il CBO
non si fida indici funzione-base sufficiente per consentire una ORDER BY
su di loro.
Altri suggerimenti
Probabilmente la cosa migliore è di controllare la validità calcolare una colonna separata e l'uso che per ordinare e utilizzare il codice cliente per la visualizzazione. Questo probabilmente comporterà 0-padding qualsiasi interi interne ad una lunghezza fissa.
L'altra possibilità è di fare il vostro ordinamento post-select sui risultati restituiti.
Jeff Atwood ha messo insieme un post di blog su come alcune persone calcolare ordinamento amichevoli umani.
Si potrebbe avere una colonna numerica [CustomerNumberInt] che viene utilizzato solo quando il CustomerNumber è puramente numerico (NULL altrimenti [1]), allora
ORDER BY CustomerNumberInt, CustomerNumber
[1] a seconda di come la versione di SQL gestisce NULL in ORDER BY si potrebbe desiderare di default a zero (o infinito!)
Ho una situazione orribile simile e hanno sviluppato una funzione opportunamente orribile occuparsi di esso (SQLServer)
Nella mia situazione ho una tabella di "unità" (si tratta di un sistema di lavoro-tracking per gli studenti, in modo da unità in questo contesto rappresenta un corso che stanno facendo). Unità hanno un codice, che per la maggior parte è puramente numerico, ma per vari motivi si è fatto un varchar e hanno deciso di prefissare alcuni fino a 5 caratteri. Quindi si aspettano 53.123.237,356 mila per ordinare normalmente, ma anche T53, T123, T237, T356
UnitCode è un nvarchar (30)
Ecco il corpo della funzione:
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
volevo spararmi in faccia dopo aver scritto che, comunque funziona e sembra di non uccidere il server quando viene eseguito.
Ho usato questo in SQL SERVER e funzionare grande: Qui la soluzione è di rilievo i valori numerici con un carattere di fronte in modo che tutti hanno la stessa lunghezza della stringa
.Ecco un esempio utilizzando tale approccio:
select MyCol
from MyTable
order by
case IsNumeric(MyCol)
when 1 then Replicate('0', 100 - Len(MyCol)) + MyCol
else MyCol
end
Il 100 deve essere sostituito con la lunghezza effettiva della colonna.