Вы находитесь на странице: 1из 31

Real SQL Programming

Persistent Stored Modules (PSM)


PL/SQL
Embedded SQL
1

SQL in Real Programs


We have seen only how SQL is used at
the generic query interface --- an
environment where we sit at a terminal
and ask queries of a database.
Reality is almost always different:
conventional programs interacting with
SQL.
2

Options
1. Code in a specialized language is
stored in the database itself (e.g.,
PSM, PL/SQL).
2. SQL statements are embedded in a
host language (e.g., C).
3. Connection tools are used to allow a
conventional language to access a
database (e.g., CLI, JDBC, PHP/DB).
3

Stored Procedures
PSM, or persistent stored modules,
allows us to store procedures as
database schema elements.
PSM = a mixture of conventional
statements (if, while, etc.) and SQL.
Lets us do things we cannot do in SQL
alone.
4

Basic PSM Form


CREATE PROCEDURE <name> (
<parameter list> )
<optional local declarations>
<body>;
Function alternative:
CREATE FUNCTION <name> (
<parameter list> ) RETURNS <type>
5

Parameters in PSM
Unlike the usual name-type pairs in
languages like C, PSM uses modename-type triples, where the mode can
be:
IN = procedure uses value, does not
change value.
OUT = procedure changes, does not use.
INOUT = both.
6

Example: Stored Procedure


Lets write a procedure that takes two
arguments b and p, and adds a tuple
to Sells(bar, beer, price) that has bar =
Joes Bar, beer = b, and price = p.
Used by Joe to add to his menu more
easily.

The Procedure
CREATE PROCEDURE JoeMenu (
IN b
CHAR(20),
Parameters are both
read-only, not changed
IN p
REAL
)
INSERT INTO Sells
The body --VALUES(Joes Bar, b, p); a single insertion
8

Invoking Procedures
Use SQL/PSM statement CALL, with the name
of the desired procedure and arguments.
Example:
CALL JoeMenu(Moosedrool, 5.00);
Functions used in SQL expressions wherever
a value of their return type is appropriate.

Kinds of PSM statements (1)


RETURN <expression> sets the return
value of a function.
Unlike C, etc., RETURN does not terminate
function execution.

DECLARE <name> <type> used to


declare local variables.
BEGIN . . . END for groups of statements.
Separate statements by semicolons.
10

Kinds of PSM Statements (2)


Assignment statements:
SET <variable> = <expression>;
Example: SET b = Bud;

Statement labels: give a statement a


label by prefixing a name and a colon.

11

IF Statements
Simplest form:
IF <condition> THEN
<statements(s)>
END IF;
Add ELSE <statement(s)> if desired, as
IF . . . THEN . . . ELSE . . . END IF;
Add additional cases by ELSEIF
<statements(s)>: IF THEN ELSEIF
THEN ELSEIF THEN ELSE END IF;
12

Example: IF
Lets rate bars by how many customers
they have, based on Frequents(drinker,bar).
<100 customers: unpopular.
100-199 customers: average.
>= 200 customers: popular.

Function Rate(b) rates bar b.

13

Example: IF (continued)
CREATE FUNCTION Rate (IN b CHAR(20) )
Number of
RETURNS CHAR(10)
customers of
bar b
DECLARE cust INTEGER;
BEGIN
SET cust = (SELECT COUNT(*) FROM Frequents
WHERE bar = b);
IF cust < 100 THEN RETURN unpopular
ELSEIF cust < 200 THEN RETURN average
ELSE RETURN popular
Nested
END IF;
IF statement
Return occurs here, not at
14
END;
one of the RETURN statements

Loops
Basic form:
<loop name>: LOOP <statements>
END LOOP;
Exit from a loop by:
LEAVE <loop name>

15

Example: Exiting a Loop


loop1: LOOP
...
LEAVE loop1;
...
END LOOP;

If this statement is executed . . .

Control winds up here

16

Other Loop Forms


WHILE <condition>
DO <statements>
END WHILE;
REPEAT <statements>
UNTIL <condition>
END REPEAT;

17

