Indice univoco su più campi con valori vuoti

di il
14 risposte

Indice univoco su più campi con valori vuoti

Ho un problema con gli indici univoci in Access:
Ho una tabella con tre campi di testo, ho definito l'indice univoco su questi tre campi però il controllo di univocità viene fatto solo se tutti e tre i campi sono completati, mentre io avrei bisogno che mi indentificasse anche come doppioni i record con solo i primi due campi compilati...

Come posso fare? Mi servirebbe definirlo gia' in tabella, ma se non possibile, anche da maschera con un controllo in vba, eventualmente

Un campo lasciato vuoto, di testo o numerico che sia, come viene visto da Access?

allego immagini di esempio:





In pratica, se inserisco "Toso Spumante Secco" mi dice è gia' presente,
mentre se scrivo "Toso Spumante" mi lascia inserirlo invece di dirmi che è gia' presente.

14 Risposte

  • Re: Indice univoco su più campi con valori vuoti

    Non ci sono mai riuscito neanche io e l'unico espediente che ho trovato è quello di sostituire tutti i valori Null con "stringa di lunghezza zero" ottenibile scrivendo:
    ""
    In questi casi imposto anche "" come Valore predefinito.
  • Re: Indice univoco su più campi con valori vuoti

    Rammento che NULL e "" sono due "cose" estremamente diverse, sia dal punto di vista teorico, che nelle implicazioni pratiche
  • Re: Indice univoco su più campi con valori vuoti

    Grazie Osvaldo, ottima idea, funziona.
    Spero di non andare incontro in futuro ai problemi giustamente rammentati da +m2+ nel proseguo del mio sviluppo...
  • Re: Indice univoco su più campi con valori vuoti

    neobios ha scritto:


    Grazie Osvaldo, ottima idea, funziona.
    Spero di non andare incontro in futuro ai problemi giustamente rammentati da +m2+ nel proseguo del mio sviluppo...
    Basta ci sia consapevolezza sul valore tecnico di questa scelta... , ma sospetto di no.
  • Re: Indice univoco su più campi con valori vuoti

    @Alex ha scritto:


    neobios ha scritto:


    Grazie Osvaldo, ottima idea, funziona.
    Spero di non andare incontro in futuro ai problemi giustamente rammentati da +m2+ nel proseguo del mio sviluppo...
    Basta ci sia consapevolezza sul valore tecnico di questa scelta... , ma sospetto di no.

    cosa proporresti altrimenti? Ha qualche idea ?
  • Re: Indice univoco su più campi con valori vuoti

    Dal momento che hai un Campo PK Univoco... mi pare ci siano troppe cose insieme.
    Se lo scopo è individuare possbili Dupplicati, e dando per scontato che l'inserimento e la manupolazione dei dati deve avvenire esclusivaente da Interfaccia Utente, ovvero la Maschera che devi predisporre... puoi Testare l'univocità prima di INSERIRE un nuovo Record ad esempio...
    Quindi va bene che questi 3 campi siano INDICI, non definirne l'univocità aggregata, ma controlla su Evento BeforeUpdate di Maschera se è vera la condizione di Esistenza di un Record con la condizione di confronto dei 3 campi AND.
    La puoi fare con un RS, per semplicità ti indico un DCOUNT...
    
    Private Sub Form_BeEforeUpdate(Cancel as Integer)
         Cancel=Dcount("ID","NomeTabella","Campo1Numerico=" & Me!NomeControllo1 & " AND Campo2Testo = '" & Replace(Me!NomeCOntrollo2,"'","''") & "' AND Campo3Numerico=" & Me!Controllo3)>0
         If Cancel Then
            MsgBox "Hai tentato di DUPLICARE un Record sui 3 Campi Indice"
            Me.Undo
         End If
    End Sub
  • Re: Indice univoco su più campi con valori vuoti

    Ne sai sempre una piu' del diavolo... come si dice!
    Appena mi metto al pc lo provo, grazie Alex!
  • Re: Indice univoco su più campi con valori vuoti

    Portate pazienza, sono ignorante...
    Il costrutto del Dcount l'ho capito, ma non riesco ad integrarlo in un recordset come indicatomi... mi potete cortesemente darmi un aiuto in riferimento alla tabella di cui sopra?
    Unica variante alle immagini, come consigliato da @Alex, ho tolto l'univocità aggregata dai campi Marca, Vino e Tipologia, e li ho messi tutti e tre come INDICI.
    Grazie ancora.
  • Re: Indice univoco su più campi con valori vuoti

    neobios ha scritto:


    Il costrutto del Dcount l'ho capito
    ma non come concatenare valori nulli ...

    provando con questo codice:
    Private Sub Form_BeforeUpdate(Cancel As Integer)
    Cancel = DCount("ID", "Vini", "Marca = '" & Replace(Me!txtMarca, "'", "''") & "' and Vino = '" & Replace(Me!txtVino, "'", "''") & "' and Tipologia = '" & Replace(Me!txtTipologia, "'", "''") & "'") > 0
    If Cancel Then
    MsgBox "Combinazione Marca&Vino&Tipologia già presente."
    Me.Undo
    End If
    End Sub
    Se reinserisco i tre campi compilati me li rileva come doppi, se uno dei tre è vuoto mi esce:

    Errore di Runtime '94' - Utilizzo non valido di Null
    sulla riga dell'IF

    Colpa della dichiarazione come INTEGER di Cancel? O il Dcount non vuole valori Null?

    help me...
  • Re: Indice univoco su più campi con valori vuoti

    A parte che non ho capito la logica che applichi, ma come ti ha detto +m2+ definire Null e NullString sono 2 cose estremamente differenti... e vanno gestite in modo separato, il problema avviene se il Campo Supporta entrambe...!
    Quindi se vuoi che in quella condizione a 3 il controllo sia solo su NULL sarà semplice userai una verifica di Null come
    
    NomeCampo IS NULL
    Così come sarà semplice se per te NULL e NULLSTRING rappresentassero la medesima condizione, sfruttanto il Castindel DataType si forza il Null a Nullstring ed in un solo controllo si prendono entrambi:
    
    Len(NomeCampo + '')>0
    Se invece devi discriminare il solo valore NullString, metterai un controllo di NullString, ma al contempo devi escludere il NULL... se il campo lo supporta per non avere errore:
    
    (Len(NomeCampo + '')>0 AND NomeCampo NOT IS NULL) AND Criterio2 AND Criterio3
    Prova a ragionarci con più calma...
  • Re: Indice univoco su più campi con valori vuoti

    Un'altra informazione "flash": testare l'esistenza di un record, prima di inserirlo, funziona solo in ambito monoutente, non è minimamente affidabile in ambito multiutente, a meno di non imporre un lock globale sull'intera tabella (o tabellE), cosa che non so se è fattibile con Access/JET.
    Diciamo quindi che è un approccio adatto per utilizzi "hobbystici".

    Tornando alla domanda, e supponendo di voler fare un po' di didattica sui covering indexes (dal tipo di domanda ovviamente siamo molto lontani da questi problemi, ma d'altronde è un forum, magari a qualcun altro può interessare un livello più approfondito) segnalo che nulla vieta, se proprio ti sei "amminchiato" con l'indice, di definire altri due campi (o anche in realtà uno solo, giustapposto, o tipicamente anche con un CRC32 con successivo check in caso di collisione) che mantenga le informazioni, su cui imporrai un indice univoco.
    Chiaro?
    Vabbè supponiamo che, per qualche motivo, tu voglia avere un metodo efficiente per controllare se esiste un record che contiene due, tre o K campi già inseriti, ma per qualche motivo non vuoi (o puoi) definire un "indicione" su ogni campo.
    Parimenti potresti aver interesse a considerare poniamo solo i primi J caratteri di una stringa molto lunga (campo blob, email, JSON o quello che ti pare), mantenendo però un indice di dimensioni modeste (come saprai gli indici "costano", soprattutto in fase di inserimento e modifica).

    Bene, puoi usare un campo appoggio, chiamiamolo testaduplicato, in cui metterai (all'inserimento dei campi, o mediante trigger se il tuo RDBMS lo supporta, o insomma come ti pare) le informazioni.
    Che so marca e vino? Memorizzerai qualcosa del tipo
    
    marcax;vinonero+
    marcax;vinobianco+
    marcay;vinonero+ 
    
    Poi, per verificare l'esistenza già di un record della marcax e vinobianco, porrai una selezione
    ...WHERE ... AND (testaduplicato="marcax;vinobianco+" )

    A cosa serve? Serve, perchè - ovviamente - nel mondo "vero" non memorizzerai la stringa intera, bensì (tipicamente) il suo codice CRC32 (che è un intero), sfruttando l'ottimizzatore delle query (se ce l'hai a disposizione) per imporre qualcosa del tipo (lo semplifico un poco), creando simil-indici-a-copertura a costo modesto
    ...WHERE ... AND (testaduplicato="0xEBAAD76A") AND (marca="marca") AND (vino="vinobianco" )

    La seconda porzione (i due AND aggiuntivi) considera la possibilità di una eventuale collisione CRC, anche nel caso in cui non esistano indici su marca e vino (la collisione CRC ti riporterà un numero minimo di righe, diciamo 2 o 3 nei casi peggiori, e quindi l'esistenza di indici è inutile, anzi addirittura negativa in questo caso)

    Usualmente non si utilizzano metodi più affidabili, talvolta in realtà si "taglia" una porzione (8 byte) di un codice SHA1 per rendere praticamente impossibile (=ultrararissima) un'eventuale collisione.

    Compendiando: problemi apparentemente semplici, come quello che ti poni, non sempre hanno risposte così banali come si potrebbe supporre.
    Le hanno nel caso "hobbystico", ma non in quello "professionale".

    Chiosa finale
    In pratica, se inserisco "Toso Spumante Secco" mi dice è gia' presente,
    mentre se scrivo "Toso Spumante" mi lascia inserirlo invece di dirmi che è gia' presente.
    Generalmente non è un'idea ottima quella di consentire campi NULL che verranno poi "infilati" nelle chiavi indiciate.
    Sia per i problemi che stai riscontrando, sia anche solo per motivi di performances (non faccio lo spiegone di come un campo NULL incida su un indice tipicamente ad albero).
    Versione superbreve: risparmiati un certo numero di problemi, NON consentendo questa circostanza.
  • Re: Indice univoco su più campi con valori vuoti

    +m2+ ha scritto:


    Un'altra informazione "flash": testare l'esistenza di un record, prima di inserirlo, funziona solo in ambito monoutente, non è minimamente affidabile in ambito multiutente, a meno di non imporre un lock globale sull'intera tabella (o tabellE), cosa che non so se è fattibile con Access/JET.
    Diciamo quindi che è un approccio adatto per utilizzi "hobbystici"..
    Io mi fermo alla parte "hobbistica"! non ho le competenze per approfondire, di lavoro faccio tutt'altro che il programmatore.
    In realta' però volevo una volta realizzato il progetto, renderlo appunto multiutente via lan (6 utenze al max)... mi spieghi in parole povere perchè non e' consigliabile fare la validazione sulle maschere dei vari client?

    Generalmente non è un'idea ottima quella di consentire campi NULL che verranno poi "infilati" nelle chiavi indiciate.
    Sia per i problemi che stai riscontrando, sia anche solo per motivi di performances (non faccio lo spiegone di come un campo NULL incida su un indice tipicamente ad albero).
    Versione superbreve: risparmiati un certo numero di problemi, NON consentendo questa circostanza.
    E se lo metto di default NULLSTRIG , stessa storia?
  • Re: Indice univoco su più campi con valori vuoti

    neobios ha scritto:


    In realta' però volevo una volta realizzato il progetto, renderlo appunto multiutente via lan (6 utenze al max)... mi spieghi in parole povere perchè non e' consigliabile fare la validazione sulle maschere dei vari client?
    Essenzialmente perchè l'operazione di controllo, e di scrittura, non è "immediata" (cioè eseguita senza che possa accadere altro).
    Un client impiegherà un certo tempo per controllare se una certa riga è presente nell'archivio. Se, proprio nel momento in cui sta facendo questo controllo, UN ALTRO client sta modificando l'archivio, potrebbe riportare un'informazione errata, qualora "per sfiga" le operazioni si accavallino (non siano effettivamente isolate)
    E' detto in termini molto rozzi: mentre il primo cliente "fa qualcosa", un altro "di nascosto" cambia la situazione (pensa al booking contemporaneo da parte di tanti utenti della medesima stanza d'albergo eccetera).
    Nel caso di concorrenza minima (pochissimi utenti), che non fanno praticamente nulla (nel senso informatico del termine, cioè stanno praticamente sempre fermi), allora il rischio è modesto.
    Ma, comunque, esiste.
    In questo caso, tipicamente, si opera mediante lock, cioè "lucchetti" o "blocchi" che dicono ..."NESSUNO può alterare i dati della tabella, fino a quando non lo dico io".
    Si ottiene una (rozza) serializzazione degli accessi: due client non possono modificare "a tradimento" i dati, perchè la tabella è bloccata fin quando non è rilasciata.
    Ciò, chiaramente, riduce le prestazioni complessive di gran lunga (mentre sto facendo la mia prenotazione booking blocco tutti gli altri utenti).
    Non apro lo spiegone sul perchè e percome, sintetizzando con: 6 utenti che non fanno nulla? Quasi certamente ti basta il controllo di esistenza "casareccio".
    Situazione in cui NON puoi avere questi problemi? L'approccio non va bene.

    E se lo metto di default NULLSTRIG , stessa storia?
    non so perchè ti stai "amminchiando" in questa situazione. Puoi benissimo mettere "" come default (che, come detto, è ASSAI diverso da NULL), ma ... perchè?
  • Re: Indice univoco su più campi con valori vuoti

    Grazie +m2+ della spiegazione, ho capito la situazione.

    In realtà mi stavo amminchiando su una questione leggermente diversa, esponendo l' esempio dei Vini per renderlo meno complesso, ma forse ho peggiorato la cosa..

    Ho tre componenti che messe assieme mi definiscono l'Articolo e in questo caso, ragionandoci potrei anche definire come default degli spazi vuoti della stessa larghezza del campo, ottenendo qualcosa di simile:

    articolo = "comp1_____comp3"
    nel caso di comp2 "mancante"

    e a me andrebbe bene lo stesso....

    comunque le vostre considerazioni mi sono servite a capire che non devo dare nulla per scontato e devo sempre ragionarci sopra.
Devi accedere o registrarti per scrivere nel forum
14 risposte