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 CustomerNumbers). 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 è?

È stato utile?

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:.

  1. 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top