You are on page 1of 36

SQL IN VFP

DIN VFP HELP


Structured Query Language (SQL) commands.
Visual FoxPro supports the following SQL commands:
SELECT - SQL
You can create a SELECT command query in these areas:
In the Command window.
In a Visual FoxPro program (like any other Visual FoxPro command).
In the Query Designer.
ALTER TABLE - SQL
Modifies an existing table. You can modify the name, type, precision, scale, null value support, and
referential integrity rules for each field in the table.
CREATE CURSOR - SQL
Creates a temporary table. Each field in the temporary table is defined with a name, type, precision,
scale, null value support, and referential integrity rules. These definitions can be obtained from the
command itself or from an array.
CREATE TABLE -SQL
Creates a table. Each new table field is defined with a name, type, precision, scale, null value support,
and referential integrity rules. These definitions can be obtained from the command itself or from an
array.
DELETE - SQL
Marks records in a table for deletion using SQL syntax.
INSERT - SQL
Appends a new record to the end of an existing table. The new record contains data listed in the INSERT
command or from an array.
UPDATE - SQL
Updates records in a table. The records can be updated based on the results of a SELECT - SQL
statement.
INTRODUCERE
Astfel pentru MANIPULAREA DATELOR sint utilizate comenzile

SELECT
INSERT
DELETE
UPDATE

Extragerea datelor din BD


Adaugarea de noi linii/inscrieri in BD
Stergerea de linii dintr-o tebela
Modificarea valorilor unor atribute

Pentru DEFINREA BAZEI DE DATE

CREATE TABEL
DROP TABLE
ALTER TABLE
CREATE VIEW
CREATE CURSOR

Adaugarea unei noi tabele in BD


Stergerea unei tabele din BD
Modificarea structurii unui tabel
Crearea unei tabele virtuale
Crearea unei tabele temporare

Pentru CONTROLUL TRANZACTIILOR


BEGIN TRANZACTION Marcheaza inceputul unei tranzactii
END TRANZACTION
Marcheaza sfirsitul unei tranzactii
1

ROLLBACK

Abandoneaza tranzactia in curs

1. CREAREA TABELELOR SI DECLARAREA RESTRICTIILOR


Se efectuiaza cu ajutorul comenzii CREATE TABLE iar pentru modificarea structurii tabelului cu
ALTER TABLE
Syntaxa
CREATE TABLE | DBF TableName1 [NAME LongTableName] [FREE]
(FieldName1 FieldType [(nFieldWidth [, nPrecision])]
[NULL | NOT NULL]
[CHECK lExpression1 [ERROR cMessageText1]]
[DEFAULT eExpression1]
[PRIMARY KEY | UNIQUE]
[REFERENCES TableName2 [TAG TagName1]]
&& Tablename2 tabela-parinte a legaturii
[NOCPTRANS]
[, FieldName2 ...]
[, PRIMARY KEY eExpression2 TAG TagName2
|, UNIQUE eExpression3 TAG TagName3]
&& Se creaza un index candidat
[, FOREIGN KEY eExpression4 TAG TagName4 [NODUP] && Se creaza un index regular
REFERENCES TableName3 [TAG TagName5]]
[, CHECK lExpression2 [ERROR cMessageText2]])
| FROM ARRAY ArrayName
Exemplu din Materialul HELP al VFP.
The following example creates a new database named Mydata1. CREATE TABLE is used to create three
tables (Salesman, Customer, and Orders). The FOREIGN KEY and REFERENCES clauses in the
second CREATE TABLE command create a persistent one-to-many relationship between the Salesman
and Customer tables. The DEFAULT clauses in the third CREATE TABLE command establish default
values, and the CHECK and ERROR clauses establish business rules for entering data into specific
fields. The MODIFY DATABASE is used to display the relationship between the three tables.
CLOSE DATABASES
CLEAR
* Create mydata database in the current directory or folder
CREATE DATABASE mydata1
* Create a salesman table with a primary key
CREATE TABLE salesman ;
(SalesID c(6) PRIMARY KEY, ;
SaleName C(20))
* Create a customer table and relate it to the salesman table.
CREATE TABLE customer ;
(SalesID c(6), ;
CustId i PRIMARY KEY, ;
CustName c(20) UNIQUE,
;
SalesBranch c(3), ;
FOREIGN KEY SalesId TAG SalesId REFERENCES salesman)
* Create an orders table related to customer with its own primary
* key and some business rules such as defaults & checks.
CREATE TABLE orders ;
(OrderId i PRIMARY KEY, ;
CustId i REFERENCES customer TAG CustId, ;
OrderAmt y(4), ;
OrderQty i ;

DEFAULT 10 ;
CHECK (OrderQty > 9) ;
ERROR "Order Quantity must be at least 10", ;
DiscPercent n(6,2) NULL ;
DEFAULT .NULL., ;
CHECK (OrderAmt > 0) ERROR "Order Amount Must be > 0" )
* Display new database, tables, and relationships
MODIFY DATABASE
* Delete example files
SET SAFETY OFF && To suppress verification message
CLOSE DATABASES
&& Close database before deleting
DELETE DATABASE mydata1 DELETETABLES

2. UTILIZAREA INSTRUCTIUNILOR SQL PENTRU CREAREA BD SI A


TABELELOR
******program care prezinta crearea si manipularea cu datele a unei BD prin intermediul SQL ******comenzilor
CLOSE DATA ALL
CLOSE TABLES ALL
CLOSE ALL
set default to home()+"\SQL_test\"
set path to TIF
DELETE DATABASE xxxxxx DELETETABLES
wait window "A fost distrusa BD xxxxxx" AT 20,60 timeout 3
CREATE DATABASE xxxxxx
CREATE TABLE raioane (;
nrai CHAR(2);
PRIMARY KEY;
CHECK(nrai=LTRIM(UPPER(nrai)));
ERROR 'indicativul judetului se scrie cu majuscule !', ;
raion CHAT(25) ;
NOT NULL ;
CHECK(raion=LTRIM(PROPER(raion))) ;
ERROR 'Prima literea din fiecare cuvint al' +chr(13)+;
'denumirii raionului este majuscula'+chr(13)+;
'restul literelor sint mici !',;
regiune CHAR(15);
DEFAULT 'Centru';
CHECK (INLIST(regiune,'Centru','Nord','Sud'));
ERROR 'Regiunea poate avea doar o valoare din lista'+CHR(13)+;
'Centru,Nord,Sud';
)
********** Tabelul 2
CREATE TABLE localitati (;
codpost CHAR(5);
3

PRIMARY KEY;
CHECK(cospost=LTRIM(UPPER(codpost)));
ERROR 'Codul postal se scrie fara spatii la inceput !', ;
loc CHAT(25) ;
NOT NULL ;
CHECK(loc=LTRIM(PROPER(loc))) ;
ERROR 'Prima literea din fiecare cuvint al' + CHR (13)+;
'denumirii localitatii este majuscula'+ CHR (13)+;
'restul literelor sint mici !',;
nrai CHAR(2);
DEFAULT 'IS',;
FOREIGN KEY nrai TAG nrai REFERENCES raioane TAG nrai;
);
********** Tabelul 3
CREATE TABLE clienti (;
codcl NUMBER(6);
PRIMARY KEY;
CHECK(codcl>1000),;
ERROR 'Codul clientului trebuie sa fie mai mare decit 1000 !', ;
dencl CHAR(30) ;
CHECK(SUBSTR(dencl,1,1)=UPPER(SUBSTR(dencl,1,1))) ;
ERROR 'Prima literea din denumirea clientului este'+ CHR (13)+;
'obligatoriu majuscula!' ,;
codfiscal CHAR(9);
NULL,;
CHECK(SUBSTR(codfiscal,1,1)=UPPER(SUBSTR(codfiscal,1,1))) ;
ERROR 'Prima literea din codul fiscal este'+ CHR (13)+;
'obligatoriu majuscula!' ,;
adresa CHAR(40);
NULL;
CHECK(SUBSTR(adresa,1,1)=UPPER(SUBSTR(adresa,1,1))) ;
ERROR 'Prima literea din adresa este'+ CHR (13)+;
'obligatoriu majuscula!' ,;
codpost CHAR(5),;
telefon CHAR(10) ;
NULL, ;
FOREIGN KEY codpost TAG codpost REFERENCES localitati TAG codpost;
);
********** Tabelul 4
CREATE TABLE persoane (;
cnp CHAR(14);
PRIMARY KEY;
CHECK(cnp=LTRIM(UPPER(cnp)));
ERROR 'Codul postal se scrie fara spatii la inceput !', ;
nume CHAR(20) ;
CHECK(nume= LTRIM(PROPER(nume))) ;
ERROR 'Prima literea din fiecare cuvint al' + CHR (13)+;
'numelui persoanei este majuscula'+ CHR (13)+;
'restul literelor sint mici !',;
prenume CHAR(20);
CHECK(prenume= LTRIM(PROPER(prenume))) ;
4

ERROR 'Prima literea din fiecare cuvint al' + CHR (13)+;


'prenumelui persoanei este majuscula'+ CHR (13)+;
'restul literelor sint mici !',;
adresa CHAR(40);
NULL;
CHECK(SUBSTR(adresa,1,1)=UPPER(SUBSTR(adresa,1,1))) ;
ERROR 'Prima literea din adresa este'+ CHR (13)+;
'obligatoriu majuscula!' ,;
sex CHAR(1) DEFAULT 'B';
CHECK(INLIST(SEX,'F','B'));
ERROR 'Atributul Sex poate avea valorile F pentru femei'+ CHR (13)+;
'si B pentru barabti' ,;
codpost CHAR(5),;
telacasa CHAR(10) NULL,;
telbirou CHAR(10) NULL,;
telmobil CHAR(10) NULL,;
email CHAR(20) NULL,;
FOREIGN KEY codpost TAG codpost REFERENCES localitati TAG codpost;
);
********** Tabelul 5
CREATE TABLE persclient (;
cnp CHAR(14),;
codcl NUMBER(6),;
functie CAHR(25);
CHECK(SUBSTR(functie,1,1)=UPPER(SUBSTR(functie,1,1))) ;
ERROR 'Prima litera din functie se scrie cu majuscule !', ;
PRIMARY KEY cnp+STR(codcl,6)+functie TAG primaru, ;
FOREIGN KEY cnp TAG cnp REFERENCES persoane TAG cnp,;
FOREIGN KEY codcl TAG codcl REFERENCES clienti TAG codcl;
)
********** Tabelul 6
CREATE TABLE produse (;
codpr NUMBER(6);
PRIMARY KEY;
CHECK(codcl>0),;
ERROR 'Codul produsului trebuie sa fie mai mare decit 0 !', ;
denpr CHAR(30) ;
CHECK(SUBSTR(denpr,1,1)=UPPER(SUBSTR(denpr,1,1))) ;
ERROR 'Prima literea din denumirea produsului este'+ CHR (13)+;
'obligatoriu majuscula!' ,;
um CHAR(10),;
grupa CHAR(15);
CHECK(SUBSTR(grupa,1,1)=UPPER(SUBSTR(grupa,1,1))) ;
ERROR 'Prima literea din grupa este'+ CHR (13)+;
'obligatoriu majuscula!' ,;
procTVA NUMBER(3,2);
DEFAULT 0.28,;
imagine GENERAL;
)
********** Tabelul 7
5

