Newsgroup: it.comp.lang.visual-basic
Titolo: ?database relazionali

Ho un database con due tabelle Bolle e Aticoli, collegate Bolle-numerobolla
con Articoli-numerobolla.
E' possibile aprendo un recordset collegato  alla tabella Bolle eliminando i
record in essa contenuti eliminare i rispettivi collegati della tabella
Articoli?
Grazie  acoloro che avranno tempo e pazienza a dedicarmi.
Un saluto Paolo

 Articoli?
Nelle opzioni di integrità referenziale di access ci sono vari flag, tra i
quali elimina record correlati a catena ed aggiorna record correlati a
catena, se usi sqlserver, sqlbase le opzioni sono le stesse ma cambia il
modo di impostarle, personalmente conosco quasi zero sqlserver, potrei darti
una mano se il tuo provider fosse sqlbase, ma penso che questo sia pressoche
impossibile, sqlbase è tanto raro e poco usato quanto potente, forse perchè
costa una certa cifra.

 ha scritto nel messaggio
news:sfDR7.5266$3r4.2...@news1.tin.it...

secondo me dovresti aprire due recordset, uno per ogni tabella; poi,
premesso che usi le tabelle rstBolle e rstArticoli usa:
rstBolle.MoveFirst
rstArticoli.MoveFirst
While Not rstBolle.EOF
  NumBolla = rstBolla.Fields("NumBolla")
  rstArticoli.Find "NumBolla = " & NumBolla
  If Not rstArticoli.NoMatch Then
      rstArticoli.Delete
      rstArticoli.MoveFirst
  End If
  rstBolle.MoveNext
Wend

Articoli?
Su che db
sono le tue tabelle?
--------------------------------
Inviato via 
http://usenet.iol.it
 

