2009-07-06 13 views
8

Voglio memorizzare un elenco di numeri (in sostanza, un set in termini matematici) in un database relazionale, in particolare SQL Server 2005.Come si memorizza al meglio un elenco di numeri in un database relazionale?

Idealmente, vorrei che fosse una singola colonna su una determinata tabella, ma sono disposto a sentire qualsiasi tipo di soluzione. I dati che devo memorizzare sono, come ho detto, una serie di numeri.

  • Non è necessario essere sequenziale (cioè le lacune vanno bene, normale e tipico)
  • Ranges sono possibili (ad esempio 1-4), ma mentre mi piacerebbe visualizzare in questo modo io' m bene con l'utilizzo di scorciatoie e tali per memorizzarlo
  • Può anche essere "tutto", quindi almeno un valore deve essere riservato, preferibilmente logicamente, per questo caso "infinito"
  • L'elenco dei numeri non deve essere ordine (cioè 3, 2, 9, 5) ma è preferibile e perfettamente ragionevole che siano e possano essere ordinati prima di inserirli, poiché solo il codice farà l'inserimento, non gli utenti manuali. Tuttavia, probabilmente non dovrebbe fare affidamento o aspettarsi che l'elenco sia già ordinato.
  • L'insieme dei numeri deve essere facilmente reperibile per un sottoinsieme (vedi sotto)
  • Tutti i numeri devono essere distinti (non dupes), ma questo può e verranno applicate prima dell'inserimento

Questa colonna è destinata per memorizzare tutti i "numeri di passo" di un dato processo a cui si applica la riga. Ogni riga può, quindi, applicare a uno o più passaggi, in qualsiasi ordine, intervallo o sequenza. Il numero massimo di passi possibili (il range massimo, in sostanza) è diverso da una riga all'altra, anche se dubito fortemente che qualcuno di loro entrerà a centinaia, quindi nel 99,9% dei casi il massimo non dovrebbe mai superare i 20 o 30, e io sarei sorpreso se arrivasse mai vicino a 100. Ogni riga è garantita per avere un valore (passo) al minimo (cioè non ha senso avere una riga che non si applica a nessun passo), ma io la figura è semplice come impostare la colonna su not null.

Tuttavia, è archiviato, mi piacerebbe che fosse cercato facilmente. Per esempio, preferirei non dover passare attraverso molti loop per scrivere una query SQL per trovare tutte le righe che si applicano al "passaggio 3", per esempio. Se una determinata riga ha diversi passaggi a cui si applica (ad esempio, 2, 3, 7 e 8), non dovrebbe essere troppo difficile abbinarla durante la ricerca dal passaggio 3.

Inoltre, mentre mi piacerebbe per dare una sorta di senso logico quando si guardano i dati grezzi (per chiunque abbia bisogno di lavorare sul sistema dopo che non sono in giro per chiedere e quindi non devono leggere una documentazione spessa per capire la mia oscura codifica), Sono disposto a scendere a compromessi su questo. La codifica dell'elenco in qualcosa che può essere decodificato in modo affidabile è, quindi, accettabile.

Mi scuso se questo è un dupe — Sono stato su Google ma ho il sospetto che questo mio problema soffra di non sapere cosa cercare o come esprimere o chiamarlo per trovare quello che sto cercando.

Su una nota di commento, mi chiedo se questa non è una di quelle aree in cui i database relazionali sono insufficienti. Sfortunatamente, non ho scelta qui. Devo memorizzarlo in SQL Server. Ho paura che salvare separatamente in un file o in un'altra memoria persistente dei dati sia fuori questione.

risposta

1

finito per usare un solution to a similar question.

Grazie lo stesso, però! Mi piace leggere le opinioni di tutti su queste aree esoteriche di progettazione di database.

2

E perché i passaggi della tabella aggiuntivi (processID JOIN, step INT) non sono un'opzione? Sono abbastanza sicuro che sarebbe il più semplice da mantenere/codice.

SELECT process.name FROM process, steps WHERE process.id = steps.processID AND steps.step = 3; 

Pardon My SQL, ma è stato un po ':)

EDIT: UNIQUE(processID, step) sarebbe consigliabile.

1