CREATE TABLE gestiuni (;


gestiune CHAR(4);
PRIMARY KEY,;
den_gest CHAR(25);
CHECK(SUBSTR(den_gest,1,1)=UPPER(SUBSTR(den_gest,1,1))) ;
ERROR 'Prima literea din denumirea produsului este'+ CHR (13)+;
'obligatoriu majuscula!' ,;
adresa CHAR(40) ;
NULL;
CHECK(SUBSTR(adresa,1,1)=UPPER(SUBSTR(adresa,1,1))) ;
ERROR 'Prima literea din adresa este'+ CHR (13)+;
'obligatoriu majuscula!' ,;
codpost CHAR(5),;
telefon CHAR(10);
NULL,;
cnp CHAR(14),;
email CHAR(20) NULL,;
FOREIGN KEY codpost TAG codpost REFERENCES localitati TAG codpost,;
FOREIGN KEY cnp TAG cnp REFERENCES persoane TAG cnp;
)
********** Tabelul 8
CREATE TABLE facturi(;
nrfact NUMBER(8);
PRIMARY KEY,;
datafact DATE;
DEFAULT DATE();
CHECK(BETWEEN(datafact,{^2001/01/01},{^2010/12/31})) ;
ERROR 'Data fact se afal in interv 1 ian 2001-31 decembrie 2010!', ;
gestiune CHAR(4) NOT NULL,;
codcl NUMBER(6),;
obs CHAR(50) NULL,;
FOREIGN KEY gestiune TAG gestiune REFERENCES gestiuni TAG gestiune,;
FOREIGN KEY codcl TAG codcl REFERENCES clienti TAG codcl;
)
********** Tabelul 9
CREATE TABLE liniifact(;
nrfact NUMBER(8),;
linie NUMBER(2);
CHECK(linie>0),;
ERROR 'Codul linie trebuie sa fie mai mare decit 0 !', ;
codpr NUMBER(6),;
cantitate NUMBER(10),;
pretunit NUMBER(12),;
PRIMARY KEY STR(nrfact,8)+STR(linie,2) TAG primaru, ;
FOREIGN KEY nrfact TAG nrfact REFERENCES facturi TAG nrfact,;
FOREIGN KEY codpr TAG codpr REFERENCES produse TAG codpr;
)
********** Tabelul 10
CREATE TABLE incasari(;
codinc NUMBER(8);
PRIMARY KEY,;
6

datainc DATE;
DEFAULT DATE();
CHECK(BETWEEN(datainc,{^2001/01/01},{^2010/12/31})) ;
ERROR 'Data inc se afal in interv 1 ian 2001-31 decembrie 2010!', ;
coddoc CHAR(4);
CHECK(coddoc= UPPER (LTRIM (coddoc)));
ERROR 'Codul documentului se scrie cu majuscule!', ;
nrdoc CHAR(16),;
datadoc DATE;
DEFAULT DATE()-5;
)
********** Tabelul 11
CREATE TABLE incasfact(;
codinc NUMBER(8),;
nrfact NUMBER(8),;
transa NUMBER(16) NOT NULL,;
PRIMARY KEY STR(codinc,8)+STR(nrfact,8) TAG primaru, ;
FOREIGN KEY codinc TAG codinc REFERENCES incasari TAG codinc,;
FOREIGN KEY nrfact TAG nrfact REFERENCES facturi TAG nrfact;
)
Atentie!!!
La crearea indexilor compusi, la crearea indexilor Primari / PRIMARY KEY /, Regulari /FOREIGN
KEY/ si Candidat /UNOQUE/.
Din pacate declararea cheilor straine nu inseamna si intituirea restrictiei referentiale. Pentru a o institui
este necesar de a institui restrictiile mentionate cu Referential Integrity Builder.
3. MODIFICAREA STRUCTURII TABELELOR
O proiectare buna in general creaza putine probleme ce tin de modificarea structurii BD. Ea de fapt
ramine intacta. Cu toate acestea pot aparea unele necesitati de modificare a lungimii unui atribut,
adaugarii unui atribut, stergerii unui atribut s.a.
Pentru a modifica structura tabelelor de date este utilizata comanda ALTER TABLE. In cele ce urmeaza
vom prezenta citeva formate de sintaxa a acestei comenzi si citeva exemple.
ALTER TABLE TableName1
ADD | ALTER [COLUMN] FieldName1
FieldType [(nFieldWidth [, nPrecision])]
[NULL | NOT NULL]
[CHECK lExpression1 [ERROR cMessageText1]]
[DEFAULT eExpression1]
[PRIMARY KEY | UNIQUE]
[REFERENCES TableName2 [TAG TagName1]]
[NOCPTRANS]
[NOVALIDATE]
-orALTER TABLE TableName1
ALTER [COLUMN] FieldName2
[NULL | NOT NULL]
[SET DEFAULT eExpression2]
[SET CHECK lExpression2 [ERROR cMessageText2]]
[DROP DEFAULT]
7

[DROP CHECK]
[NOVALIDATE]
-orALTER TABLE TableName1
[DROP [COLUMN] FieldName3]
[SET CHECK lExpression3 [ERROR cMessageText3]]
[DROP CHECK]
[ADD PRIMARY KEY eExpression3 TAG TagName2 [FOR lExpression4]]
[DROP PRIMARY KEY]
[ADD UNIQUE eExpression4 [TAG TagName3 [FOR lExpression5]]]
[DROP UNIQUE TAG TagName4]
[ADD FOREIGN KEY [eExpression5] TAG TagName4 [FOR lExpression6]
REFERENCES TableName2 [TAG TagName5]]
[DROP FOREIGN KEY TAG TagName6 [SAVE]]
[RENAME COLUMN FieldName4 TO FieldName5]
[NOVALIDATE]
Exemple din HELP VFP.
ALTER TABLE SQL Command Examples
Example 1 adds a field called fax to the customer table and allows the field to have null values.
Example 2 makes the cust_id field the primary key of the customer table.
Example 3 adds a field validation rule to the quantity field of the orders table so that values in the
quantity field must be non-negative.
Example 4 adds a one-to-many persistent relation between the customer and orders tables based on
the primary key cust_id in the customer table and a new foreign key index cust_id in the orders
table.
Example 5 removes the field validation rule from the quantity field in the orders table.
Example 6 removes the persistent relation between the customer and orders tables, but keeps the
cust_id index tag in the orders table.
Example 7 adds a field called fax2 to the customer table and prevents the field from containing null
values. The new structure of the table is displayed. Two ALTER COLUMN clauses are used to allow the
field to have null values and set the default value for the field to the null value. Note that multiple
ALTER COLUMN clauses are required to change more than one property of a field in a single ALTER
TABLE command. The new field is then removed from the table to restore the table to its original state.
* Example 1
SET PATH TO (HOME(2) + 'Data\')
&& Sets path to table
ALTER TABLE customer ADD COLUMN fax c(20) NULL
* Example 2
ALTER TABLE customer ADD PRIMARY KEY cust_id TAG cust_id
ALTER TABLE customer ALTER COLUMN cust_id c(5) PRIMARY KEY
* Example 3
ALTER TABLE orders;
ALTER COLUMN quantity SET CHECK quantity >= 0;
ERROR "Quantities must be non-negative"
* Example 4
ALTER TABLE orders;
ADD FOREIGN KEY cust_id TAG cust_id REFERENCES customer
* Example 5

ALTER TABLE orders ALTER COLUMN quantity DROP CHECK


* Example 6
ALTER TABLE orders DROP FOREIGN KEY TAG cust_id SAVE
* Example 7
CLEAR
ALTER TABLE customer ADD COLUMN fax2 c(20) NOT NULL
DISPLAY STRUCTURE
ALTER TABLE customer;
ALTER COLUMN fax2 NULL;
ALTER COLUMN fax2 SET DEFAULT .NULL.
ALTER TABLE customer DROP COLUMN fax2

In cazul exemplului BD generate de noi


Adaugarea atributului DataNast adica data nasterii in tabela PERSOANE se realizeaza astfel
ALTER TABLE PERSOANE ADD DataNast DATE
Redenumirea unui atribut, il poate face doar VFP printere cele mai renumite SGBD-uir
ALTER TABLE PERSOANE RENAME COLUMN DataNast TO DataNasterii
Stergerea unui atribut, sa zicem pe cel pe care numai ce l-am adaugat se va face prin
comanda
ALTER TABLE PERSOANE DROP COLUMN DataNasterii
Modificarea tipului/lungimii unui atribut
ALTER TABLE PERSOANE ALTER COLUMN Prenume CHAR(21)
ALTER TABLE PERSOANE ALTER COLUMN Nume CHAR(17)
Adaugarea/modificarea valorii implicite
ALTER TABLE PERSOANE ALTER COLUMN Sex SET DEFAULT F
Se definesc valorile prin Default, deoarece se presupune ca exista mai multe femei decit
barbate.
Interzicerea valorilor nule pentru atributul Sex se executa dupa comanda.
ALTER TABLE PERSOANE ALTER COLUMN Sex NOT NULL
Adaugarea/anularea restrictiilor se executa tot cu ajutorul ALTER
Restrictiile
PRIMARY KEY cheie primara
UNIQUE unicitate
FOREIGN KEY referentiala
CHECK de comportament.
De exemplu dezactivarea cheiei primare se efectuiaza cu ajutorul comenzii
ALTER TABLE PERSOANE DROP PRIMARY KEY
Pentru restabilirea keiei
9

ALTER TABLE PERSOANE ADD PRIMARY KEY (CNP) && numele cimpului in paranteze
Atentie!!!
NOVALIDATE se permite operarea unor modificari ale structurii chiar daca acestea
ar viola integritatea datelor.
4.COMENZI DE ACTUALIZARE
Trei sunt comenzile de actualizare INSERT, UPDATE si DELETE
A. Adaugarea unei linii/inscrieri
Din HELP al VFP
Appends a record to the end of a table that contains the specified field values.
Syntaxa
INSERT INTO dbf_name [(fname1 [, fname2, ...])]
VALUES (eExpression1 [, eExpression2, ...])
-orINSERT INTO dbf_name FROM ARRAY ArrayName | FROM MEMVAR
Arguments
INSERT INTO dbf_name
Specifies the name of the table to which the new record is appended. dbf_name can include a path and
can be a name expression.
If the table you specify isn't open, it is opened exclusively in a new work area and the new record is
appended to the table. The new work area isn't selected; the current work area remains selected.
If the table you specify is open, INSERT appends the new record to the table. If the table is open in a
work area other than the current work area, it isn't selected after the record is appended; the current
work area remains selected.
[(fname1 [, fname2 [, ...]])]
Specifies the names of the fields in the new record into which the values are inserted.
VALUES (eExpression1 [, eExpression2 [, ...]])
Specifies the field values inserted into the new record. If you omit the field names, you must specify the
field values in the order defined by the table structure. If SET NULL is ON, INSERT SQL attempts to
insert null values into any fields not specified in the VALUES clause.
FROM ARRAY ArrayName
Specifies the array whose data is inserted into the new record. The contents of the elements of the array,
starting with the first element, are inserted into the corresponding fields of the record. The contents of
the first array element are inserted into the first field of the new record; the contents of the second array
element are inserted into the second field, and so on.
Any default values for fields are ignored when you include the FROM ARRAY clause.
FROM MEMVAR
Specifies that the contents of variables are inserted into fields with the same names as the variables. If a
variable doesn't exist with the same name as the field, the field is left empty.
Remarks
The new record contains the data listed in the VALUES clause or contained in the specified array or
variables. The record pointer is positioned on the new record.
INSERT SQL Command Examples din HELP VFP
10

The following example opens the employee table and adds one record.

USE employee
INSERT INTO employee (emp_no, fname, lname, officeno) ;
VALUES (3022, "John", "Smith", 2101)
The following example opens the customer table in the testdata database.

The contents of the current


record are scattered to variables, and the table's structure is copied to a new table named cust2.
INSERT - SQL is used to insert a new record in the cust2 table, and BROWSE is issued to display the
new record.
CLOSE DATABASES
CLEAR
OPEN DATABASE (HOME(2) + 'Data\testdata')
USE Customer
&& Open customer table
* Scatter current record to memory variables
SCATTER MEMVAR
* Copy structure of current table to example table
COPY STRUCTURE TO cust2
* Insert record from memory variable
INSERT INTO cust2 FROM MEMVAR
SELECT CUST2
BROWSE
* Close and delete example table
USE
DELETE FILE cust2.dbf

Atentie!!!
Ordinea valorilor in clauza VALUES trebuie sa fie identica cu cea declarata la
crearea (sau modificarea structurii) tabelelor. Modificarea este posibila numai
prin enumararea dupa numele tabelei, a atributelor ce vor primi valorile
specificate
B. STERGEREA UNOR LINII/INSCRIERI
Din HELP VFP
Marks records for deletion.
Syntax
DELETE
[Scope] [FOR lExpression1] [WHILE lExpression2]
[IN nWorkArea | cTableAlias]
[NOOPTIMIZE]
Arguments
Scope
Specifies a range of records to mark for deletion. The scope clauses are: ALL, NEXT nRecords,
RECORD nRecordNumber, and REST.
The default scope for DELETE is the current record (NEXT 1).
FOR lExpression1
Specifies a condition whereby only the records that satisfy the logical condition lExpression1 are
marked for deletion.
11

Rushmore optimizes a query created with DELETE ... FOR if lExpression1 is an optimizable expression
and the table is indexed on DELETED( ). For best performance, use an optimizable expression in the
FOR clause.
WHILE lExpression2
Specifies a condition whereby records are marked for deletion for as long as lExpression2 evaluates to
true (.T.).
IN nWorkArea
Specifies the work area of the table in which records are marked for deletion.
IN cTableAlias
Specifies the alias of the table in which records are marked for deletion.
If you omit nWorkArea and cTableAlias, records are marked for deletion in the table in the currently
selected work area.
NOOPTIMIZE
Disables Rushmore optimization of DELETE.
Remarks
Records marked for deletion aren't physically removed from the table until PACK is issued. Records
marked for deletion can be recalled (unmarked) with RECALL.
DELETE Command Example din HELP VFP
The following example opens the customer table in the testdata database. DELETE is used to mark
all records for deletion where the country field contains USA. All the records marked for deletion are
displayed. RECALL ALL is used to unmark all the records marked for deletion.
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'Data\testdata')
USE customer && Opens Customer table
DELETE FOR country = 'USA' && Mark for deletion
CLEAR
LIST FIELDS company, country FOR DELETED( ) && List marked records
RECALL ALL && Unmark all records marked for deletion