> Articoli?
DR> Nelle opzioni di integrità referenziale di access ci sono vari flag,
Aggiungo  che  la cosa  e`  presente in  tutti  i  DB relazionali  che
implementino  le cosiddette  "regole di  integrita`  referenziale". La
cosa in gergo la si chiama "Delete Cascade".
-- 
Gian  | main(){printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Uberto|                        David Korn, 1987 ioccc best one liner 
Lauri |-------------------------------------------------------------------
(aka saint) >>Vedere X-Nospam nell'header - See X-Nospam field in Header<<

        > secondo me dovresti aprire due recordset, uno per ogni tabella;
poi,
        > premesso che usi le tabelle rstBolle e rstArticoli usa:
        >
        > rstBolle.MoveFirst
        > rstArticoli.MoveFirst
        > While Not rstBolle.EOF
        >   NumBolla = rstBolla.Fields("NumBolla")
        >   rstArticoli.Find "NumBolla = " & NumBolla
        >   If Not rstArticoli.NoMatch Then
        >       rstArticoli.Delete
        >       rstArticoli.MoveFirst
        >   End If
        >   rstBolle.MoveNext
        > Wend
Facendo così non si sfrutta affatto l'integrità referenziale del db.
Il tuo codice funziona anche se non hai messo in relazione le due tabelle
nel db.
Non che questa sia una soluzione che non funziona.
Funziona eccome, però non sfrutti affatto il motore del db.
Infatti, se imposti delle relazioni tra le due tabelle, facendo in modo che
per mantenere intatta l'integrità referenziale dell'intero db, ogni qual
volta si elimini un record da una, tutti quelli che puntano ad esso
nell'altra vengano eliminati in cascata (cascade), dal codice ti serve
soltanto eliminare il record in questione (una riga - nessun ciclo!!!). A
tutto il resto pensa il motore del db (leggi DBEngine).
Ovviamente questo procedimento va usato con la dovuta cautela, per evitare
la perdita di dati.
Per questo motivo, generalmente io sono solito mettere un doppio controllo
sull'eliminazione: appena l'utente sceglie di eliminare un dato record
appare un primo MsgBox di conferma. Nel caso l'utente risponda di essere
sicuro di voler eliminare il record in questione, dal codice vado a vedere
che le tabelle collegate non abbiano record dipendenti da quello che si
vuole eliminare. Se tale ricerca è positiva appare un nuovo MsgBox che
avverte del pericolo di eliminazioni a catena, chiedendo nuovamente conferma
delle proprie intenzioni.
Può sembrare più complicato, ma il tutto si risolve in due o tre righe di
codice, e soprattutto senza far fare cicli a VB tra i record della tabella.
L'unico ciclo che fai è tra le tabelle, per vedere quali di esse sono in
relazione con quella in cui stai operando l'eliminazione. Ed è ovvio che il
numero di elementi nel secondo caso è molto più ridotto che nel primo!
Provate a vedere l'insieme Relations dell'oggetto Database (DAO) e il suo
metodo ForeignTable.
Funziona ed è estremamente più veloce.
Gemini.

        > Nelle opzioni di integritŕ referenziale di access ci sono vari
flag,
        > tra i quali elimina record correlati a catena
        > ed aggiorna record correlati a catena
Aggiungo anche che da VB puoi indagare se il tuo record ha record collegati
in altre tabelle e visualizzare un'ulteriore richiesta di conferma
dell'eliminazione in caso affermativo.
Con riferimento a strutture DAO, ciň che voglio dire č questo:
1. L'utente sceglie di eliminare un record.
2. Appare un MsgBox di conferma: "Sei sicuro di voler eliminare il record
selezionato?"
3. Nal caso l'utente risponda SĚ, da codice si effettua la ricerca di record
collegati nelle tabelle che sono in relazione con quella da cui si sta
operando l'eliminazione.
        Public Function LinkedRecordExist(ByVal T As String, ByVal Id As
Long) As Boolean
            Dim I As Long, DB As Database, R As Recordset
            Set DB = CurrentDb
            For I = 1 To DB.Relations.Count - 1
                If DB.Relations(I).Table = T Then
                    Set R = DB.OpenRecordset(DB.Relations(I).ForeignTable,
dbOpenDynaset)
                    R.FindFirst DB.Relations(I).Fields(0).ForeignName & " =
" & Id
                    LinkedRecordExist = Not R.NoMatch
                    Exit Function
                End If
            Next I
            LinkedRecordExist = False
        End Function
4. Se la funzione restituisce True significa che l'eliminazione del record
selezionato causerŕ un'eliminazione a catena dei record collegati, perciň si
attiva un ulteriore MsgBox che avvisa dei rischi cui si va incontro in caso
di eliminazione accidentale.
Questo accorgimento ti dŕ il beneficio di sfruttare il motore del DB per le
eliminazioni a catena, ma ti mette anche al riparo da eventuali
cancellazioni accidentali, che potrebbero compromettere dei dati all'interno
del db.
Spero di essere stato sufficientemente chiaro.
Gemini.

 ha scritto nel messaggio
news:157Z29Z81Z46Y1...@usenet.iol.it...


 ha scritto nel messaggio
news:sfDR7.5266$3r4.2...@news1.tin.it...


 metodo ForeignTable.
già usato nel suddetot programma.
E se ho messo quell'esempio semplice, è proprio per questo: almeno lo
capisci subito, e se devi migliorarlo, nessuno ti impedisce di farlo, no?

        > e infatti ho voluto mettere solo la soluzione più semplice!
Se questa la chiami semplicità!!!
Far fare un ciclo while al codice alla ricerca di tutti i record che
contengono un certo valore per poi valutare l'integrità referenziale "a
mano". Considerando che i record potrebbero essere decine di migliaia e
altrettanti quelli collegati!!!
Allora che esistono a fare DAO, ADO, integrità referenziale e robaccia
simile.
Potremmo schiaffare tutto in un file testo, e ogni cosa continuerebbe a
funzionare!!!
La risposta al quesito iniziale era una e rimane una sola: INTEGRITÀ
REFERENZIALE!!!
Altrimenti tutti gli studi fatti sulle basi di dati vanno a farsi friggere.
Perché lavorare al posto del database, quando questo ha tutti gli strumenti
per farlo da solo?
        > ed è quello che ho fatto per un programmone enorme
        > per le pubbliche assistenze genovesi!!
Il programma diventa un programmone se dobbiamo scrivere del codice per
avere funzioni che il sistema ci mette già a disposizione.
È come dire che per fare un'elevazione a potenza si fa:
    Res = 1
    For I = 1 to Esponente
        Res = Res * X
    Next I
invece di
    Res = X ^ Esponente
Dal punteo di vista della correttezza non fa una grinza, ma dal punto di
vista concettuale c'è un abisso di differenza.
        > E se ho messo quell'esempio semplice,
        > è proprio per questo: almeno lo capisci subito,
        > e se devi migliorarlo, nessuno ti impedisce di farlo, no?
La semplicità del codice non sta solo nella facilità di lettura, ma
soprattutto nella semplicità concettuale dell'algoritmo che descrive.
E l'algoritmo più semplice, da che bit è bit, è quello che compie una certa
operazione nel minor tempo possibile. In tal caso semplicità = efficienza.
Ciao.
Gemini.

 Questo accorgimento ti dà il beneficio di sfruttare il motore del DB per


 per farlo da solo?
d'accordissimo su questo punto, ma quando uno ti fa una richiesta del genere
non sembra conoscere cosa cavolo sia l'integrità refernziale. Vallo a
spiegare ad un neofita di VB...

 ha scritto nel messaggio
news:9v9ovi$i7e$1...@pegasus.tiscalinet.it...


 Ti ringrazio comunque per tutto
Anche se non hai quotato (MOLTO GRAVE) io propongo un
A-P-P-L-A-U-S-O
Ciao
Davide

        > Ho provato ad utilizzare il tuo codice
        > ma non riesco a farlo funzionare.
        > aimè sono un dilettante semiprincipiante"
Probabilmente non ti funziona perché questo è un codice che avevo scritto
per il VBA di Access. Infatti ci si accorge di ciò dalla presenza
dell'oggetto CurrentDB, che invece non c'è in VB.
Innanzitutto devi impostare tutte le relazioni create in Access in modo tale
che mantengano l'integrità referenziale delle tabelle. Per fare ciò, nella
finestra Relazioni, clicca su ogni relazione creata, apri le proprietà del
Join e imposta entrambi i flag che riguardano l'integrità referenziale.
Hanno due significati diversi: uno fa in modo che cambiando il valore
collegato in una tabella, tutti quelli che a lui puntano nell'altra si
aggiornino automaticamente; l'altro riguarda la cancella zione in cascata di
tutti i record collegati a  quello che si cancella in una tabella.
Fatto ciò, scrivi il tuo codice per aprire il db (quello che avevi postato
ieri!).
In tal modo otterrai l'instanziazione dell'oggetto DataBase che ti serve per
far funzionare la mia funzione LinkedRecordExists. Praticamente devi
sostituire il tuo oggetto DataBase al mio CurrentDB, magari passandoglielo
come parametro di ingresso. La funzione diventa pressappoco così:
            Public Function LinkedRecordExist(DB as DataBase, ByVal T As
String, ByVal Id As Long) As Boolean
            Dim I As Long, R As Recordset
            For I = 1 To DB.Relations.Count - 1
                If DB.Relations(I).Table = T Then
                    Set R = DB.OpenRecordset(DB.Relations(I).ForeignTable,
dbOpenDynaset)
                    R.FindFirst DB.Relations(I).Fields(0).ForeignName & " =
" & Id
                    LinkedRecordExist = Not R.NoMatch
                    Exit Function
                End If
            Next I
            LinkedRecordExist = False
        End Function
Ovviamente quando richiami la funzione, con DB gli passerai il database che
hai aperto.
La funzione è abbastanza semplice a livello concettuale!
1. Tra tutte le relazioni del DB (ciclo FOR) cerca quella in cui è implicata
la tabella principale (parametro di ingresso stringa T).
2. Apre in un recordset temporaneo la tabella secondaria collegata ad essa
(Set R = ...)
3. Cerca se ci sono occorrenze del valore di collegamento che si sta
cancellando (passato in input con Id) nel campo collegato della tabella
secondaria (.ForeignName)
4. Restituisce il valore della ricerca come risultato della funzione.
Modifiche da fare per adattare tale codice.
Considera che per mia abitudine, in ogni tabella che creo genero una Chiave
Primaria automatica come contatore (quindi valore numerico Long)
indipendentemente dal fatto che nella tabella si possa individuare o meno un
campo che funga da Chiave Primaria (es. anagrafica -> codice fiscale, creo
ugualmente un Id numerico contatore!!!).
Questo è il presupposto per il corretto funzionamento di LinkedRecordExists.
Infatti il parametro di ingresso Id è un intero lungo. Se gli passi una
stringa, la funzione non va.
Per passargli un valore diverso di volta in volta lo devi dichiarare come
Variant, cioè ByVal Id as Variant e modificare il codice all'interno in modo
che riconosca il tipo della variabile e crei una stringa di ricerca SQL
adatta per ciascun tipo.
Devi sapere infatti che quando ricerchi un valore in SQL, questo va
delimitato in modo diverso a seconda che sia numero, stringa o data, nel
modo seguente:
Campo = 'Valore'    ->    Se è una stringa
Campo = Valore     ->    Se è un numero
Campo = #Valore# ->    Se è una data
Spero di esserti stato di aiuto.
Ciao.
Gemini.

 Campo = #Valore# ->    Se č una data


        > grazie mille per la cortesia
Assolutamente di niente! Siamo qui per questo!!!
Però devi farci una piccola cortesia anche tu.
Potresti quotare il messaggio cui rispondi???
Intendo dire includi solo le frasi cui vuoi replicare e non tutto il
messaggio.
Altrimenti i thread diventano lunghissimi da caricare.
Se ognuno aggiungesse 10 righe al messaggio precedente, alla decima risposta
le righe sarebbero 100.
Fa' anche tu come ho fatto io all'inizio di questa mia risposta: ho
riportato solo la tua affermazione cui volevo replicare, quotandola (cioè
indentandola e aggiungendo un parentesi angolare) in modo da far capire che
quella riga proviene dal messaggio precedente.
Grazie mille e... se hai bisogno... posta... quotando!!!
Gemini.

>Grazie mille e... se hai bisogno... posta... quotando!!!
Ti ringrazio ancora, scusa era un modo di fare che non conoscevo.
Adesso non mancherò di adottare questo sistema.
Ciao Paolo