userei un design relazionale semplice e canonica: CREATE TABLE gamme (process_id int, int num_low, num_hi int). Le ultime due colonne specificano l'intervallo. Indice indipendente su ogni colonna. Per valori infiniti "speciali" usa solo i massimi o le colonne booleane aggiuntive.

Vantaggi: ricerca semplice se un determinato numero è nel campo o se gli intervalli si intersecano. Facile manutenzione Comprensibilità generale e semplicità.

Svantaggi: è necessaria una certa logica durante la modifica del set, ovvero il controllo dell'intervallo appena inserito o modificato interseca. Possono essere richiesti intervalli di giunzione.

+0

Ma l'elenco non hanno bisogno (e di solito non è) una bella gamma semplice. Tipicamente è uno o due, forse tre numeri distinti in nessuna sequenza particolare (cioè 3, 5, 9). Solo occasionalmente è 1 - 4. –

4

non riesco a ricordare la terminologia corretta per questo, ma il modo corretto per farlo sarebbe quello di creare una tabella come quella qui sotto:

| id | table1_id | value | 
-------------------------------- 
| 0 |   1 |  1 | 
| 1 |   1 |  2 | 
| 2 |   1 |  3 | 
| 3 |   1 |  7 | 
| 4 |   1 |  9 | 
| 5 |   2 |  1 | 
| 6 |   2 |  3 | 
| ... |  ... | ... | 

Per ogni valore in tabella 1 si aggiungono i valori richiesti in questo tavolo.

Per "tutti" è possibile creare una colonna in table1 che è una bandiera che è possibile impostare se si desidera tutto. (Io uso 'enum' in MySql ma non sono sicuro che esista in SQL Server).

Non sono sicuro che ci sia un modo specifico per Sql Server poiché utilizzo principalmente MySql.

+0

Ho menzionato la piattaforma, ma sinceramente spero che la risposta sia abbastanza generica per qualsiasi sistema di database relazionale ragionevolmente caratterizzato. Preferirei non fare affidamento su una soluzione collegata a Microsoft, ma se ci sono alcuni trucchi ingegnosi sono tutto per questo. Ad esempio, utilizzo spesso Common Table Expressions e sono abbastanza sicuro che siano una funzionalità specifica di SQL Server. –

1

La risposta qui sotto per fare un sottotabella (MitMaro) è il modo "standard".

se si deve mettere una serie di numeri in una colonna o di una tabella anche se l'unico modo che posso immaginare è quello di utilizzare le operazioni bit per bit per memorizzare il set ed è possibile utilizzare le operazioni bit a bit nelle query tuoi dati per cercare bit specifici che sono impostato. Ricerca rapida su google indica che MSSql 2005 supporta questo, ma solo fino a 32-bit int, quindi se passi 32 passi incontrerai problemi.

Tutto sommato, la sottotabella è la più normale sarebbe fare per le query un po 'più comprensibili contro il tavolo (s). Questo è anche il modo più sicuro per supportare qualsiasi caso futuro in cui si possano ottenere mappe con valore superiore a 32.

1

Se non sono legati a SQL Server, PostgreSQL ha grande supporto per questo genere di cose attraverso un array. Hanno persino un valore speciale per l'infinito.

Se sei legato a SQL Server, il modo in cui MitMaro è il migliore.

+0

Interessante che abbia quello. Volevo qualcosa come un tipo di dati "array". Ma sì, mi viene richiesto di usare quello che abbiamo --- SQL Server. :) –

1
create table setmember (setid int, setmemberid int) 
create unique nonclustered index idx_setmember_idx1 on setmember (setid, setmemberid) 

Consentitemi di assumere un numero magico (-1 o 999999999) per "tutti".

Questo sarà altamente performante sia per le query su base per set, sia per l'aggiornamento tramite l'indice non cluster. L'unicità non impone ripetizioni di voci. È problematico imporre un "tutto" o più membri del set multipli come un vincolo, ma ci sono rendimenti decrescenti anche se potrebbe essere fatto in un trigger.

Inoltre aggiungere

create nonclustered index idx_setmember_idx2 on setmember (setmemberid, setid) 

per consentire per le query di ricerca inversa efficienti.

Se si utilizzano tipi di array, si può essere in grado di attuare la ricerca inversa efficiente.

Nota tutta la SQL ANSI sopra è compatibile.

Problemi correlati