PROGRAM DE COMPLETARE CU DATE A BD XXXXXX.DBC


Set deafult to home()+ \SQL_test\
IF !DBUSED(xxxxxx)
OPEN DATABASE xxxxxx EXCLUSIVE
ENDIF
DELETE FROM incasfact
SELE incasfact
ZAP
DELETE FROM incasari
SELE incasari
ZAP
DELETE FROM liniifact
SELE liniifact
ZAP
DELETE FROM facturi
SELE facturi
ZAP
DELETE FROM gestiuni
SELE gestiuni
ZAP
DELETE FROM produse
SELE produse
ZAP
DELETE FROM persclienti
SELE persclienti
ZAP

12

DELETE FROM persoane


SELE persoane
ZAP
DELETE FROM clienti
SELE clienti
ZAP
DELETE FROM localitati
SELE localitati
ZAP
DELETE FROM raioane
SELE raioane
ZAP

*********Inserare de date
INSERT INTO raioane VALUES (AN,Anenii Noi, Centru)
INSERT INTO raioane VALUES (ST,Straseni, Centru)
INSERT INTO raioane VALUES (CR,Criuleni, Centru)
INSERT INTO raioane VALUES (IA,Ialoveni, Centru)
INSERT INTO raioane VALUES (HI,Hincesti, Centru)
INSERT INTO raioane VALUES (NI,Nisporeni, Centru)
INSERT INTO raioane VALUES (SO,Soroca, Nord)
INSERT INTO raioane VALUES (ED,Edinet, Nord)
INSERT INTO raioane VALUES (BR,Briceni, Nord)
INSERT INTO raioane VALUES (RE,Rezina, Nord)
INSERT INTO raioane VALUES (CH,Cahul, Sud)
INSERT INTO raioane VALUES (CA,Cantemir, Sud)
INSERT INTO raioane VALUES (LE,Leova, Sud)
INSERT INTO raioane VALUES (GA,UTAG, Sud)
INSERT INTO localitati VALUES (2200,Anenii Noi, AN)
INSERT INTO localitati VALUES (2300,Anenii Noi, AN)
INSERT INTO localitati VALUES (2000,Straseni, ST)
INSERT INTO localitati VALUES (2100,Straseni, ST)
INSERT INTO localitati VALUES (2400,Criuleni, CR)
INSERT INTO localitati VALUES (2500,Criuleni, CR)
INSERT INTO localitati VALUES (2600,Cantemir, CA)
INSERT INTO localitati VALUES (2700,Ialoveni, IA)
INSERT INTO localitati VALUES (3000,Hincesti, HI)
INSERT INTO localitati VALUES (3200,Hincesti, HI)
INSERT INTO localitati VALUES (3400,Edinet, ED)
INSERT INTO localitati VALUES (3600,Cahul, CH)
INSERT INTO clienti VALUES (1001,Client 1 SRL,R1001,Cucima 13,2000,NULL)
INSERT INTO clienti (codcl,dencl,codfiscal,codpost,telefon);
VALUES (1002,Client 2 SRL,R1002,Cucima 13,2700,032-212121)
INSERT INTO clienti VALUES (1003,Client 1 SRL,R1003,Putin 13,2200,NULL)
INSERT INTO clienti (codcl,dencl,codfiscal,codpost,telefon);
VALUES (1004,Client 2 SRL,R1004,Cucima 13,2200,032-212121)
INSERT INTO clienti VALUES (1005,Client 1 SRL,R1005,Brejnev 13,2000,NULL)
INSERT INTO clienti VALUES (1006,Client 1 SRL,R1006,Ustinov 13,2200,NULL)
INSERT INTO clienti VALUES (1007,Client 1 SRL,R1007,Andropov 13,3400,NULL)
INSERT INTO clienti VALUES (1008,Client 1 SRL,R1008,Cosighin 13,2200,NULL)
INSERT INTO persoane
VALUES (CNP1,Ion, Vasile,Sloboda 13,B,2200,123456,987654,094222222,NULL)
INSERT INTO persoane
13

VALUES (CNP2,Chiron, Ileana,Sloboda


13,F,2200,123456,987654,094222222,NULL)
INSERT INTO persoane
VALUES (CNP3,Vanea, Petru,Sloboda 13,B,2100,123456,987654,094222222,NULL)
INSERT INTO persoane
VALUES (CNP4,Ghita, Valea,Sloboda 13,F,2000,123456,987654,094222222,NULL)
INSERT INTO persoane
VALUES (CNP5,Tiron, Iulia,Sloboda 13,F,2700,123456,987654,094222222,NULL)
INSERT INTO persoane
VALUES (CNP6,Papion, Nelea,Sloboda 13,F,2500,123456,987654,094222222,NULL)
INSERT INTO persoane
VALUES (CNP7,Ghidon, Peste,Sloboda 13,B,3000,123456,987654,094222222,NULL)
INSERT INTO persclient VALUES (CNP1,1001,Director general)
INSERT INTO persclient VALUES (CNP2,1002,Director general)
INSERT INTO persclient VALUES (CNP3,1003,Sef aprovizionare)
INSERT INTO persclient VALUES (CNP4,1004,Sef aprovizionare)
INSERT INTO persclient VALUES (CNP5,1005,Director financiar)
INSERT INTO persclient VALUES (CNP6,1006,Director general)
INSERT INTO persclient VALUES (CNP7,1007,Director financiar)
INSERT INTO persclient VALUES (CNP8,1008,Sef aprovizionare)
INSERT INTO produse (codpr,denpr,um,grupa,proctva);
VALUES (1,Produs 1,buc,Tigari,0.19)
INSERT INTO produse (codpr,denpr,um,grupa,proctva);
VALUES (2,Produs 2,kg,Bere,0.19)
INSERT INTO produse (codpr,denpr,um,grupa,proctva);
VALUES (3,Produs 3,kg,Bere,0.19)
INSERT INTO produse (codpr,denpr,um,grupa,proctva);
VALUES (4,Produs 4,buc,Dulciuri,0.19)
*includerea imaginilor in cimpurile GENERAL. !!!! In SQL nu exista astfel de posibilitati
SELECT Produse
GO TOP
nrFisierTif=ADIR(A_fTifuri,*.tif)
IF nrFisierTif>0
FOR I=1 TO nrFisierTif
APPEND GENERAL imagine FROM A_fTifuri(I,1)
SKIP
ENDFOR
ENDIF

