Da XBase a SQL
(Raffronto fra i comand XBase e

gli equivalenti SQL

Last Modified: March 17, 1999
Ken Mayer, dBVIPS


Scopo del documento.

Questo documento serve per aiutare gli sviluppatori a passare dalla vecchia release di dBASE (dBASE/DOS, Visual dBASE 5.x, etc.) o da qualsiasi dialetto di XBase al nuovo Visual dBASE 7.x. Con questo documento si vogliono confrontare i comandi XBase con gli equivalenti Local SQL .

Tuttavia, molto importante, questo non è un suggerimento ad usare tutti i comandi equivalenti SQL nello sviluppo di applicazioni Visual dBASE . "Perchè no?", vi chiederete. Perchè molti di questi comandi restituiscono queries a sola lettura, che in molte applicazioni non servono. In alcuni casi, dovrete usare le OODML di Visual dBASE 7 (vedere X2OODML.ZIP, BEGDATA.ZIP e altri HOW TO sul sito dell'autore come pure il Tutorial Visual dBASE 7 ...).

Nota: molti comandi lavorano meglio con Visual dBASE 5.5 e 5.6, ma questo non è garantito.-- Le potenzialità  SQL del BDE sono state notevolmente aumentate nella versione 32-bit del BDE (4.5 e successive releases), per cui se utilizzerete i comandi che vedremo con Visual dBASE 5.x, potreste ottenere un messaggio di errore " Capacità non supportata".

NOTA: la mia fonte principale di informazioni è stato un buon libro su SQL: Understanding the New SQL: A Complete Guide, by Jim Melton and Alan R. Simon, Morgan Kaufmann Publishers, San Francisco, 1993, ISBN: 1-55860-245-3. Questo libro usa un approccio eccellente per insegnare SQL. (In aggiunta all'help in linea... ma se credete di spendere molto tempo per SQL, raccomando vivamente questo libro.-- Non ho esperienza di altri libri...)

Oltre al libro summenzionato, esiste l'icona  "SQL Help" nella cartella Visual dBASE -- nella quale viene discusso SQL con maggiore approfondimento rispetto a quanto discuteremo in questo documento e, cosa più importante, , viene discussa l'implementazione BDE.

Varie
I comandi SQL , come quelli XBase, non sono generalmente sensibili al maiuscolo/minuscolo. In questo documento saranno scritti in maiuscolo per differenziarli dai dati, campi ecc., ma voi potrete usarli con qualsiasi combinazione maiuscolo/minuscolo..

In questo documento userò i simboli(< e> ) attorno ad un valore. Per esempio, scrivendo: SELECT * FROM <tablename> --  se desiderate usare la tabella "FISH"  esistente nella directory degli esempi, dovrete sostituire "<tablename>" con "fish" (senza le virgolette) -- il comando finale sarà : SELECT * FROM fish

Usando tabelle Paradox , potrà essere necessario includere anche l'estensione della tabella .DB e in qualche caso l'estensione potrà essere sempre necessaria.

Quando si eseguono molti di questi comandi, non è necessario che la tabella sia aperta. Gli esempi risulteranno più chiari e molti di questi esempi sono stati fatti con le tabelle di esempio fornite con Visual dBASE 7.

Molte opzione dello statement SELECT restituiscono come risultato una query, invece di aprire una tabella come ci si aspetta. Questa  query viene aperta in dBASE come tabella temporanea ,nella forma di un alias con il nome SQL_<num. Queste tabelle non sono aggiornabili essendo a sola lettura. Per saperlo usate questo codice:

   //issue your select statement and then:
   if ( <tablename $ DBF() )
      // è aggiornabile
   else
      // è a sola lettura
   endif

La parola colonna  viene usata come sinonimo di campo di un record, mentre il termine riga viene usato come riferimento a un record di una tabella (questi termini sono standard SQL).

Se trovate una pipe (|), significa che un'opzione prevede più scelte. (per esempio: "* | <fieldlist>" significa che si può usare l'asterisco per "tutti i campi" oppure una lista specifica di campi separati dalla virgola).

Le parentesi quadre in una opzione  ([]), significano che essa non è obbligatoria ma opzionale. Questo si trova spesso con la clausola "WHERE", p.e.,

   SELECT * FROM <tablename> [WHERE <condition>]

In molti esempi, saranno usati alias BDE che rappresentano un puntatore ad un "database", e precedono la tabella (per maggiori dettagli sugli alias BDE  vedere MISCCODE.ZIP e BEGDATA.ZIP sul sito dell'autore). Come esempio, potreste manipolare la tabella "FISH" esistente nel database VDBSAMPLE . Per riferirsi a questa tabella, è necessario far precedere il nome con il riferimento al database: ":vdbsample:", p.e.,

   SELECT * FROM :vdbsample:fish

Qualche colonna di tabella potrebbe contenere come nome di campo spazi o parole riservate SQL --- in questi casi bisogna riferirsi a questi campi con il nome della tabella con un punto di separazione e con virgolette attorno al nome del campo. Esempio:

   SELECT name, fish."length cm" FROM :vdbsample:fish

Infine, per seguire queste spiegazioni non è necessario conoscere molto di SQL Visual dBASE 7, ma coloro che vogliono saperne di più troveranno vari approfondimenti. Questo documento non copre tutti gli aspetti di SQL. Lo scopo è quello di mettere a confronto i comandi XBase con quelli local SQL e fornire una base di comprensione di come lavora SQL con le tabelle locali. (Molti software 'SQL Server' come Interbase, Oracle, ed altri possiedono molti più comandi avanzati SQL, che vengono passati dal BDE a questi servers i quali provvedono a restituire un risultato. Se usate questi servers dovete fare riferimento ai manuali per maggiori dettagli.....)

Prima di partire...
Se volete tentare di fare quello che vedremo, dovrete assicurarvi  che siano aperti i due alias che vengono usati qui. Essi sono installati nella cartella "esempi" di Visual dBASE. Dalla finetra comandi digitate:

open database mugs
open database vdbsample

Dalla finestra comandi, premere quindi enter dopo ogni comando.

Potreste voler fare un back up delle tabelle esistenti nelle directories ..\VISUAL DBASE\SAMPLES e ..\VISUAL DBASE\SAMPLES\MUGS\TABLES prima di manipolare queste tabelle con il presente documento HOW TO (cancellarle, modificarle ecc.).

Se un comando è suddiviso in più linee, per scriverlo in un'unica riga bisogna togliere il punto e virgola.

Per vedere il risultato di quanto digitato,  dopo il comando SELECT visto prima, bisogna digitare : BROWSE -- per vedere la tabella in modalità standard.

Digitando uno statemente SQL SELECT , dBASE  apre  automaticamente il risultato(sia quello di una query che della tabella attualmente in uso), in una nuova area di lavoro. Questo significa che se usate molto local SQL avrete molte aree di lavoro aperte. Nel vostro codice, se si desidera ottenere qualche dato attraverso una query ottenuta con select SQL e quindi fare qualche cosa con essa,  chiudere il risultato e ritornare alla precedente area di lavoro. Si può fare con queste righe:

   cArea = alias()  // area di lavoro corrente
   SELECT * FROM whatever WHERE whateveroptions ...
   // fate ciò che dovete fare
   use              // chiude la query
   select ( cArea ) // ritorna alla precedente area di lavoro

Quando è stato fatto tutto, si può chiudere le tabelle ed i risultati delle queries digitando:

CLOSE TABLES

Infine si può digitare il comando

CLOSE DATABASES

per essere sicuri di non lasciare nulla di aperto (che sarebbe aperto la prossima volta che si attiva dBASE ...).


Equivalenza dei Comandi XBase e SQL (come implementato da BDE)

Questa sezione ha come scopo quello di confrontare i comandi XBase DML (XDML) con SQL. Ci possono essere altri comandi XDML che possono avere equivalenti in SQL, ma questi sono i soli che ho trovato.

APPEND/APPEND FROM
Aggiungere una riga alla tabella con il comando SQL INSERT .

APPEND
Sintassi SQL :

   INSERT INTO <tablename [( <column[s] )] ;
               VALUES ( <value list )

Se non si specifica la lista delle colonne, ci deve essere un valore per ogni campo ed i campi sono riempiti secondo l'ordine definito dalla struttura della tabella. (p.e., il primo valore viene posto nel primo campo ecc.)

Usando l'elenco delle colonne, si deve specificare almeno una colonna con il relativo valore. Se non viene indicata una colonna, sarà lasciata vuota empty (null - questo significa che la funzione empty() ritornerà true, mentre isblank() potrebbere non ritornare true).
 

Esempio
   // aggiunge una nuova riga alla tabella fish nel database "VDBSAMPLE" :
   INSERT INTO :vdbsample:fish ( name, species, fish."length cm" ) ;
               VALUES ("George", "Human", 10 )

Si possono visualizzare le tabelle , dopo averle aperte e si vedrà la nuova riga.

   SELECT * FROM :vdbsample:fish
   BROWSE

APPEND FROM
Sintassi SQL :

   INSERT INTO <tablename SELECT * | <fieldlist ;
          FROM <tablename [WHERE <condition]

Le colonne dello statement select devono essere le stesse della tabella nella quale si deve effettuare l'inserimento (sebbene il nome del campo non sia lo stesso, il numero di colonne, il tipo e la dimensione devono essere uguali). Usando una lista di campi, i campi devono essere gli stessi
Esempio:

   INSERT INTO :vdbsample:fish SELECT * FROM :vdbsample:fish2

Il codice sopra presuppone che abbiate fatto una copia della tabella fish della directory VDBSample ( "copy table fish to fish2" ) ... e che eventualmente siano cambiati i dati della seconda tabella.

Usando la clausola opzionale  "WHERE" (che sarà discussa più avanti) saranno aggiunte solo le righe che rispettano la condizione.


Esempio:

   INSERT INTO :vdbsample:fish SELECT * FROM :vdbsample:fish2 WHERE fish2."length cm" <= 10

COUNT
Il comando XBase DML  COUNT  viene usato per contare i records di una tabella. Si può aggiungere un qualificatore (COUNT FOR ...)e si può usare  COUNT ... TO ... per salvare il valore in una variabile di memoria.

L'equivalente SQL genera una query read-only che contiene una singola riga con un'unica colonna con il valore del numero di righe, opzionalmente può contare le righe che rispettano alcune condizioni:

Sintassi SQL :

   SELECT COUNT(*) FROM <tablename [WHERE <condition]

Esempi:

   SELECT COUNT(*) FROM :vdbsample:fish
   // oppure:
   SELECT COUNT(*) FROM :vdbsample:fish WHERE fish."length cm" <= 10

Il risultato sarà una tabella con un nome simile a "SQL_1" o "SQL_2"che può essere visualizzata con  browse che conterrà una colonna (o campo) chiamato"COUNT___" (nota -- questi sono tre caratteri underscore -- che però dipendono dal font di caratteri usato). Chiudendo le tabelle o digitando "USE" la tabella temporanea sarà chiusa ed eliminata...

Per salvare il risultato  bisogna fare cosi':

   cArea = alias()
   SELECT COUNT(*) FROM :vdbsample:fish WHERE fish."length cm" <= 10
   // salva in una variabile di memoria:
   nCount = COUNT___
   // chiude la tabella temporanea:
   use
   select (cArea)

Ci sono altri calcoli alla fine del documento.

DELETE/ZAP
Le tabelle in formato dBASE (.DBF) usano una cancellazione  "soft ". L'unico vantaggio di usarlo consiste nel fatto che i records sono lasciati nella tabella in caso in cui sia necessario riprenderli. Il XBase DML prevede questa possibilità e tutti i comandi local SQL e OODML che lavorano con .DBF lo prevedono. NOTA Questa cancellazione "soft" è prevista  solo per le tabelle .DBF mentre per le altre la cancellazione è effettiva.

L' SQL rispetta il settaggio "SET DELETED" , che determina se visualizzare o meno le righe segnate come cancellate..

Sintassi SQL :

   DELETE FROM <tablename [WHERE <condition]

ATTENZIONE: Lasciando vuota la <condition questo comando vuoterà la tabella il chè equivale a ZAP, eccetto che DELETE FROM ignora il settaggio di SET SAFETY e non vi chiede se si vuole veramente cancellare le righe della tabella...


NOTA: Come il comando ZAP , anche "DELETE FROM" richiede l'uso esclusivo della tabella. Se non siete sicuri di ottenere l'esclusiva della tabella, potete usare la seguente funzione (by Peter Rorlick, esistente nella libreria dUFLP...):
      function UseExclusive( cTableName, lInNewArea )
          local lSuccess

          // Se si desidera un'area di lavoro nuova:
          if lInNewArea
             select select()
          endif

          // apre la tabella con parametro exclusive :
          use (cTableName) exclusive

          // default:
          lSuccess = false

          // si verifica se è possibile farlo:
          try
             delete tag DummyXYZ // index tag inesistente
             // La linea sopra genera uno dei seguenti errori
             //   110: "Operation requires exclusive use of table"
             //    53: "Tag not found: DUMMYXYZ"    or
             //    35: "Table is not indexed"
          catch( exception e )
             if e.code == 53 // message = "Error: Tag not found"
                // abbiamo aperto con successi la tabella in modo esclusivo
                lSuccess = true
             endif
          endtry
          // table is now open one way or another ...
      return lSuccess
Ricordatevi di chiudere la tabella prima di eseguire il comando SQL DELETE .
Esempio:
      if UseExclusive( ":vdbsample:fish" )
         use
         DELETE FROM :vdbsample:fish WHERE name IS NULL
      else
         use
      endif


Esempi:

   // cancella righe vuote:
   DELETE FROM :vdbsample:fish WHERE name IS NULL
   
   // cancella righe specifiche:
   DELETE FROM :vdbsample:fish WHERE name = "George"

   // vuota la tabella ( da fare solo se si è fatto il back up ):
   DELETE FROM :vdbsample:fish

Un'altra annotazione: se non avete familiarità con la cancellazione "soft" delle tabelle .DBF, sappiate che i dati sono ancora presenti , ma che per riprenderli dovete usare il comando XBase RECALL (dettagli sull' help in linea). Per cancellare definitivamente le righe della tabella bisogna usare il comando XBase PACK, oppure il metodo packTable() dell'oggetto OODML database. Per visualizzare le righe cancellate, bisogna utilizzare il comando SET DELETED OFF, oppure settare, nella casella di dialogo Proprietà, questa opzione. Per non vedere le righe, SET DELETED ON (valore di default di Visual dBASE 7.x).

DELETE TABLE
Il comando Xbase DML DELETE TABLE viene utilizzato per cancellare una tabella e tutti i suoi files associati (.MDX, .DBT nel caso di.DBF, in caso di tabella.DB, tutta la miriade di files che può creare).

Il comando SQL per questo è DROP TABLE.

Sintassi SQL:

   DROP TABLE <tablename

Esempio (fare questo solo se si è fatto un back up della tabella...):

   DROP TABLE :vdbsample:fish

DELETE TAG
Il comando Xbase DML DELETE TAG viene utilizzato per cancellare un tag indice da una tabella.

Il comando SQL per questo è DROP INDEX.

NOTA: Se si cancellano tutti gli indici tags, il file .MDX sarà automaticamente cancellato..

Sintassi SQL:

   DROP INDEX <tablename.<indexname | PRIMARY

Notare che la parola "PRIMARY" viene utilizzata per tabelle .DB con indice primario al posto del <indexname> visto sopra (Le tabelle in formato .DB possono creare una chiave primaria senza il nome di un indice per cui questa parola è vitale). Per le tabelle DBF con indice primario, usare il nome dell'indice...

Esempi:

  // per un .DBF:
  DROP INDEX :vdbsample:fish.species

  // oppure per un.DB (questo è un esempio
  // poichè la tabella non esiste avrete un errore
   DROP INDEX "customer.db".PRIMARY

INDEX
Il comando Xbase DML INDEX, con varie opzioni, viene utilizzato per creare indici per le tabelle. Viene utilizzato anche per creare sia files .NDX che tags .MDX con tabelle.DBF

Il comando SQL per questo è CREATE INDEX. Con tabelle .DBF il comando crea tags.MDX, ma non files .NDX -- non esistono opzioni per fare questo.

Sintassi SQL:

   CREATE INDEX <indexname ON <tablename ;
                (<column1 [, <column2 ...] )

Ci sono seri inconvenienti se si usano espressioni per gli indici – in SQL non si possono usare. Si possono creare indici su colonne multiple, ma non con espressioni.

Inoltre, non potete creare indici PRIMARY con questo comando -- la sola via per creare indici PRIMARY usando SQL è con il comando CREATE TABLE (p.e., quando si crea la tabella originariamente) e, per quello che so io, solo con tabelle Paradox.

Esempi:

   CREATE INDEX name2 ON :vdbsample:fish ( name )
   CREATE INDEX namespecies ON :vdbsample:fish ( name, species )

REPLACE
Il comando REPLACE rappresenta il metodo di XBase DML per assegnare valori, a mezzo del programma, ai campi oppure, usando l'opzione "ALL", vengono sostituiti i dati di uno o più campi in tutte le righe della tabella.

Sintassi SQL:

   UPDATE <tablename ;
      SET <fieldname=<somevalue [, <fieldname2=<someothervalue ...] ;
      [ WHERE <somecondition ]

IL "SET" indica il campo o i campi da sostituire , separati dalla virgola , e <somevalue> indica il nuovo valore del campo dopo che è stato aggiornata la tabella.

Esempi:

Per esempio può essere necessario sostituire un campo logico in tutte le righe del rowset con "false":

   UPDATE MyTable SET myLogicalField = false

Nota: Nelle mie prove questa procedura risulta più veloce del comando XBase REPLACE ALL, e sostanzialmente più veloce del metodo OODML (che richiede di processare una tabella riga per riga e memorizzare il nuovo valore in ogni riga).

Se è necessario usare una condizione, come un campo basato su qualche valore:

   d = date()
   UPDATE MyTable SET myLogicalField = false;
          WHERE myDateField <= :d

SET FIELDS
Il comando XBase DML SET FIELDS viene utilizzato per limitare la visualizzazione o l'accesso ai campi di una tabella.

Nella versione SQL , si usa l'elenco dei campi in sostituzione della wildcard. In aggiunta si possono creare campi calcolati "al volo"… vedere USE più avanti.

SET FILTER
Lo statement XBase DML SET FILTER serve per filtrare i dati di una tabella.

In SQL si usano le clausole opzionali WHERE o HAVING già viste in molti altri comandi. La clausola WHERE è molto più veloce del filtro XBase.

Gli operatori sono importanti e non sempre uguali fra XDML e SQL:

Xbase

SQL

and/.and.

And

or/.or. 

or 

not/.not.

Not

=

=

==

=

=>/>=

>=

=</<=

<=

#/<>

<>

empty()/isBlank()

Is null

not empty/not isBlank()

Is not null

string1+string2
(concatenation of strings)

String1 || string2

Da notare che la sequenza minore e maggiore combinata con il segno uguale è molto importante in SQL (in altre parole, >= è corretto, => non lo è).

Si possono inserire più condizioni combinando gli operatori and e/o or come in XBase.

La clausola Where è un filtro standard ed è usata come sotto indicato. La clausola Having viene usata con calcoli aggregati (campi calcolati) quando questi campi hanno un determinato valore. La clausola Having può essere usata solo quando ci sono campi calcolati ed è presente anche la clausola Group By.

Sintassi SQL – clausola Where:

   SELECT * | <fieldlist FROM <tablename WHERE ;
              <condition [ORDER BY <fieldname(s)]

Esempio:

   SELECT * FROM :vdbsamples:fish WHERE fish."length cm" <= 10

Sintassi SQL – clausola Having:

   SELECT <fieldlist, <CalculatedField(s) FROM <tablename ;
          GROUP BY <fieldname(s) ;
          HAVING ( <condition ) [ORDER BY <fieldname(s)]

Esempio:

   SELECT lineitem."invoice id", sum( qty ) AS totalqty FROM :mugs:lineitem ;
          GROUP BY lineitem."invoice id" ;
          HAVING ( sum(qty) <= 3 )

Le due clausole WHERE e HAVING possono essere combinate... In più (dal Local SQL Help): "La clausola HAVING filtra i dati dopo l'aggregazione ottenuta con GROUP BY. Per filtri basati su valori di righe prima della aggregazione, usare la clauola WHERE."

Opzioni Speciali -- "$" -- Item List
L'operatore "$" di XBase, viene utilizzato per vedere se una stringa è contenuta in una lista di stringhe (o in una singola stringa -- vedere sotto). In SQL, questo viene fatto con la clausola "IN":

Sintassi SQL:

   SELECT * | <fieldlist FROM <tablename WHERE ;
              <fieldname IN ( <item1, <item2 ... )

Esempio:

   SELECT * FROM :mugs:customer WHERE customer."state id" IN ("CA", "NY" )

Da notare che il risultato della query può essere soggetto a editazione ...

Opzioni Speciali -- "$" -- String1 In String2
Questa opzione è differente dalla precedente in quanto andiamo a confrontare una singola stringa. In XBase, si può controllare se una stringa è contenuta in un'altra (es."somestring" $ fieldname).

In SQL occorre un pò più di lavoro ma si può fare ugualmente con i caratteri jolli. Il rowset risultante può esere a sola lettura. (NOTA: SQL è sensibile alle maiuscole/minuscole...)

Sintassi SQL:

   SELECT * | <fieldlist FROM <tablename WHERE ;
              <fieldname LIKE "string-with-wildcard(s)"

I due caratteri jolly sono "%" e "_" (percento e sottolineatura).

Se si ha familiarità con i caratteri jolly del DOS, il percento è uguale all'asterisco (*), mentre la sottolineatura lavora nello stesso modo del punto interrogativo (?).

Esempi:

   // restituisce ogni riga che contiene, nel campo name, la lettera 'à 
   SELECT * FROM :vdbsample:fish WHERE name LIKE "%a%"
    
   // restituisce ogni riga che inizia, nel campo name, con la lettera 'B'
   SELECT * FROM :vdbsample:fish WHERE name LIKE "B%"

   // restituisce ogni riga il cui campo nome finisce con "fish"
   SELECT * FROM :vdbsample:fish WHERE name LIKE "%fish"

   // Restituisce la riga il cui nome inizia con due caratteri qualsiasi, e quindi
   // ha i caratteri 'uè e dopo qualsiasi altro carattere...
   SELECT * FROM :vdbsample:fish WHERE name LIKE "__ue%"

Usando questa combinazioni di caratteri si ottiene tutto quanto si vuole... vedere anche più avanti quando si discute delle funzioni di stringa -- si possono usare le funzioni di stringa per rendere le ricerche non sensibili al maiuscolo/minuscolo...

SET INDEX/SET ORDER
I due comandi XBase DML SET INDEX e SET ORDER, hanno un utilizzo simile. Tuttavia , mentre SET INDEX può aprire un file .NDX, SQL non lo fa per niente e , francamente, non so come si possa fare.

Usare un indice con SQL è molto semplice, ma si deve bypassare i tags indice e dire semplicemente a dBASE in quale ordine si vogliono i dati

Sintassi SQL:

  SELECT * | <fieldlist FROM <tablename ;
            ORDER BY <fieldname [,<fieldname ...] [ASC|DESC]

Da notare che si possono selezionare più campi e ci si può riferire anche a campi calcolati. (vedere sotto).

Gli operatori "ASC" e "DESC" sono opzionali -- per default la tabella viene ordinata in maniera ascendente (ASC), ma si può anche ordinare in maniera discendente (aggiungendo "DESC" alla fine della clausole ORDER BY oppurer alla fine della referenza al singolo campo). Interessante è l'utilizzo della combinazione di campi ascendenti e discendenti in un unico comando SQL.

Se è presente un tag indice, si può usare il nome del tag anzichè il nome del campo. Se l'indice tag ha lo stesso nome del campo, dBASE userà l'indice tag.

Esempi:

   // ordina la tabella customer in base a last name:
   SELECT * FROM :mugs:customer ORDER BY customer."last name"

   // ordina la tabella customer in base a last name ma in maniera discendente
   SELECT * FROM :mugs:customer ORDER BY customer."last name" DESC

   // non sensibile a maiuscolo/minuscolo
   SELECT * FROM :mugs:customer ORDER BY UPPER( customer."last name" )

   // campi multipli (descendente state_id, ascendente last name):
   SELECT * FROM :mugs:customer ORDER BY customer."state id" DESC, customer."last name" ASC

   // campi calcolati:
   SELECT customer."last name" || ', ' || customer."first name" AS fullname, ;
          street1, street2 FROM :mugs:customer ORDER BY fullname

Con i campi calcolati non è possibile usare i caratteri jolly ed il rowset sarà "a sola lettura" a causa del campo calcolato.

SET RELATION
Con XBase DML lo statement SET RELATION determina le relazioni tra tabelle.

Anche SQL può mettere in relazione le tabelle, ma si avrà, con le tabelle locali, un rowset a sola lettura. È un poco complesso. Si deve usare la clausola SQL JOIN per relazionare le tabelle con altre opzioni (INNER JOIN, OUTER JOIN ...).

Questo modo di operare ha un senso solo quando si creano reports in Visual dBASE 7 (dato che il risultato della query sarebbe sempre a solo lettura -- i reports non scrivono, generalmente, sulle tabella). Dato che, nei reports, la gestione di più tabelle (padre/figlio o tabella principale con una o più tabelle di dettaglio) risulta un pò difficoltosa, l'utilizzo della SQL JOIN può aver senso.

Per tutte le form che utilizzano tabelle multiple, si usano gli oggetti dati OODML (vedere X2OODML.ZIP, BEGDATA.ZIP ed altri documenti HOW TO sul sito dell'autore).

Se si deve usare la Joins SQL, consiglio (ed è l'unica volta che lo faccio) di usare il Designer SQL e quindi modificare l'output SQL per semplificarlo . Il Designer SQL crea un codice lungo non sempre necessario

Un esempio di una outer join usata con tre tabelle -- una principale e due di dettaglio (non tentare di fare questo fino a quando non si abbiano le tabelle con questi nomi e campi.):

   SELECT * FROM "testprim.dbf" Testprim ;
      FULL OUTER JOIN "testdet1.dbf" Testdet1 ;
      ON  (Testprim.LinkField = Testdet1.LinkField)  ;
      FULL OUTER JOIN "testdet2.dbf" Testdet2 ;
      ON  (Testprim.LinkField = Testdet2.LinkField )

Le tabelle sono unite attraverso un campo chiamato "LinkField", la tabella principale (genitore) si chiama "TestPrim" mentre le altre tabelle sono "TestDet1" e "TestDet2" per i dettagli 1 e dettagli 2

TOTAL
I comando XBase DML TOTAL crea una nuova tabella contenente il totale dei campi numerici derivanti dalla tabella sulla quale si deve effettuare la totalizzazione

Vedere più avanti le funzioni di calcolo e aggregate. Il comando SQL fornisce risultati simili..

USE
Per aprire una tabella con XBASE DML si deve usare il comando "USE". La stessa cosa avviene con lo statement SELECT di SQL. Questo comando deve essere conosciuto per usare in maniera appropriata Visual dBASE 7 e OODML.

Sintassi SQL:

   SELECT * | <fieldlist FROM <tablename ;
        [ORDER BY <fieldname [, <fieldname ...]] ;
        [WHERE <condition] ;
        [HAVING (<condition)] ;
        [GROUP BY <fieldlist] ;
        [SAVE TO <tablename]

L'asterisco "*" è il carattere jolly per indicare tutti i campi.

Invece di selezionare tutti i campi, si può limitarne alcuni indicandoli uno per uno con il nome e separandoli con la virgola.

Esempi:

   SELECT * FROM :vdbsample:fish
   SELECT name, species FROM :vdbsample:fish

Se il nome di un campo è uguale ad una parola riservata SQL, oppure il nome del campo contiene spazi, è necessario far precedere il nome della tabella, un punto ed inserire il nome del campo tra virgolette, es.,:

   SELECT name, fish."length cm" FROM :vdbsample:fish

Campi Calcolati
Si possono creare campi calcolati ma in questo caso il risultato sarà una tabella a sola lettura. In più non è possibile usare il carattere jolly "*" per indicare "tutti i campi"..

Sintassi SQL:

   SELECT <fieldlist, <calculation AS <calcfieldname FROM <tablename

Con il seguente esempio, viene moltiplicato per 10 ogni singolo valore del campo qty della tabella lineitem dell'esempio Mugs

   SELECT qty, qty*10 AS ordertotal FROM :mugs:lineitem

Ci sono altri calcoli discussi più avanti...

NOTA: Non si può usare la wildcard con i campi calcolati (es., non si può usare "*, calcfield").

Save To
È possibile salvare il risultato di una query in un'altra tabella usando la clausola opzionale SAVE TO .Ciò può essere utile con le JOIN ed altre SELECT complesse.

Esempio:

   SELECT lineitem."invoice id", qty, qty*10 AS ordertotal FROM :mugs:lineitem ;
          SAVE TO ordertotals

NOTA: Il salvataggio avviene nella directory corrente, a meno che non sia stato inserito l'Alias BDE .

La tabella risultante può essere aperta ed aggiornata, ma la tabella (o le tabelle) originali che l'hanno generata non possono essere aggiornate..

Altre Opzioni
Esistono altre opzioni SQL che possono essere combinate in un singolo statement SELECT. Costruirli cone uno statement può trarre in inganno, ma è possibile fare quancosa di complesso con un’unico comando SQL.

ZAP
Vedere il comando "DELETE" trattato precedentemente su questo documento.


Miscellanea di opzioni SQL...

Unique Rows in una tabella
Se si vogliono selezionare tutte le righe uniche di una tabella, con Xbase si doveva definire un tag indice con l'operatore UNIQUE.

In SQL è molto più semplice e facile...

Sintassi SQL:

   SELECT DISTINCT <fieldname [, <fieldname ...] FROM <tablename

Problema: non è possibile selezionare ogni campo ad esclusione di quelli che sono marcati come "unici". Nella SELECT si possono usare più campi ma l'operatore DISTINCT troverà una combinazione dei valori unici per tutti i campi listati

Esempio:

  // Ricerca di tutte le righe uniche basate sul campo
  // last names della tabella customers:
  SELECT DISTINCT customer."last name" FROM :mugs:customer

Tuttavia, usando le subquery, si possono ottenere tutti i campi (colonne) della tabella customer nella quale è stato trovato il valore unico:

   SELECT * FROM :mugs:customer WHERE customer."last name" IN ;
      (SELECT DISTINCT customer."last name" FROM :mugs:customer) ;
      ORDER BY customer."last name"

Sum/Group By
Si può volere il totale di un campo in una tabella. Automaticamente viene creata una singola riga e colonna in una tabella a sola lettura. Si possono anche raggruppare i totali in base ad altri campi -- questo viene fatto per creare il totale di tutte le righe del campo raggruppato. Anche in questo caso il rowset è a sola lettura.

Sintassi SQL:

   SELECT SUM( <fieldname ) FROM <tablename
      OR
   SELECT <fieldlist, SUM( <fieldname ) FROM <tablename ;
              GROUP BY <fieldname

Viene creato il campo: SUM OF <fieldname > dove fieldname è il campo dal quale sono estratti i dati della somma.

Esempio (viene usata la tabella lineitem del database MUGS):

   // totale del campo qty... -- una riga, un campo
   SELECT SUM( qty ) FROM :mugs:lineitem

   // restituisce il totale per ogni invoice:
   SELECT lineitem."invoice id", SUM( qty ) FROM :mugs:lineitem GROUP BY lineitem."invoice id"

   // restituisce il totale per ogni item:
   SELECT lineitem."item id", SUM( qty ) FROM :mugs:lineitem GROUP BY lineitem."item id"

Altri Calcoli
In SQL è sufficiente aggiungere i seguenti comandi allo statement SELECT

Esempi...

MAX()
Sintassi SQL:

   SELECT MAX( <fieldname> ) FROM <tablename

Restituisce il valore massimo del campo in questione. Il nuovo campo si chiama: MAX OF <fieldname> dove <fieldname> è il campo dal quale provengono i dati

Esempio:

   SELECT MAX( fish."length cm" ) FROM :vdbsample:fish

Per ottenere tutti i campi della riga che interessa ( e se si hanno più righe con lo stesso valore) si usa la subquery (come visto precedentemente):

   SELECT * FROM :vdbsample:fish WHERE fish."length cm" = ;
          ( SELECT MAX( fish."length cm" ) FROM :vdbsample:fish )

MIN()
Sintassi SQL:

   SELECT MIN( <fieldname ) FROM <tablename

Restituisce il valore minimo del campo in questione. Il nuovo campo si chiama: MIN OF <fieldname> dove <fieldname> è il campo dal quale provengono i dati

Esempio:

   SELECT MIN( fish."length cm" ) FROM :vdbsample:fish

Per ottenere tutti i campi della riga che interessa ( e se si hanno più righe con lo stesso valore) si usa la subquery (come visto precedentemente):

   SELECT * FROM :vdbsample:fish WHERE fish."length cm" = ;
          ( SELECT MIN( fish."length cm" ) FROM :vdbsample:fish )

AVG()
Sintassi SQL:

   SELECT AVG( <fieldname ) FROM <tablename

Restituisce la media del campo in questione. Il nuovo campo si chiama: AVG OF <fieldname> dove <fieldname> è il campo dal quale provengono i dati.

Esempio:

   SELECT AVG( fish."length cm" ) FROM :vdbsample:fish

COUNT()
COUNT è stato discusso in precedenza.

Subqueries
Con le Subqueries si possono limitare i dati restituiti da una query confrontando i valori con un'altra tabella (o nella stessa -- vedere i calcoli precedenti).

Sintassi SQL:

   SELECT * | <fieldlist FROM <tablename WHERE (<subquery)

La subquery sarà un altro statement SQL Select.

Con le subquery si possono usare operatori speciali come "EXISTS" per verificare se il valore di una subquery è presente nella query principale creata con lo statement SELECT.

Esempio (nota si usa ancora il database MUGS):

   SELECT * FROM :mugs:customer WHERE EXISTS ;
       (SELECT * FROM :mugs:invoice WHERE invoice."customer id" = customer."customer id" )

Non vengono restituiti i dati della tabella Invoice, ma solo quelli della tabella customer che hanno il campo "customer id" uguale a quello della tabella invoice. Se un cliente non ha corrispondenza nella tabella invoices, non apparirà nel set risultante.

Tabelle Multiple
In aggiunta a quando detto sulle JOIN nella precedente sezione "SET RELATION" è possibile aprire più tabelle in una singola query. Il risultato sarà a sola lettura ed in qualche caso produce strani risultati

Sintassi SQL:

   SELECT * | <fieldlist FROM <tablename1, ;
          FROM <tablename2

       or

   SELECT <tablename1.<field, <tablename2.<field FROM;
          <tablename1, <tablename2
    
       or

   SELECT <alias1.<field, <alias2.<field FROM;
          <tablename1 <alias1, <tablename2 <alias2

L'ultimo statement mostra la sintassi quando si usano molti campi di tabelle differenti-- si assegna un alias alla tabella scrivendo ( dopo la clausola FROM) il nome della tabella seguito da uno spazio e quindi il nome dell' alias

Esempi:

   SELECT * FROM :vdbsample:fish, :vdbsample:sample

Se si effettua il browse, si vede che per ogni record in FISH c'e un record di SAMPLE. Questo può avere qualche strano risultato...

   SELECT fish.name, sample.sample FROM :vdbsample:fish, :vdbsample:sample

Si ottiene lo stesso risultato visto prima solo che vengono visualizzati solo due campi, uno per tabella...

   SELECT a.name, b.sample FROM :vdbsample:fish a, :vdbsample:sample b

Stesso risultato con l'uso di alias. L'alias può avere più di un carattere come ad esempio "TableA" e "TableB".).

Creazione di Tabelle
Una delle cose più interessenti è quella di creare o modificare tabelle locali "al volo".

Per creare una tabella usare il comando SQL CREATE TABLE:

Sintassi SQL:

   CREATE TABLE <tablename ( <fieldname <type(<size) ... )

I tipo SQL sono diversi a seconda di tabelle SQL o .DBF o altre (es. Paradox .DB):

Tabelle SQL e .DBF

SQL

.DBF

SMALLINT

Long

INTEGER

Long

DECIMAL(X,Y)

Numeric(X,Y)

NUMERIC(X,Y)

Numeric(X,Y)

FLOAT(X,Y)

Double

CHAR(X)

Character(X)

VARCHAR(X)

Character(X)

DATE

Date

BOOLEAN

Logical

BLOB(x,1)

Memo

BLOB(x,2)

Binary

BLOB(x,4)

OLE

TIMESTAMP

TimeStamp

MONEY

Numeric(20,4)

AUTOINC

Autoincrement

SQL e tabelle .DB

SQL

.DB

SMALLINT

Short

INTEGER

Long

DECIMAL(X,Y)

BCD

NUMERIC(X,Y)

Number

FLOAT(X,Y)

Number

CHAR(X)

Alpha

VARCHAR(X)

Alpha

DATE

Date

BOOLEAN

Logical

BLOB(x,1)

Memo

BLOB(x,2)

Binary

BLOB(x,3)

Formatted Memo

BLOB(x,4)

OLE

BLOB(x,5)

Graphic

TIME

Time

TIMESTAMP

TimeStamp

MONEY

Money

AUTOINC

Autoincrement

BYTES(x)

Bytes

Per creare un indice primario nelle tabelle.DB, si deve aggiungere alla fine del comando CREATE TABLE:

PRIMARY( <keyfield ), e il campo chiave deve essere il primo della tabella!

Esempio:

   CREATE TABLE TEST (;
          "First Name" Char( 20 );
          "Last Name"  Char( 20 );
          "Birthdate"  Date ;
          "Notes"      Blob( 10, 1 ) )

(L'ultimo campo è memo.)

Modifica della struttura delle Tabelle
Oltre che la creazione di tabelle, è possibile modificare le tabelle aggiungendo o cancellando colonne (campi).

Sintassi SQL:

   ALTER TABLE <tablename ;
      ADD <fieldname(<type) | DROP <fieldname ;
      [ ADD <fieldname(<type) | DROP <fieldname ... ]

I comandi add/drop possono essere mescolati nello stesso statement SQL. Per l'indicazione del tipo vedere sopra.

Per le tabelle .DB esiste un problema con i campi Autoincrement che possono essere creati in una nuova tabella ma non possono essere aggiunti ad una tabella gia esistente. Questa limitazione non esiste con le tabelle .DBF

Formati Date
SQL prevede le date in formato U.S. mese/giorno/anno ( con 2 o 4 caratteri). Per evitare errate interpretazioni inserirle fra virgolette nel seguente modo "1/23/1998" per evitare che vengano interpretate come 1 diviso 28 diviso 1998

Il carattere 0(zero) per il mese e il giorno è opzionale.

Il settaggio della variabile FOURDIGITYEAR in BDE controlla il secolo. Se FOURDIGITYEAR è posto a FALSE e l'anno viene specificato con due soli caratteri, gli anni inferiori a 49 avranno il prefisso 20 (es., 2049) mentre quelli superiori a 50 il prefisso 19. (È molto meglio usare il settaggio SET EPOCH posto a 1950, con il comando standard dBASE...) Per usare una data al di fuori di questi limiti, utilizzare 4 caratteri per l'indicazione di anno.

Per paesi diversi dagli USA comportarsi nel seguente modo...:

       q.sql = [select * from 'mytable.dbf' where datum = '17.01.1999']
       q.sql = [select * from 'mytable.dbf' where datum = '01/17/1999']

 

Il tipo di separatore dice a SQL quale tipo di data aspettarsi. Con il punto i valori alla sinistra del primo punto rappresentano i giorni del mese ed i caratteri fra il primo ed il secondo punto sono il mese mentre con il separatore "/" i caratteri a sinistra sono il mese seguito dal giorno. In ogni caso i dati dopo il secondo separatore rappresentano l'anno che può essere di 2 o 4 cifre.).

Thanks to Ivar B. Jessen for detailing this out and hopefully shedding a bit more light on the subject ...

Funzioni Stringa
Queste funzioni sono usate con la clausole WHERE, lista dei campi, clausola, ORDER BY ecc...

UPPER(), LOWER()
Lavorano esattamente come le corrispondenti funzioni XDML/dBASE per convertire in maiuscolo/minuscolo...

TRIM()
La funzione TRIM() è un poco diversa rispetto alla versione dBASE ed ha qualche parametro:

Sintassi SQL:

   TRIM( <whattotrim ["<c"] FROM <fieldname )

La parte <whattotrim può essere una delle seguenti:

LEADING

Caratteri all'inizio del campo

TRAILING

Caratteri alla fine del campo

BOTH

Caratteri all'inizio ed alla fine del campo

Il carattere per default da eliminare è lo spazio, ma come si vede dalla sintassi, può essere eliminato un qualsiasi carattere. Con il seguente esempio si tolgono da un campo gli asterischi alla sinistra di un numero

   SELECT TRIM( LEADING "*" FROM MyField ), NAME, otherfields FROM MyTable

La funzione TRIM()restituisce un set a sola lettura.

SUBSTRING()
Simile alla funzione dBASE SUBSTR() solo che in SQL l' indicazione della fine della stringa non è opzionale.

Sintassi SQL:

  SUBSTRING( <fieldname FROM <nStart FOR <nEnd )

Per avere i primi tre caratteri del campo "NAME" usare:

  // Restituisce due colonne , la prima con il campo name,
  // la successiva con i primi 3 caratteri del campo name
  // la seconda colonna si chiama: "name substring 1"
  SELECT name, SUBSTRING( name FROM 1 FOR 3 ) from :vdbsample:fish

Anche questa è a sola lettura, poichè abbiamo calcolato un campo

Funzioni di Date
Le funzioni dBASE erano day(), month(), year() e molte altre che venivano usate sia per i campi che per altri valori di date.

In SQL si usa la funzione EXTRACT() con qualche opzione specifica.

Sintassi SQL:

   EXTRACT( <part FROM <fieldname )

Dove <part è una delle seguenti parole : YEAR, MONTH, DAY, HOUR, MINUTE, SECOND.

Esempio:

   // Retsituisce il campo 'customer id' field, e un secondo campo
   // chiamato: "EXTRACT DAY FROM order date"
   SELECT invoice."customer id", EXTRACT( DAY FROM invoice."order date" ) FROM :mugs:invoice

Anche questa è a sola lettura, poichè abbiamo calcolato un campo

Funzione CAST
Funzione che non ha l'equivalenza in dBASE XML (anche se VdBASE 7.x può cambiare qualche tipo di campo).

La funzione CAST viene utilizzata per convertire i valori di uno specifico campo in dati di tipo specificato. Può essere applicato a valori letterali o calcolati, può essere usato nelle clausole WHERE, nell'elenco di colonne di SELECT o come parte di uno statement UPDATE.

Sintassi SQL:

    CAST( <fieldname AS <datatype )

Il parametro datatype deve essere un tipo standard usato dall' SQL locale (CHAR, INTEGER, NUMERIC, ecc.). Non si può usare invece con i campi BLOB, MEMO o BYTEs.

La conversione con CAST consente l'uso di altre funzioni , che altrimenti sarebbero incompatibili, come la funzione SUBSTRING con un campo DATE.

L'effetto della trasformazione con CAST è temporaneo e non influisce sui dati memorizzati,. Per renderlo effettivo si deve applicare lo statement UPDATE.

Sostituzione di Variabili

Risulta utile inserire nello statement SQL Select delle variabili

Le possibilità sono due Esempio:

   cVar = "Blue Angelfish"
   SELECT * FROM :vdbsample:fish WHERE name = :cVar

Una seconda possibilita è quella di 'usare le virgolette attorno alle variabili (per stringhe o per date):

   cVar = "Blue Angelfish"
   SELECT * FROM :vdbsample:fish WHERE name = "&cVar."

La ragione della macro (vedere & sull'help in linea) è che local SQL si aspetta uno statement SQL valido e non può valutare da solo la variabile dBASE (inserendo la macro si obbliga dBASE a valutarla prima di passarlo a SQL).

Per le date , e meglio usare i parametri che danno meno problemi.

Nell'esempio sopra, si possono aggiungere caratteri jolly e usare la clausola LIKE, anzichè l’operatore "=".

NOTA: Per assegnare una Select alla proprietà sql di un oggetto query si pongono i valori nel seguente modo:

 
   cVar     = "Blue Angelfish"
   q        = new query()
   q.sql    = [SELECT * FROM :vdbsample:fish WHERE name = "]+cVar+["]
   q.active := true

   // Oppure -- non usare una combinazione dei due!!
   q        = new query()
   q.sql    = [SELECT * FROM :vdbsample:fish WHERE name = :cVar]
   q.params[ "cVar" ] = "Blue Angelfish"
   q.active := true

Le parentesi quadre sono usate per delimitare e per rendere più leggibile il codice.

Dalla finestra Comandi si può digitare:

   cVar = 10
   SELECT * FROM :vdbsample:fish WHERE fish."length cm" = :cVar

Date
SQL riconosce le date come stringa di caratteri.

Un Esempio:

   SELECT * FROM :mugs:invoice WHERE invoice."order date" <= "12/15/1997"

Vedere la sezione delle date.

Logici
Usare le parole "true" o "false"...

   SELECT * FROM mytable WHERE mylogical = TRUE


Usare SQL con OODML

La ragione principale per conoscere SQL di Visual dBASE 7 è che può essere usato con gli oggetti dati, altrimenti chiamati OODML (Object Oriented Data Manipulation Language).

Quanto visto sinora può essere usato spesso, tuttavia se SQL produce un set a sola lettura, bisogna passare a OODML.

Proprietà SQL degli oggetti Query
La prima cosa che viene vista da chi programma in dBase, sono gli oggetti dati e come si apre o si accede ad una tabella.

Nella definizione più semplice, l'oggetto query deve avere almeno 3 statement che devono rispettare la seguente sequenza

   queryName = new Query() // crea un'istanza della  query
   queryName.sql = "some SQL statement" // select sql 
   queryName.active = true // ativa l'oggetto query object

Maggiori dettagli sono forniti in X2OODML.ZIP sul sito web...

Si può usare la clausola WHERE oppure usare la proprietà filter dell'oggetto rowset (che viene creato quando la query viene attivata).

Si può decidere di usare la clausola WHERE , e successivamente la proprietà filter per qualcos’altro...

La clausola WHERE in un oggetto query deve avere delimitatori. Poichè anche lo statement SQL è una stringa, bisogna usare delimitatori annidati che sono difficili da leggere.

   queryName.sql = "select * from customer where lastname = 'Jones'"

      // molto più leggibile è la seguente:

   queryName.sql = [select * from customer where lastname = 'Jones']

Usando variabili o valori letterali cambia la sintassi...

   cName = "Jones"
   queryName.sql = [select * from customer where lastname = "]+cName+["]

Osservare le virgolette all'interno della stringa.

Anche i valori data richiedono delimitatori.

Per valori logici e numerici NON sono necessarie le virgolette...

   nAge = 21
   queryName.sql = [select * from customer where CustAge  ]+nAge

   // oppure

   bUpdated = false
   queryName.sql = [select * from customer where Updated = ]+bUpdated

Filtri
La proprietà filtro serve a filtrare i dati del rowset. Il filtro non può essere un'espressione dBASE ma una espressione sql come abbiamo visto prima (es. usando la clausola WHERE).

Tuttavia, lo statement SQL SELECT riconosce tutte le opzioni LIKE della clausola WHERE consentendo una grande flessibilità. Queste opzioni non sono consentite con la proprietà filter

Riprendendo l'esempio visto sopra

   queryName = new query()
   queryName.sql = "select * from customer"
   queryName.active = true

   // somewhere in your code:
   nAge = 21
   queryName.rowset.filter = "CustAge  "+nAge

(Si possono usare molti metodi nel rowset (es. findKey() method) per dettagli vedere X2OODML.ZIP e BEGDATA.ZIP sul sito web).

Indicizzazione/Ordinamento dei dati
Con la clausola ORDER BY , si ordina in base ad un solo campo e si ottiene una query read-only.

In alternativa, si usa un tag indice della tabella e la proprietà indexName del rowset:

   queryName = new query()
   queryName.sql = "select * from customer"
   queryName.active = true
   // può essere fatto anche dopo l'attivazione della query:
   queryName.rowset.indexName = "someindexTag"

Joins
Con le Joins si creano tabelle tabelle "virtuali" combinando più tabelle ed ottenendo query read-only.

Per le relazioni fra tabelle principale/dettaglio o padre/figlio, è megio usare le proprietà masterRowset/masterFields del rowset, mentre se si usano tabelle non locali (.DBF or .DB), è meglio usare la proprietà masterSource.

La sola ragione per usare una join con OODML è con i report (vedere BEGREP.ZIP,BEGDATA.ZIP e X2OODML.ZIP )

Altri dettagli
Per tutto quello che non è stato discusso in questo documento, fare riferimento all'help in linea o ai newsgroups .


IL Designer SQL

In Visual dBASE 7 esiste un designer che serve per creare files.SQL files.

Il solo svantaggio consiste nel fatto che crea del codice un pò lungo:

Dall'altro lato, si può eseguire il file SQL e visualizzare il risultato in una finestra ...

La mia opinione personale è che, salvo il caso in cui si debba fare un report con due tabelle relazionate, il Designer non si userà mai ed anche se si usa si dovranno apportare cambiamenti al codice generato.


Sommario

Questa è solo una prima vista generale del SQL di Visual dBASE. Esistono opzioni che abbiamo appena accennato. Poichè l'implementazione del SQL nel BDE è piuttosto buono, è meglio utilizzare OODML di Visual dBASE 7. Per ultimo, potete esaminare i documenti HOW TO sul sito web dell'autore che discute sul confronto fra XBase e OODML, ed altri documenti che si trovano a

   http://www.mindspring.com/~hirschv/dbase/dbase.htm

Sfortunatamente , ci sono situazioni in OODML di Visual dBASE 7 per le quali si è obbligati ad usare la sintassi SQL, chi sviluppa in dBASE troverà sicuramente il modo di ottenere ciò che vuole( mi viene in mente l’area dei filtri – è piacevole usare la clausola LIKE con le opzioni wildcard...) con qualche tentativo...

Once again, thanks to Gary White, who provided me with an updated copy of the LOCALSQL help file produced by Inprise, and did some editing/review of the document as well.


DISCLAIMER: the author is a member of dBVIPS (dBASE Volunteer Internet Peer Support) -- a group of volunteers who provide technical support for dBASE, Inc. on the Visual dBASE newsgroups (news.dbase2000.com). If you have questions regarding this .HOW document, or about Visual dBASE you can communicate directly with the author and dBVIPS in the appropriate newsgroups on the internet. Technical support is not currently provided by private E-Mail by members of dBVIPS.
.HOW files are created as a free service by members of dBVIPS to help users learn to use Visual dBASE more effectively. They are edited by both dBVIPS members and dBASE, Inc. Technical Support (to ensure quality). This .HOW file MAY NOT BE POSTED ELSEWHERE without the explicit permission of the author, who retains all rights to the document.
Copyright 1999, Kenneth J. Mayer. All rights reserved.
Information about dBASE, Inc. can be found at:
       http://www.dbase2000.com


EoHT: X2SQL.HTM -- March 17, 1999 -- KJM