Queries
General SELECT-FROM-WHERE
queries are not permitted in PSM.
There are three ways to get the effect
of a query:
1. Queries producing one value can be the
expression in an assignment.
2. Single-row SELECT . . . INTO.
3. Cursors.
18

Example: Assignment/Query
Using local variable p and Sells(bar, beer,
price), we can get the price Joe charges for
Bud by:
SET p = (SELECT price FROM Sells
WHERE bar = Joes Bar AND
beer = Bud);

19

SELECT . . . INTO
Another way to get the value of a query
that returns one tuple is by placing INTO
<variable> after the SELECT clause.
Example:
SELECT price INTO p FROM Sells
WHERE bar = Joes Bar AND
beer = Bud;
20

Cursors
A cursor is essentially a tuple-variable
that ranges over all tuples in the result
of some query.
Declare a cursor c by:
DECLARE c CURSOR FOR <query>;

21

Opening and Closing Cursors


To use cursor c, we must issue the
command:
OPEN c;
The query of c is evaluated, and c is set
to point to the first tuple of the result.

When finished with c, issue command:


CLOSE c;
22

Fetching Tuples From a Cursor


To get the next tuple from cursor c,
issue command:
FETCH FROM c INTO x1, x2,,xn ;
The x s are a list of variables, one for
each component of the tuples referred
to by c.
c is moved automatically to the next
tuple.
23

Breaking Cursor Loops (1)


The usual way to use a cursor is to
create a loop with a FETCH statement,
and do something with each tuple
fetched.
A tricky point is how we get out of the
loop when the cursor has no more
tuples to deliver.
24

Breaking Cursor Loops (2)


Each SQL operation returns a status,
which is a 5-digit character string.
For example, 00000 = Everything OK,
and 02000 = Failed to find a tuple.

In PSM, we can get the value of the


status in a variable called SQLSTATE.

25

Breaking Cursor Loops (3)


We may declare a condition, which is a
boolean variable that is true if and only
if SQLSTATE has a particular value.
Example: We can declare condition
NotFound to represent 02000 by:
DECLARE NotFound CONDITION FOR
SQLSTATE 02000;
26

Breaking Cursor Loops (4)


The structure of a cursor loop is thus:
cursorLoop: LOOP

FETCH c INTO ;
IF NotFound THEN LEAVE
cursorLoop;
END IF;

END LOOP;

27

Example: Cursor
Lets write a procedure that examines
Sells(bar, beer, price), and raises by $1
the price of all beers at Joes Bar that
are under $3.
Yes, we could write this as a simple
UPDATE, but the details are instructive
anyway.

28

The Needed Declarations


CREATE PROCEDURE JoeGouge( )
Used to hold
beer-price pairs
DECLARE theBeer CHAR(20);
when fetching
DECLARE thePrice REAL;
through cursor c
DECLARE NotFound CONDITION FOR
SQLSTATE 02000;
Returns Joes menu
DECLARE c CURSOR FOR
(SELECT beer, price FROM Sells
WHERE bar = Joes Bar);
29

The Procedure Body


BEGIN
Check if the recent
OPEN c;
FETCH failed to
menuLoop: LOOP
get a tuple
FETCH c INTO theBeer, thePrice;
IF NotFound THEN LEAVE menuLoop END IF;
IF thePrice < 3.00 THEN
UPDATE Sells SET price = thePrice + 1.00
WHERE bar = Joes Bar AND beer = theBeer;
END IF;
END LOOP;
If Joe charges less than $3 for
CLOSE c;
the beer, raise its price at
Joes Bar by $1.
END;
30

MySQL Cursors
CREATE PROCEDURE curdemo()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE a CHAR(16);
DECLARE b, c INT;
DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1; OPEN cur2;
read_loop: LOOP
FETCH cur1 INTO a, b;
FETCH cur2 INTO c;
IF done THEN LEAVE read_loop; END IF;
IF b < c THEN INSERT INTO test.t3 VALUES (a,b);
ELSE INSERT INTO test.t3 VALUES (a,c); END IF;
END LOOP;
CLOSE cur1;
CLOSE cur2;
31
END;

Вам также может понравиться