ADIR( ) Function Example


The following example uses ADIR( ) to create an array
containing database information. The names of the databases
are then displayed.
CLOSE DATABASES
SET PATH TO (HOME(2) + 'Data')
gnDbcnumber = ADIR(gaDatabase, '*.DBC') && Create array
CLEAR
FOR nCount = 1 TO gnDbcnumber && Loop for number of
databases
? gaDatabase(nCount,1) && Display database names
ENDFOR
SET PATH TO HOME( ) && Set path to Visual FoxPro
directory

INSERT INTO gestiuni


VALUES (001,Depozitul 1,Soseaua Hincesti, 13,2200,CNP10,212121,xgest001@mail.ru)
INSERT INTO gestiuni
VALUES (002,Depozitul 2,Soseaua Hincesti, 13,2300,CNP11,212121,xgest001@mail.ru)
INSERT INTO gestiuni
VALUES (003,Depozitul 3,Soseaua Hincesti, 13,2700,CNP12,212121,xgest001@mail.ru)
INSERT INTO facturi (nrfact,datafact,gestiune,codcl)
VALUES(\ (1111,{^2001/08/01},001,1001)
INSERT INTO facturi (nrfact,datafact,gestiune,codcl)
14

VALUES(\ (1112,{^2001/08/01},001,1001)
INSERT INTO facturi (nrfact,datafact,gestiune,codcl)
VALUES(\ (1113,{^2001/08/01},001,1002)
INSERT INTO facturi (nrfact,datafact,gestiune,codcl)
VALUES(\ (1114,{^2001/08/01},001,1002)
INSERT INTO facturi (nrfact,datafact,gestiune,codcl)
VALUES(\ (1115,{^2001/08/01},001,1003)
INSERT INTO facturi (nrfact,datafact,gestiune,codcl)
VALUES(\ (1116,{^2001/08/01},001,1003)
INSERT INTO facturi (nrfact,datafact,gestiune,codcl)
VALUES(\ (1117,{^2001/08/01},001,1004)
INSERT INTO liniifact VALUES(\ (1111,1,1,50,10000)
INSERT INTO liniifact VALUES(\ (1111,2,2,75,10500)
INSERT INTO liniifact VALUES(\ (1111,3,5,500,6500)
INSERT INTO liniifact VALUES(\ (1112,1,2,80,10300)
INSERT INTO liniifact VALUES(\ (1112,2,3,40,7500)
INSERT INTO liniifact VALUES(\ (1113,1,2,100,9750)
INSERT INTO liniifact VALUES(\ (1113,1,2,70,10700)
INSERT INTO liniifact VALUES(\ (1113,2,4,30,15800)
INSERT INTO liniifact VALUES(\ (1114,3,5,700,10000)
INSERT INTO liniifact VALUES(\ (1114,1,2,150,9300)
INSERT INTO liniifact VALUES(\ (1114,1,2,125,9300)
INSERT INTO liniifact VALUES(\ (1115,1,2,100,9500)
INSERT INTO liniifact VALUES(\ (1116,2,1,150,6400)
INSERT INTO liniifact VALUES(\ (1117,1,2,35,10500)
INSERT INTO incasari VALUES(\ (1234,{^2001/08/15},OP,111,{^2000/08/10})
INSERT INTO incasari VALUES(\ (1235,{^2001/08/15},CHIT,222,{^2000/08/15})
INSERT INTO incasari VALUES(\ (1236,{^2001/08/16},OP,333,{^2000/08/09})
INSERT INTO incasari VALUES(\ (1237,{^2001/08/17},CEC,444,{^2000/08/10})
INSERT INTO incasari VALUES(\ (1238,{^2001/08/17},OP,555,{^2000/08/10})
INSERT INTO incasari VALUES(\ (1239,{^2001/08/18},OP,666,{^2000/08/11})
INSERT INTO incasfact VALUES(\ (1234,1111,5399625)
INSERT INTO incasfact VALUES(\ (1234,1118,5399625)
INSERT INTO incasfact VALUES(\ (1235,1112,5399625)
INSERT INTO incasfact VALUES(\ (1235,1117,5399625)
INSERT INTO incasfact VALUES(\ (1236,1118,5399625)
INSERT INTO incasfact VALUES(\ (1236,1120,5399625)
INSERT INTO incasfact VALUES(\ (1237,1117,5399625)
INSERT INTO incasfact VALUES(\ (1238,1113,5399625)
INSERT INTO incasfact VALUES(\ (1239,1117,5399625)
Atentie!!!
In exemplul de mai sus am pornit de la presupunerea ca in directoriul current exista cite un fisier graphic
cu extensia tif pentru fiecare produs, iar ordinea acestora coiencide cu ordinea produselor din tabela,
ceea ce e destul de riscant. Astfel incit procedura ce urmeaza pare a fi una mai adecvata.
SELECT PRODUSE
15

SCAN
Nume_=figura_+LTRIM(STR(codpr,6))+.TIF
IF FILE((nume_))
APPEND GENERAL image FROM (nume_) LINK
ENDIF
ENDSCAN
C. MODIFICAREA VALORILOR UNOR ATTRIBUTE
Updates records in a table with new values.
Syntax
UPDATE [DatabaseName1!]TableName1
SET Column_Name1 = eExpression1
[, Column_Name2 = eExpression2 ...]
WHERE FilterCondition1 [AND | OR FilterCondition2 ...]]
Arguments
[DatabaseName1!]TableName1
Specifies the table in which records are updated with new values.
DatabaseName1! specifies the name of a non-current database containing the table. You must include
the name of the database containing the table if the database is not the current one. Include the
exclamation point (!) delimiter after the database name and before the table name.
SET Column_Name1 = eExpression1
[, Column_Name2 = eExpression2
Specifies the columns that are updated and their new values. If you omit the WHERE clause, every row
in the column is updated with the same value.
WHERE FilterCondition1 [AND | OR FilterCondition2 ...]]
Specifies the records that are updated with new values.
FilterCondition specifies the criteria that records must meet to be updated with new values. You can
include as many filter conditions as you like, connecting them with the AND or OR operator. You can
also use the NOT operator to reverse the value of a logical expression, or use EMPTY( ) to check for an
empty field.
Remarks
UPDATE - SQL can only update records in a single table. Note that subqueries are supported in
UPDATE SQL.
Unlike REPLACE, UPDATE - SQL uses record locking when updating multiple records in a table
opened for shared access. This reduces record contention in multiuser situations, but may reduce
performance. For maximum performance, open the table for exclusive use or use FLOCK( ) to lock the
table.
UPDATE - SQL Command Example din HELP VFP
The following example opens the customer table in the testdata database. UPDATE -SQL is used to
set all of the values in the maxordamt field to 25.
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'Data\testdata')
USE Customer
&& Open customer table
* Set and display amounts for customers
UPDATE customer SET maxordamt = 25

16

BROWSE FIELDS company,maxordamt

Exemple cu referinta la BD creata mai sus


Remarca
Modificarea se produce pe toate liniile tabelei care indeplinesc conditia formulata prin
predicat.
De exemplu
Noul numar de telefon al clientului ce are codul 1001 este 032-313131. Sa se opereze
modificarea in baza de date
UPDATE CLIENT;
SET telefon =032-313131;
WHERE codcl=1001
Modificarea cresterii TVA pentru toate produsele de la 0.19 la 0.22 se va efectua cu
ajutorul comenzii
UPDATE PRODUSE;
SET procTVA=0.22;
5. INTEROGAREA BAZELOR DE DATE COMANDA SELECT
Syntaxa
SELECT [ALL | DISTINCT] [TOP nExpr [PERCENT]]
[Alias.] Select_Item [AS Column_Name]
[, [Alias.] Select_Item [AS Column_Name] ...]
FROM [FORCE]
[DatabaseName!]Table [[AS] Local_Alias]
[[INNER | LEFT [OUTER] | RIGHT [OUTER] | FULL [OUTER] JOIN
DatabaseName!]Table [[AS] Local_Alias]
[ON JoinCondition ]
[[INTO Destination]
| [TO FILE FileName [ADDITIVE] | TO PRINTER [PROMPT]
| TO SCREEN]]
[PREFERENCE PreferenceName]
[NOCONSOLE]
[PLAIN]
[NOWAIT]
[WHERE JoinCondition [AND JoinCondition ...]
[AND | OR FilterCondition [AND | OR FilterCondition ...]]]
[GROUP BY GroupColumn [, GroupColumn ...]]
[HAVING FilterCondition]
[UNION [ALL] SELECTCommand]
[ORDER BY Order_Item [ASC | DESC] [, Order_Item [ASC | DESC] ...]]
Exemple din HELP VFP
SELECT - SQL Command Examples
The following examples illustrate the use of user-defined functions with SELECT - SQL:
Example 1
17

Example 1 displays the names of all companies in customer (one field from one table).
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT customer.company ;
FROM customer

Example 2
Example 2 displays the contents of three fields from two tables and joins the two tables based on the
cust_id field. It uses local aliases for both tables.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT a.company, b.order_date, b.shipped_on ;
FROM customer a, orders b ;
WHERE a.cust_id = b.cust_id

Example 3
Example 3 displays only records with unique data in the specified fields.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT DISTINCT a.company, b.order_date, b.shipped_on ;
FROM customer a, orders b ;
WHERE a.cust_id = b.cust_id

Example 4
Example 4 displays the country, postalcode, and company fields in ascending order.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT country, postalcode, company ;
FROM customer ;
ORDER BY country, postalcode, company

Example 5
Example 5 stores the contents of fields from two tables in a third table.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT a.company, b.order_date, b.shipped_on ;
FROM customer a, orders b ;
WHERE a.cust_id = b.cust_id ;
INTO TABLE custship.dbf
BROWSE

Example 6
Example 6 displays only records with an order date earlier than 02/16/1994.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT a.company, b.order_date, b.shipped_on ;
FROM customer a, orders b ;
WHERE a.cust_id = b.cust_id ;
AND b.order_date < {^1994-02-16}

Example 7
Example 7 displays the names of all companies from customer with a postal code that matches a postal
code in the orders table.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT company FROM customer a WHERE ;
EXISTS (SELECT * FROM orders b WHERE a.postalcode = b.postalcode)

Example 8
18

Example 8 displays all records from customer having a company name that begins with an uppercase C
and is an unknown length.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT * FROM customer a WHERE a.company LIKE "C%"

Example 9
Example 9 displays all records from customer having a country name that begins with an uppercase U
and is followed by one unknown character.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT * FROM customer a WHERE a.country LIKE "U_"

Example 10
Example 10 displays the names of all cities in customer in uppercase and names the output column
CityList.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT UPPER(city) AS CityList FROM customer

Example 11
Example 11 demonstrates how you can perform a query on data that contains percentage signs (%). A
backslash (\) is placed before the percentage sign to indicate that it should be treated as a literal, and the
backslash is specified as the escape character in the ESCAPE clause.
Because the sample tables included with Visual FoxPro do not contain the percentage sign character, this
query returns no results.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT * FROM customer;
WHERE company LIKE "%\%%" ESCAPE "\"

Example 12
Example 12 demonstrates how you can perform a query on data that contains underscores (_). A
backslash (\) is placed before the underscore to indicate that it should be treated as a literal, and the
backslash is specified as the escape character in the ESCAPE clause.
Because the sample tables included with Visual FoxPro do not contain the underscore character, this
query returns no results.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT * FROM customer;
WHERE company LIKE "%\_%" ESCAPE "\"

Example 13
In example 13, the Escape character uses itself as a literal. The dash is both the escape character and a
literal. The query returns all rows where the company name contains a percentage sign followed by a
dash.
Because the sample tables included with Visual FoxPro do not contain the percentage sign character, this
query returns no results.
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'data\testdata')
SELECT * FROM customer;
WHERE company LIKE "%-%--%" Escape "-"

Exemple cu referinta la Structura BD create in primul punct

19

Exemple cu referinta la BD creata mai sus


Comanda SELECT respecta in VfP sintaxa de baza din standardul. SQL.92, cele trei clauze principale
fiind SELECT, FROM si WHERE, la care se adauga ORDER BY, GROUP BY, HAVING si alte
elemente legate de subinterogari/subconsultari. De asemenea, VFP utilizeaza si jonctiunea interna
INNER JOIN si extema OUTER JOIN.
Exemplul 1
Presupundnd ca plata se face la 14 zile, care sunt facturile ce urmeaza a fi incasate in perioada 1518 august 2001 ?
Solutia 1.1
SELECT DISTINCT NrFact, DataFact, DataFact + 14 AS Scadenta ;
FROM Facturi ;
WHERE DataFact + 14 >= {^200l/08/15} AND ;
DataFact+l4 <= {"2001/08/18}
Solutia l.2 - folosind propozitia BETWEEN:
SELECT DISTINCT NrFact, DataFact, DataFact+ 14 AS Scadenta ;
FROM Facturi;
WHERE DataFact + 14 BETWEEN {^2001/08/15} AND {"2001/08/18}
Exemplul 2
Care sunt clienlii din din Anenii Noi si Criuleni?
Solutia 2.1 :
SELECT CLIENTI.* ;
FROM CLIENTI INNER JOIN LOCALITATI ;
ON CLIENTI.CodPost = LOCALITATI.CodPost ;
WHERE Loc=Anenii Noi OR Loc=Criuleni
Solutia 2.2- folosind operatorul IN:
SELECT CLIENTI.* ;
FROM CLIENTI INNER JOIN LOCALITATI ;
ON CLIENTI.CodPost = LOCALITATI.CodPost ;
WHERE Loc IN ('Anenii Noi', 'Criuleni')
Solutia 2.3 -vechea sintaxa din SQL-89:
SELECT CLIENTI.* ;
FROM CLIENTI, LOCALITATI ;
WHERE CLIENTI.CodPost = LOCALITATI.CodPost AND Loc ;
IN ('Anenii Noi', 'Criuleni')
Solutia 2.4- sintaxa SQL-89, cu aliasuri pentru tabele:
SELECT C.* ;
FROM CLIENTI C, LOCALITATI L ;
WHERE C.CodPost = L.CodPost AND ;
Loc IN ('Anenii Noi', 'Criuleni')
20

Solutia 2.5 - bazat pe subinterogari/subconsultari


SELECT * ;
FROM CLI.ENTI ;
WHERE CodPost IN ;
(SELECT CodPost ;
FROM LOCALITATI ;
WHERE Loc IN ('Anenii Noi', 'Criuleni');
)
Exemplul 3
Ce persoane cheie trebuie felicitate de Sfintul ION?
Solutia 3.1 folosind operatorul LIKE
SELECT dencl, functie, p.*;
FROM persoane P INNER JOIN persclienti pc;
ON p.cnp=pc.cnp;
INNER JOIN clienti c
ON pc.codcl=c.codcl;
WHERE UPPER(Presume) LIKE ION& OR;
UPPER(Presume) LIKE ION& OR;
UPPER(Presume) LIKE % ION& OR;
UPPER(Presume) LIKE % IOAN& OR;
UPPER(Presume) LIKE %-ION& OR;
UPPER(Presume) LIKE %-IOAN&
Exemplul 4
Ce persoane chepe de la firmele client un au e-mail?
Solutia 4.1 folosind operatorul IS NULL
SELECT dencl, functie, p.*;
FROM persoane P INNER JOIN persclienti pc;
ON p.cnp=pc.cnp;
INNER JOIN clienti c
ON pc.codcl=c.codcl;
WHERE email IS NULL
Exemplul 5
Care sunt facturile emise in aceeasi zi ca si factura 1113?
Solutia 5.1 bazata pe subinterogare/subconsultare
SELECT *;
FROM facturi;
where DataFact IN ;
(SELECT DataFact;
FROM facturi;
WHERE NrFact=1113)
Solutia 5.2 bazata pe jonctiunea interna
SELECT F1.NrFact, F1.DataFact;
FROM facturi F1 INNER JOIN facturi F2;
ON F1.DataFact=F2.DataFact AND F2.Nr.Fact=1113
21

Solutia 5.3 folosind o interogare corelata


SELECT *;
FROM facturi F1;
where EXISTS ;
(SELECT F1;
FROM facturi F2;
WHERE F1.DataFact=F2.DataFact AND F2.NrFact=1113)
Exemplul 6
Care dintre persoanele din tabela cu acelasi nume un au functii la firmele client?
Solutia 6.1 bazata pe subinterogare/subconsultare
SELECT P.*;
FROM persoane P;
where cnp NOT IN ;
(SELECT CNP;
FROM persclienti)
Solutia 6.2 bazata pe jonctiunea externa
SELECT *;
FROM persoane P LEFT OUTER JOIN persclienti PC ;
ON p.cnp=pc.cnp;
WHERE NVL(PC.codcl,0)=0

Returns a non-null value from two expressions.


Syntax
NVL(eExpression1, eExpression2)
Returns
Character, Date, DateTime, Numeric, Currency,
Logical, or the null value
Arguments
eExpression1, eExpression2
NVL( ) returns eExpression2 if eExpression1
evaluates to a null value. NVL( ) returns
eExpression1 if eExpression1 is not a null value.
eExpression1 and eExpression2 may be any data
type. NVL( ) returns .NULL. if both
eExpression1 and eExpression2 both evaluate to
the null value.

Exemplul 7
/Functii agregat cu si fara grupare/
La citi clienti sau trimis facturi?
Solutia 7.1 bazata pe functia COUNT si o subinterogare/subconsultare
SELECT COUNT(*);
FROM clienti;
where codcl IN ;
(SELECT codcl;
FROM facturi)
Solutia 7.2 bazata pe functia COUNT si clauza DISTINCT
SELECT COUNT(DISTINCT codcl);
FROM facturi
Exemplul 8
Care este valoarea totala a facturii 1119, valoarea medie, maxima si minima a produselor vindute pe
aceasta factura?
SELECT SUM(cantitate*pretunit*(1+procTVA) AS Val_Totala;
AVG(cantitate*pretunit+ cantitate*pretunit*procTVA) AS Val_Medie;
MIN(cantitate*pretunit+ cantitate*pretunit*procTVA) AS Val_Minima;
MAX(cantitate*pretunit+ cantitate*pretunit*procTVA) AS Val_Maxima;
FROM produse P INNER JOIN linii Fac. LF;
ON P.codpr=LF.codpr

22

Exemplul 9
Care este valoarea totald a vinzdrilor pentru fiecare zi in care s-au emis facturi :
Pentru rezolvarea problemei este obligatorie folosirea gruparii
SELECT DataFact, SUM(Cantitate * PretUnit * (l+ProcTVA)) AS ValTotala ;
FROM LINIIFACT LF, PRODUSE P, FACTURI F ;
WHERE LF.CodPr = P.CodPr AND LF.NrFact = F.NrFact ;
GROUP BY DataFact
Exemplul 10
Care sunt vtinzarile, cantitativ si valoric, pentru fiecare produs ?
SELECT DenPr, UM, SUM(Cantitate) AS Cantitativ, ;
SUM(Cantitate * PretUnit * (l+ProcTVA)) AS Valoric ;
FROM LINIIFACT LF, PRODUSE P, FACTURI F ;
.WHERE P.CodPr = LF.CodPr AND LF.NrFact = F.NrFact ;
GROUP BY DenPr, UM
Exemplul ll
Sa se oblina situalia vanzarilor pe clienli si zile, afisindu-se cate un subtotal la nivel , client si un total
general.
Varianta propusa, reuneste multimea facturilor propriu-zise, obtinuta din prima fraza SELECT, cu
multimea subtotalurilor la nivel de client (al doilea SELECT) si cu o linie ce reprezintA totalul general.
SELECT PADR(ALLT(dencl),40) As DenumireClient, ;
datafact,;
SUM(Cantitate * PretUnit * (l+ProcTVA)) AS Vinzari ;
FROM liniifact LF, produse P, facturi F, clienti C;
WHERE p.codpr=LF.codpr AND LF.Nrfact=F.Nrfact;
AND F.codcl=C.codcl;
GROUP BY dencl, datafact;
UNION;
SELECT PADR(ALLT(dencl) +-Subtotal,40), { / / },;
SUM(Cantitate * PretUnit * (l+ProcTVA));
FROM liniifact LF, produse P, facturi F, clienti C;
WHERE p.codpr=LF.codpr AND LF.Nrfact=F.Nrfact;
AND F.codcl=C.codcl;
GROUP BY dencl, datafact;
UNION;
SELECT CHR(255)+Total General, { / / },;
SUM(Cantitate * PretUnit * (l+ProcTVA));
FROM liniifact LF, produse P;
WHERE p.codpr=LF.codpr
Exemplul 12
Care sunt zilele in care sau intocmit cel putin 3 facturi?
SELECT datafact, COUNT(*) AS Nr_Facturi;
FROM facturi;
GROUP BY datafact;
HAVING COUNT(*)>=3

23

Exemplul 13
In ce zile s-au vandut si produsul cu denumirea "Produs 1 " si cel cu denumir "Produs 2" ?
Desi are un enunt banal, rezolvarea acestei probleme ofera oportunitatea unor interogari dintre cele mai
spumoase. Va prezentam numai cinci dintre acestea.
.Solutia 13.1.- jonctionarea unei instante obtinuta prin jonctiunea PRODUSE-LINIIFACT-FACTURI (In
care DenPr = 'Produs 1 ') cu o alta instanta aceleiasi combinatii (In care DenPr = 'Produs 2'):
SELECT DISTINCT Fl.DataEact ;
FROM PRODUSE Pl ;
INNER JOIN LINIIFACT LF1;
ON Pl.CodPr = LF1.CodPr ;
INNER JOIN FACTURI Fl ;
ON LF1.NrFact = Fl.NrFact ;
INNER JOIN FACTURI F2;
ON Fl.Datafact=F2,DataFact ;
INNER JOIN LINIIFACT LF2;
ON LF2..Nrfact= F2.NrFact ;
INNER JOIN PRODUSE P2;
ONLF2.CodPr = P2.CodPr ;
WHERE Pl.Denpr = 'Produs l' AND P2.DenPr = 'Produs 2'
.Solutia 13.2- folosind clauza HAVING si functia COUNT:
SELECT DISTINCT DataFact ;
FROM PRODUSE INNER JOIN LINIIFACT ;
ON PRODUSE. CodPr = LINIIFACT. CodPr ;
INNER JOIN FACTURI ;
ON LINIIFACT.Nrfact =FACTURI.Nrfact;
WHERE DenPr;
IN ('Produs l',Produs 2') I;
GROUP BY DataFact ;
HAVING COUNT(DISTINCT LINIIFACT.CodPr) = 2
Solutia 13.3- simuland intersectia prin subconsultari:
SELECT DISTINCT DataFact ;
FROM PRODUSE INNER JOIN LI.NIIFACT ;
ON PRODUSE.CodPr = LINIIFACT.CodPr ;
INNER JOIN FACTURI
ON LINIIFACT.Nrfact = FACTUR.NrFact
WHERE DenPr = 'Produs l' AND DataFact IN ;
(SELECT DISTINCT DataFact ;
FROM PRODUSE ;
INNER JOIN LINIIFACT;
ON PRODUSE.CodPR = LINIIFACT.CodPr ;
INNER JOIN FACTURI;
ON LINIIFACT.Nrfact = FACTURI.NrFact ;
WHERE DenPr = 'Produs 2')
Solutia 13.4 -prin corelarea a doua instante ale jonctiunii PRODUSE-LINIIFACT - FACTURI; prima
contine liniile legate de Produs I, iar a doua de Produs 2:
24

SELECT DISTINCT DataFact ;


FROM PRODUSE Pl, LINIIFACT LF1, FACTORI Fl ;
WHERE Pl.CodPr = LF1.CodPr AND ;
LF1.Nffact =F1.NrFact AND DenPr = Produs 1 ' ;
AND EXISTS;
(SELECT 1;
FROM PRODUSE P2, LINIIFACT LF2, FACTUEI F2 ;
WHERE P2.CodPr = LF2.CodPr AND Lf2;Nrfact = F2.NrFact;
AND P2.Denpr= 'Produs 2' AND F2.DataFact=Fl.DataFact)
Solutia 13.5:
SELECT DISTINCT DataFact ;
FROM FACTURI ;
INNER JOIN LINIIFACT
ON FACTURI.NrFact=LINIIFACT.NrFact ;
INNER JOIN PROPUSE
ON LI.NIIFACT.CodPr=PRODUSE.CodPr AND DenPr IN ('Produs .1', 'Produs 2') ;
WHERE DTOC(DataFact)+DTOC({ / / }) NOT IN ;
(SELECT DISTINCT ;
DTOC(F1.DataFact)+DTOC(NVL(F2.DataFact,{ / / })) ;
FROM FACTURI Fl INNER JOIN PRODUSE P1 ;
ON P1.DenPr IN ('Produs 1', 'Produs 2') ;
LEFT OUTER JOIN (LINI.IFACT LF2 INNER JOIN FACTURI F2 ;
]N LF2 .NrFact:F2 .NrFaCt )
ON F1. DataFact=F2 .DataFact AND P1.CodPr=LF2 .CodPr)
Exemplul 14
Afisarea pe coloane separate, pentru cele trei gestiuni, a facturilor necesita folosirea unei secvente de
IF-uri immediate (IIF-uri):
SELECT IIF(gestiune = '001', STR(F.NrFact,8), space{8)) ;
AS Gestiune 001, ;
IIF(gestiune ='002, STR{F.NrFact,8), space{8)) ;
AS Gestiune 002, ;
IIF(gestiune ='003, STR{F.NrFact,8), space{8)) ;
AS Gestiune 003, ;
DataFact, SUM(Cantitate * PretUnit * (l+ProcTVA)) ;
AS ValTotala ;
FROM FACTURI F ;
INNER JOIN LINIIFACT LF
ON F.NrFact = LF.NrFact ;
INNER JOIN PRODUSE P
ON LF.CodPr = P.CodPr ;
GROUP BY F.NrFact
Exemplul 15
Scadenla fiecarei facturi emise este de 20 de zile. Daca insa data-limita cade intr-o sambata sau
duminica, atunci scadenla se muta in lunea urmatoare. Care sunt zilele, scadente in aceste condilii ?
Visual FoxPro prezinta functiile CDOW (Character Day Of the Week) si DOW (Day of the Week).In
acest caz putem obtine urmatorul rezultat.
25

SELECT NrFact AS Factura, DataFact, ;


DataFact + 20 AS Scadental, ;
CDOW(DataFact+20) AS NumeZil, ;
IIF(DOW(DataFact+20)=6, ;
DataFact+22, ;
IIF(DOW(DataFact+20)=1, ;
DataFact+21, ;
DataFact+20) ) AS Scadenta,;
CDOW(IIF(DOW(Datafact+20)=6,;
DataFact+22, ;
IIF(DOW(DataFact+20)=1, ;
DataFact+21,;
DataFact+20) ) ) AS ZI_Scadenta ;
FROM FACTURI
Exemplul 16
Care sunt valorile facturate si incasate ale fieciirei facturi ?
Solutia de mai jos, reune~te facturile care au macar o transa de incasare cu cele nelncasate deloc:
SELECT F. NrFact, ;
SUM(Cantitate *PfretUnit * (l+ProcTVA).) / ;
COUNT (DISTINCT I..CodInc) AS Facturat, ;
SUM(Transa) / MAX(LF.Linie) AS Incasat ;
FROM LINIIFACT LF, PRODUSE P, FACTURI F, INCASFACT I ;
WHERE LF.CodPr = P.CodPr AND LF.NrFact = F.NrFact ;
AND F.NrFact=I.NrFact ;
GROUP BY F.NrFact ;
UNION ;
SELECT F. NrFact, ;
SUM(Cantitate * P+PretUpit * (l+ProcTVA)) AS Facturat,
0 AS Incasat ;
FROM LINIIFACT LF, PRODUSE P, FACTURI F ;
WHERE LF.CodPr = P.CodPr AND LF.NrFact = F.NrFact ;
AND F.NrFact NOT IN ;
(SELECT NrFact ;
F'ROM INCASFACT) ;
GROUP BY F.NrFact
Clauza TOP. Operatorii ALL si ANY (SOME)
Exemplul 17
Care sunt cele mai mari cinci preluri unitare de vanzare, produsele si facturile in care apar cele cinci
preluri maxime?
In alte SGBD-uri, aceasta problema ar crea mari dureri de cap. Clauza TOP din VFP realizeaza
ordonarea si extragerea celor cinci valori relative simplu )
SELECT TQP 5 NrFact, DenPr, PretUnit ;
FROM LINIIFACT INNER JOIN PRODUSE ;
ON LINIIFACT.CodPr=PRODUSE.CodPr;
ORDER BY PretUnit DESC
26

Exemplul 18
Care sunt produsele vandute la preturi unitare superioare oricarui pret unitar la carea fost vandut
'Produs I' ?
Unul dintre obiectivele acestui exemplu este de a prezenta modul de conexiune a unei consultari cu
subconsultarea sa prin operatorul ALL.
SELECT DISTINCT DenPr, PretUnit ;
FROM PRODUSE P, LINIIFACT LF ;
WHERE p.CodPr=LF.CoQP AND Pretunit > ALL ;
(SELECT DISTINCT PretUnit;
FROM PRODUSE P, LINIIFACT LF;
WHERE p.CodPr=LF.CodPr AND DenPr ='Produs 1'
Exemplul 19
Care sunt produsele vandute la preluri unitare superioare macar unui prel unitar al 'Produsului l' ?
Este genul de situatii in care se foloseste SOME sau ANY (au aceeasi functiune).
SELECT DISTINCT DenPr, PretUnit ;
FROM RODUSE P INNER JO1N LINIIFACT LF ,
ON P.CodPr=LF.CodPr ;
WHERE PretUnit > ANY;
(SELECT DISTINCT PretUnit ;
FROM PRODUSE P INNER JOIN LINIIFACT
ON P.CodPr=LF.CodPr ;
WHERE DenPr ='Produs 1')
Exemplul 20
Care este ultima factura intocmita /factura cea mai recenta/ si data in care a fost remisa ?
Aceasta este o problema cu multe variante de rezolvare
Solutie 20.1
SELECT DataFact, NrFact AS Ultima_Factura ;
FROM facturi;
WHERE NrFact IN;
(SELECT MAX(Nrfact);
FROM facturi)
Solutie 20.2 in locul operatorului de conexiune IN este utilizat semnul =
SELECT DataFact, NrFact AS Ultima_Factura ;
FROM facturi;
WHERE NrFact =;
(SELECT MAX(Nrfact);
FROM facturi)
Solutie 20.3 in locul operatorului de conexiune IN este utilizat operatorul ANY
SELECT DataFact, NrFact AS Ultima_Factura ;
FROM facturi;
WHERE NrFact = ANY;
(SELECT MAX(Nrfact);
FROM facturi)
27

Solutie 20.4 in locul operatorului de conexiune IN este utilizat operatorul ALL


SELECT DataFact, NrFact AS Ultima_Factura ;
FROM facturi;
WHERE NrFact = ALL;
(SELECT MAX(Nrfact);
FROM facturi)
Solutie 20.5 in locul operatorului de conexiune IN este utilizat operatorul >=ALL
SELECT DataFact, NrFact AS Ultima_Factura ;
FROM facturi;
WHERE NrFact = ALL;
(SELECT Nrfact;
FROM facturi)
Solutie 20.6 Se utilizeaza clauza TOP
SELECT TOP 1 DataFact, COUNT(*) AS Nr ;
FROM facturi;
GROUP BY DataFact;
ORDER BY Nr DESC
Exemplul 21
Care este gestiunea cu vinzarile cele mai bune ?
Daca in alte SGBD-uri sunt necesare subconsultari in clauza FROM, in VFP, aceasi clauza TOP salveaza
totul!
SELECT TOP 1 Gestiune, SUM(Cantitate * PretUnit * (l+ProcTVA)) AS Vinzari_Gestiuni ;
FROM FACTURI F ;
INNER JOIN LINIIFACT LF
ON F.NrFact=LF.NrFact ;
INNER JOIN PRODUSE P
ON LF.CodPr=P.CodPr ;
GROUP BY Gestiune ;
ODER BY Vinzari_Gestiuni DESC
6. Includerea comenzii SELECT in programe
Multe din necesitatile VFP necesita folosirea in SQL a mai multor nivele de subconsultare in mod
deosebit in propozitiile FROM sau HAVING. Aceste facilitate nucleul SQL in VFP nu le are in deplina
masura si putere.
In schim in VFP aceste rezultate se pot crea ca rezultate intermediare stocate in CURSOARE sau
TABELE virtuale care la rindul lor pot fi utilizate ca argumente in alte noi consultari.
Salvarea unei operatii SELECT intr-un CURSOR
CURSORUL este in VFP o tabelea temporara care exista din momentul formarii comenzii SELECT cu
clauza INTO CURSOR sau CREATE CURSOR si pina la includerea sa implicita sau explicita

28

Sa revenim la Exemplul 13.


In ce zile sau vindut si produsul cu denumirea Produs 1 si produsul cu denumirea Produs 2
La seria interogarilor care au fost prezentate deja mai adaugam si o varianta simpla de program dupa
cum urmeaza
Programe VFP ce salveaza rezultatele intermediare ale interogarilor in cursoare
SELECT DISTINCT DataFact ;
INTO CURSOR Zile_P1 ;
FROM PRODUSE INNER JOIN LINIIFACT ON PRODUSE.CodPr = LINIIFACT.CodPr ;
INNER JOIN FACTURI ON LINIIFACT.Nrfact = FACTURI.NrFact ;
WHERE DenPr = 'Produs l'
SELECT DISTINCT DataFact ;
INTO CURSOR Zile_P2 ;
FROM PRODUSE INNER JOIN LlNIIFACT ON PRODUSE.CodPr = LlNIIFACT.CodPr ;
INNER JOIN FACTURI ON LlNIIFACT.Nrfact = FACTURI.NrFact ;
WHERE DenPr = 'Produs 2'
SELECT *;
FROM Zile_P1
WHERE DataFact IN
(SELECT DataFact;
FROM ZILE_P2)
Prima interogare creaza cursoul Zile_P1 si contine numai zilele in care s-a vindut primul produs.
Zile_P2 este cursorul ce tine de zilele cind s-a vindut al doilea produs.
Ultima interogare contine intersectia celor doua cursoare ce rezolva problema
Exemplul 22
Care este raionul cu vinzari imediat superioare raionului Anenii Noi ?
Interesul este aici ca in WHERE are loc jonctiunea care solutioneaza cazul
**** Vinzarile raionului Anenii Noi
SELECT SUM(Cantitate * PretUnit * (1 +ProcTVA)) AS Vinzari ;
FROM raioane R ;
INNER JOIN LOCALITATI L ON R.nrai=L.nrai ;
INNER JOIN CLIENTI C ON L.CodPost=C.CodPost ;
INNER JOIN FACTURI F ON C.CodCI=F.CodCI ;
INNER JOIN LINIIFACT LF ON F.NrFact=LF.NrFact ;
INNER JOIN PRODUSE P ON LF.CodPr=P.CodPr ;
INTO CURSOR cVinzari_Aneni_Noi WHERE raion='Anenii Noi'
**** Vinzarile fjecarui raion
SELECT raion, SUM(Cantitate .PretUnit .(1+ProcTVA)) AS Vinzari ;
FROM raioane R ;
INNER JOIN LOCALITATI L ON R.nrai=L.nrai ;
INNER JOIN CLIENTI C ON L.CodPost=C.CodPost ;
INNER JOIN FACTURI F ON C.CodCI=F.CodCI ;
INNER JOIN LlNIIFACT LF ON F.NrFact=LF.NrFact ;
INNER JOIN PRODUSE P ON LF.CodPr=P.CodPr ;
INTO CURSOR cVinzari_Raioane GROUP BY raion
29

SELECT raion, Vinzari ;


FROM cVinzari_Raioane;
WHERE Vinzari <= ALL ;
(SELECT cVinzari_Raioane.Vinzari ;
FROM cVinzari_Raioane, cVinzari_Anenii_Noi ;
WHERE cVinzari_Raioane.Vinzari > cVinzari_Anenii_Noi.Vinzari) ;
AND Vinzari > ALL ;
(SELECT Vinzari ;
FROM cVinzari_Anenii_Noi)
7. Alte consideratii privind cursoarele
Un cursor poate ti creat si prin comanda CREATE CURSOR, caz in care tabela temporara este
actualizabila. Formatul comenzii prezinta clauze similare CRE
Syntaxa
CREATE CURSOR alias_name
(fname1 type [(precision [, scale])
[NULL | NOT NULL]
[CHECK lExpression [ERROR cMessageText]]
[DEFAULT eExpression]
[UNIQUE]
[NOCPTRANS]]
[, fname2 ...])
| FROM ARRAY ArrayName
Din HELP VFP
The following example creates a cursor with the alias employee. A blank record is appended, filled, and displayed with the
BROWSE command.
CLOSE DATABASES
CLEAR
CREATE CURSOR employee ;
(EmpID N(5), Name C(20), Address C(30), City C(30), ;
PostalCode C(10), OfficeNo C(8) NULL, Specialty M)
DISPLAY STRUCTURE
WAIT WINDOW "Press a key to add a record."
INSERT INTO employee (EmpId, Name, Address, City, PostalCode, ;
OfficeNo, Specialty);
VALUES (1002, "Dr. Bonnie Doren", "University of Oregon", "Eugene", ;
"98403", "", "Secondary Special Education")
BROWSE
* At this point you could copy this record to a permanent table
CLOSE ALL
&& Once the cursor is closed, all data is flushed
&& from memory
CLEAR

O data creat si declarate restrictiile, un cursor poate fi actualizat ca orice tabela obisnuita, prin comenzile
SQL: INSERT, UPDATE si DELETE, precum si orice alta comanda de editare specifica VFP. De
asemenea, orice incalcare a vreunei restrictii definite va fi sernnalizata. Cursoarelor, similar tabelelor
virtuale, li se pot vizualiza si configura proprietatile prin functiile CURSORGETPROP( ) si
CURSORSETPRQP().
Continutul unui cursor poate fi adaugat la inregistrarile curente ale unei tabele prin comanda
30

APPEND FROM DBF ( '<NumeCursor>' ) .


Cursoarele pot fi, in unele cazuri un bun inlocuitor al vectorilor.
Exemplu. Este stiut ca agentilor care achita bine platile si impozitele li se acorda anumite facilitati, de
exemplu anumite reduceri la plati.
Program de calcul al reducerilor acordate pentru incasari si anume pentru transele de facturi
platite /INCASARI.DataInc/
in termen de pina la 10 zile se acorda o reducere de 10%
intre 11 si 12 zile se acorda o reducere de 9%
intre 13 si 15 zile se acorda o reducere de 8%
peste 16 zile nu se acorda nici o favaore /in realitate se acorda penalizari/
Transele acordate a reducerilor pot fi stocate in cursoare si astfel folosite la interogari.
* se creaza si introduce datele in cursorul cu transele de reduceri
CREATE CURSOR transe_red ( ;
zile_min INTEGER, ;
zile_max INTEGER, ;
procent INTEGER ;
)
INSERT INTO transe_red VALUES ( 0, 10, 10)
INSERT INTO transe_red VALUES (11, 12, 9)
INSERT INTO transe_red VALUES (13, 15, 8)
INSERT INTO transe_red VALUES (16,99999, 0)
*pentru fiecare factura cu valoare peste zero se insereaza
*in cursorul FACT_TRANSE cite o linie pentru fiecare transa
*posibila de reduceri
SELECT NrFact, DataFact, ValTotala, DataFact + zile_min AS Liminf,
DataFact + zile_max AS LimSup, procent ;
FROM FACTURI, TRANSE_RED
INTO CURSOR FACT_TRANSE ;
WHERE procent > 0 AND ValTotala > 0
* se calculeaza reducerile pe fiecare transa
SELECT FACT_TRANSE.*, Datalnc, Transa, INT(Procent * Transa 1100) AS Reducere ;
INTO CURSOR reduceri_transe ;
FROM INCASFACT INNER JOIN INCASARI ON INCASFACT.Codlnc=INCASARI.Codlnc ;
INNER JOIN FACT_TRANSE ;
ON INCASFACT.NrFact = FACT_TRANSE.NrFact ;
WHERE INCASARI.Datainc >= FACT_TRANSE.Liminf AND ;
INCASARI.Datainc <= FACT_TRANSE.LimSup
* se actualizeaza atributul FACTURI.Reduceri
DIME suma_(1, 1)
SELECT facturi
SCAN
Suma_ = 0
SELECT SUM(Reducere) ;
INTO ARRAY suma_;
31

FROM REDUCERI- TRANSE ;


WHERE NrFact = facturi.Nrfact
SELECT facturi
REPLACE Reduceri WITH suma_(1 , 1 )
ENDSCAN
Este o solutie nu prea simpla dar operationala!!! Aici pielea costa cit dubala!
8. Variante pentru utilizarea interogarilor
Exemplu.
De listat facturile emise catre un client pentru un anumit interval de timp definit de o data initiala si una
finala.
Programul ce urmeaza este o procedura si la ea se poate de adresat cu parametri
PROCEDURE listare
PARAMETER codcl_, datainf_,datasup_
SELECT DenCI AS Client, Nrfact, DataFact, Gestiune, ValTotala AS Valoare;
FROM clienti C LEFT OUTER JOIN facturi F
ON C.codcl=F.codcl;
WHERE F.codcl=codcl_ AND datafact BETWEEN datainf_ AND datasup_
RETURN
ENDPROC
Pentru a obtine lista clientului 1 /cod 1001/ in perioada 2-7 august 2001 apelam la procedura scrisa dupa
cum urmeaza
DO listare WITH 1001,{^2001/08/02},{^2001/08/07}
Varianta ce urmeaza permite afisarea pe ecran
PROCEDURE listare
PARAMETER codcl_, datainf_,datasup_
SELECT DenCI AS Client, Nrfact, DataFact, Gestiune, ValTotala AS Valoare;
INTO CURSOR c1 ;
FROM clienti C LEFT OUTER JOIN facturi F
ON C.codcl=F.codcl;
WHERE F.codcl=codcl_ AND datafact BETWEEN datainf_ AND datasup_
Titlu_=Lista facturilor pentru clientul+ALLTRIM(c1.client)+in perioada+ ;
DTOC(datainf_)+-+DTOC(datasup_)
SELECT C1
BROWSE TITLE Titlu_
RETURN
ENDPROC
Important este ca in asa mod obtinem rezultatele fara a incarca memoria cu Gunoi adica tabele in plus
9. Macrosubstitutia in fraze SELECT
Sa presupunem ca o aceeasi lista - a facturilor ce contine urmatoarele date:
- numarul facturii,
- data emiterii,
32

- numele clientului,
- localjtatea in care-si are sediul c1ientul,
- valoarea incasata pana in momentul curent trebuie obtinuta pentru un anumit interval calendaristic, in orice ordine declarata prin toate combinatiile
posibile ale celor cinci cimpuri
Iata o varianta de program
PROCEDURE listare1
PARAMETER datainf_,datasup_,cimp1_,cimp2_,cimp3_,cimp4_
SELECT Dencl AS Client, Loc As Localitate, Nrfact, DataFact, Gestiune, ValTotala AS Valoare;
FROM clienti C LEFT OUTER JOIN facturi F
ON C.codcl=F.codcl;
INNER JOIN LOCALITATI L
ON C.CodPost = L.CodPost;
WHERE Datafact BETWEEN datainf_ AND datasup_ ;
ORDER BY &cimp1, &cimp2_, &cimp3_, &cimp4_
RETURN
ENDPROC
Clauza ORDER BY se construieste dinamic cu ajutorul macrosubstitutiei.
Lansarea acestui program se face cu comanda DO:
DO listare1 WITH {^2001/08/02}, {^2001/08/07}, 'Loc', 'DataFact', 'DenCl', 'ValTotala'
In continuare se propune o varianta mai eleganta.
Ce-ar fi ca, in arara celor doua date calendaristice, de inceput si de sfarsit, ordonarea sa fie precizata
printr-o lista care sa contina unul, doua, trei. ..sau chiar nici un atribut?
Programul ce urmeaza preia un parametru de tip sir de caractere care este, de rapt, lista atributelor de
ordonare, atribute separate prin virgula.
Asa incat programul analizeaza virgulele din sir si extrage atributele pe baza carora se va construi,
dinamic, clauza WHERE.
In exemplul ce urmeaza se preia numai data initiala si finala, plus ordinea de prezentare, sub forma
de lista de atribute separate prin virgula
Returns the beginning numeric position of the first occurrence of a character expression or memo field
within another character expression or memo field, counting from the leftmost character. La inceput sa
facem cunostinta cu functia AT()
Syntaxa
AT(cSearchExpression, cExpressionSearched [, nOccurrence])
Returns
Numeric
Arguments
cSearchExpression
Specifies the character expression that AT( ) searches for in cExpressionSearched.
cExpressionSearched
Specifies the character expression cSearchExpression searches for.
Both cSearchExpression and cExpressionSearched can be memo fields of any size.
nOccurrence
Specifies which occurrence (first, second, third, and so on) of cSearchExpression is searched for in
cExpressionSearched. By default, AT( ) searches for the first occurrence of cSearchExpression
33

(nOccurrence = 1). Including nOccurrence lets you search for additional occurrences of
cSearchExpression in cExpressionSearched. AT( ) returns 0 if nOccurrence is greater than the number
of times cSearchExpression occurs in cExpressionSearched.
Remarks
AT( ) searches the second character expression for the first occurrence of the first character expression.
It then returns an integer indicating the position of the first character in the character expression found.
If the character expression isn't found, AT( ) returns 0.
The search performed by AT( ) is case-sensitive. To perform a search that isn't case-sensitive, use
ATC( ).
PROCEDURE listare2
PARAMETER datainf_, datasup_, ordinea_
I=1
*se determina prima pozitie a virgulei (asta inseamna cu sunt macar
*doua atribute de ordonare)
poz_ = AT (',', ordinea_, i)
IF poz_ > 0

&& exista macar o virgula, deci sunt mai multe atribute de ordonare

* se localizeaza toate virgulele si se extrag atributele cuprinse intre virgule


poz_preced = O
DO WHILE poz_ # O
ii = str(i,1)
cimp&ii = SUBSTR(ordinea_, poz_preced + 1, poz_ -poz_preced -1 )
poz_preced = poz_
i = i+ 1
poz_ = AT (',', ordinea_, i)
ENDDO
*a mai ramas atributul dintre ultima virgula si sfirsitul sirului de ordonare
ii = str(i,1)
cimp&ii = SUBSTR(ordinea_, poz_preced + 1, LEN(ordinea_) -poz_preced)
*se construieste clauza ORDER BY
order_by_ =
FOR j = 1 TO i
jj = STR(j,1)
IF j > 1
order_by_ = order_by_ + ,
ENDIF
order_by_ = order_by_ + ALLTRIM(cimp&jj)
ENDFOR
ELSE && exista maximum un atribut de ordonare de la IF poz_>0
IF LEN(ALLT(ordinea_))=0
Order_by_=1
ELSE

&& de fapt, nu exista nici un atribut de ordonare


&& ordonarea se face dupa prima coloana
34

Order_by_=ALLTRIM(ordinea_)

&& exista un singur atribut de ordonare

ENDIF
ENDIF
* si acum presentam propriu zis ordonarea
SELECT Dencl AS Client, Loc As Localitate, Nrfact, DataFact, Gestiune, ValTotala AS Valoare;
FROM clienti C LEFT OUTER JOIN facturi F
ON C.codcl=F.codcl;
INNER JOIN LOCALITATI L
ON C.CodPost = L.CodPost;
WHERE Datafact BETWEEN datainf_ AND datasup_ ;
ORDER BY &order_by_
RETURN
ENDPROC
Prezentam 3 moduri de adresare la programul prezentat mai sus
DO listare2 WITH {^2001/08/02}, {^2001/08/07}, 'ValTotala,Dencl,NrFact'
DO listare2 WITH {^2001/08/02}, {^2001/08/07}, 'NrFact'
DO listare2 WITH {^2001/08/02}, {^2001/08/07}, ' '

10. Macrosubstitutie si iteratii SQL


Tot cu ajutorul macrosubstitutiei se pot rezolva situatii dintre cele mai dificile de obtinere a unor
rapoarte pretentioase. Spre exemplificare, dorim obtinerea unui raport matriceal in care, pe verticala, sa
fie prezente toate produsele comercializate de firma, iar "ordonata" sa fie constituita dfn primele patru
zile ale lunii august 2001, adica
DenPr CodPr Zi 01 08 2001

Zi 02 08 2001

Zi 03 08 2001

Zi 04 08 2001

Pentru facilitarea prezentarii, sa ne limitam la patru zile, dar programul ce urmeaza functioneaza pentru
oricate zile dorim, singura problema fiind completarea cursorului ZILE.
In prograrnul ce urmeaza, aceasta se face prin INSERT-uri directe, insa in aplicatii datele initiale si
finale ale intervalului se pot prelua printr-un formular si, astfel, completarea cursorului se
automatizeaza.
SET MARK TO '_'

&& separatorul pentru data calendaristica

CREATE CURSOR Zile (Zi DATE)


INSERT INTO Zile VALUES ({^2001/08/01})
INSERT INTO Zile VALUES ({^2001/08/02})
INSERT INTO Zile VALUES ((^2001/08/03})
INSERT INTO Zile VALUES ({^2001/08/04})
SELECT DataFact, DenPr, LF.CodPr, SUM(INT(Cantitate .PretUnit .(1+ProcTVA))) AS Valoare;
INTO CURSOR Zile_Produse ;
FROM FACTURI F INNER JOIN LINIIFACT LF ON F.NrFact = LF.NrFact ;
INNER JOIN PRODUSE P ON LF.CodPr=P.CodPr ;
WHERE DataFact IN ;
(SELECT Zi ;
35

FROM Zile) ;
GROUP BY DataFact, DenPr, LF.CodPr
SELECT DenPr, CodPr;
INTO CURSOR c1 ;
FROM PRODUSE ;
ORDER BY DenPr
i= 1
SELECT Zile
SCAN
ii = ALL T(STR(i,2))
ii_plus_1 = ALL T(STR(i+1 ,2))
ziua_= '_'+DTOC(Zile.Zi)
SELECT c&ii..*, NVL(ZILE_PRODUSE.Valoare,0) AS Zi&ziua_ ;
FROM c&ii LEFT OUTER JOIN ZILE_PRODUSE ;
ON c&ii..CodPr = ZILE_PRODUSE.CodPr AND DataFact = Zile.Zi ;
INTO CURSOR c&ii_plus_1
i=i+ 1
SELECT Zile
ENDSCAN
SELECT c&ii_plus_1
BROWSE TITLE 'Vinzari_Produse/Zile'
SELECT Zile
USE
SELECT Zile_Produse
USE
FOR j=1 TO i
ii = ALLT(STR(j,2))
SELECT c&ii
USE
ENDFOR
Cateva explicatii. Cursorul ZILE contine toate datele calendaristice care trebuie sa apara drept coloane
ale raportului.
Valorile vanzarilor pe produse si zile sunt calculate si stocate in cursorul Z ILE_PRODUSE.
Liniile raportului sunt alcatuite din toate produsele firmei, astfel incat cursorul "de start" - C1 -este
obtinut din tabela PRODUSE.
Numarul iteratiilor depinde de numarul inregistrarilor din cursorul ZILE - numarul zilelor pentru care
intereseaza raportul.
Corpul ciclului contine jonctiunea cursorului "curent" cu ziua corespunzatoare inregistrarii curente din
cursorul ZILE.

36

You might also like