0% found this document useful (0 votes)
85 views

Select From: 'Customer (' ') :'

The document discusses using implicit cursors in PL/SQL. Implicit cursors are automatically created for SQL statements without an explicit cursor. Attributes like %FOUND, %NOTFOUND, and %ROWCOUNT can be used to check the status and results of the implicit cursor. An example updates all salaries in a CUSTOMERS table by 500 and uses %ROWCOUNT to check the number of rows affected.

Uploaded by

Sakshi Goel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
85 views

Select From: 'Customer (' ') :'

The document discusses using implicit cursors in PL/SQL. Implicit cursors are automatically created for SQL statements without an explicit cursor. Attributes like %FOUND, %NOTFOUND, and %ROWCOUNT can be used to check the status and results of the implicit cursor. An example updates all salaries in a CUSTOMERS table by 500 and uses %ROWCOUNT to check the number of rows affected.

Uploaded by

Sakshi Goel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 17

Elements of a varray could also be a %ROWTYPE of any database table or %TYPE of any database table field.

The following
example illustrates the concept:

We will use the CUSTOMERS table stored in our database as:

Select * from customers;

+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
+----+----------+-----+-----------+----------+
Following example makes use of cursor which you will study in detail in a separate chapter.
DECLARE
CURSOR c_customers is
SELECT name FROM customers;
type c_list is varray (6) of customers.name%type;
name_list c_list := c_list();
counter integer :=0;
BEGIN
FOR n IN c_customers LOOP
counter := counter + 1;
name_list.extend;
name_list(counter) := n.name;
dbms_output.put_line('Customer('||counter ||'):'||name_list(counter));
END LOOP;
END;
/

When the above code is executed at SQL prompt, it produces the following result:

Customer(1): Ramesh
Customer(2): Khilan
Customer(3): kaushik
Customer(4): Chaitali
Customer(5): Hardik
Customer(6): Komal

PL/SQL procedure successfully completed.


IN & OUT Mode Example 1
This program finds the minimum of two values, here procedure takes two numbers using IN mode and returns their minimum using
OUT paramters.

DECLARE
a number;
b number;
c number;

PROCEDURE findMin(x IN number, y IN number, z OUT number) IS


BEGIN
IF x < y THEN
z:= x;
ELSE
z:= y;
END IF;
END;

BEGIN
a:= 23;
b:= 45;
findMin(a, b, c);
dbms_output.put_line(' Minimum of (23, 45) : ' || c);
END;
/

When the above code is executed at SQL prompt, it produces the following result:

Minimum of (23, 45) : 23

PL/SQL procedure successfully completed.

IN & OUT Mode Example 2


This procedure computes the square of value of a passed value. This example shows how we can use same parameter to accept a
value and then return another result.

DECLARE
a number;
PROCEDURE squareNum(x IN OUT number) IS
BEGIN
x := x * x;
END;
BEGIN
a:= 23;
squareNum(a);
dbms_output.put_line(' Square of (23): ' || a);
END;
/

When the above code is executed at SQL prompt, it produces the following result:

Square of (23): 529

PL/SQL procedure successfully completed.

Methods for Passing Parameters


Actual parameters could be passed in three ways:

 Positional notation
 Named notation

 Mixed notation

POSITIONAL NOTATION
In positional notation, you can call the procedure as:

findMin(a, b, c, d);

In positional notation, the first actual parameter is substituted for the first formal parameter; the second actual parameter is
substituted for the second formal parameter, and so on. So, a is substituted for x, b is substituted for y, c is substituted for z and d is
substituted for m.

NAMED NOTATION
In named notation, the actual parameter is associated with the formal parameter using the arrow symbol ( => ). So the procedure
call would look like:

findMin(x=>a, y=>b, z=>c, m=>d);

MIXED NOTATION
In mixed notation, you can mix both notations in procedure call; however, the positional notation should precede the named
notation.

The following call is legal:

findMin(a, b, c, m=>d);

But this is not legal:

findMin(x=>a, b, c, d);
Example:
The following example illustrates creating and calling a standalone function. This function returns the total number of CUSTOMERS
in the customers table. We will use the CUSTOMERS table which we had created in PL/SQL Variables chapter:
Select * from customers;

+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
+----+----------+-----+-----------+----------+
CREATE OR REPLACE FUNCTION totalCustomers
RETURN number IS
total number(2) := 0;
BEGIN
SELECT count(*) into total
FROM customers;

RETURN total;
END;
/

When above code is executed using SQL prompt, it will produce the following result:

Function created.

Calling a Function
While creating a function, you give a definition of what the function has to do. To use a function, you will have to call that function to
perform the defined task. When a program calls a function, program control is transferred to the called function.

A called function performs defined task and when its return statement is executed or when it last end statement is reached, it
returns program control back to the main program.

To call a function you simply need to pass the required parameters along with function name and if function returns a value then
you can store returned value. Following program calls the function totalCustomers from an anonymous block:

DECLARE
c number(2);
BEGIN
c := totalCustomers();
dbms_output.put_line('Total no. of Customers: ' || c);
END;
/

When the above code is executed at SQL prompt, it produces the following result:

Total no. of Customers: 6

PL/SQL procedure successfully completed.

Example:
The following is one more example which demonstrates Declaring, Defining, and Invoking a Simple PL/SQL Function that computes
and returns the maximum of two values.

DECLARE
a number;
b number;
c number;
FUNCTION findMax(x IN number, y IN number)
RETURN number
IS
z number;
BEGIN
IF x > y THEN
z:= x;
ELSE
Z:= y;
END IF;

RETURN z;
END;
BEGIN
a:= 23;
b:= 45;

c := findMax(a, b);
dbms_output.put_line(' Maximum of (23,45): ' || c);
END;
/

When the above code is executed at SQL prompt, it produces the following result:

Maximum of (23,45): 78

PL/SQL procedure successfully completed.

PL/SQL Recursive Functions


We have seen that a program or subprogram may call another subprogram. When a subprogram calls itself, it is referred to as a
recursive call and the process is known as recursion.

To illustrate the concept, let us calculate the factorial of a number. Factorial of a number n is defined as:

n! = n*(n-1)!
= n*(n-1)*(n-2)!
...
= n*(n-1)*(n-2)*(n-3)... 1

The following program calculates the factorial of a given number by calling itself recursively:

DECLARE
num number;
factorial number;

FUNCTION fact(x number)


RETURN number
IS
f number;
BEGIN
IF x=0 THEN
f := 1;
ELSE
f := x * fact(x-1);
END IF;
RETURN f;
END;

BEGIN
num:= 6;
factorial := fact(num);
dbms_output.put_line(' Factorial '|| num || ' is ' || factorial);
END;
/
When the above code is executed at SQL prompt, it produces the following result:

Factorial 6 is 720

PL/SQL procedure successfully completed.


Implicit Cursors
Implicit cursors are automatically created by Oracle whenever an SQL statement is executed, when there is no explicit cursor for
the statement. Programmers cannot control the implicit cursors and the information in it.

Whenever a DML statement (INSERT, UPDATE and DELETE) is issued, an implicit cursor is associated with this statement. For
INSERT operations, the cursor holds the data that need to be inserted. For UPDATE and DELETE operations, the cursor identifies
the rows that would be affected.

In PL/SQL, you can refer to the most recent implicit cursor as the SQL cursor, which always has the attributes like %FOUND,
%ISOPEN, %NOTFOUND, and %ROWCOUNT. The SQL cursor has additional attributes, %BULK_ROWCOUNT and
%BULK_EXCEPTIONS, designed for use with the FORALL statement. The following table provides the description of the most
used attributes:
Attribute Description

Returns TRUE if an INSERT, UPDATE, or DELETE statement affected one or


%FOUND more rows or a SELECT INTO statement returned one or more rows.
Otherwise, it returns FALSE.

The logical opposite of %FOUND. It returns TRUE if an INSERT, UPDATE, or


%NOTFOUND DELETE statement affected no rows, or a SELECT INTO statement returned
no rows. Otherwise, it returns FALSE.

Always returns FALSE for implicit cursors, because Oracle closes the SQL
%ISOPEN
cursor automatically after executing its associated SQL statement.

Returns the number of rows affected by an INSERT, UPDATE, or DELETE


%ROWCOUNT
statement, or returned by a SELECT INTO statement.
Any SQL cursor attribute will be accessed as sql%attribute_name as shown below in the the example.

Example:
We will be using the CUSTOMERS table we had created and used in the previous chapters.

Select * from customers;

+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
+----+----------+-----+-----------+----------+

The following program would update the table and increase salary of each customer by 500 and use the SQL%ROWCOUNT
attribute to determine the number of rows affected:

DECLARE
total_rows number(2);
BEGIN
UPDATE customers
SET salary = salary + 500;
IF sql%notfound THEN
dbms_output.put_line('no customers selected');
ELSIF sql%found THEN
total_rows := sql%rowcount;
dbms_output.put_line( total_rows || ' customers selected ');
END IF;
END;
/

When the above code is executed at SQL prompt, it produces the following result:
6 customers selected

PL/SQL procedure successfully completed.

If you check the records in customers table, you will find that the rows have been updated:

Select * from customers;

+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2500.00 |
| 2 | Khilan | 25 | Delhi | 2000.00 |
| 3 | kaushik | 23 | Kota | 2500.00 |
| 4 | Chaitali | 25 | Mumbai | 7000.00 |
| 5 | Hardik | 27 | Bhopal | 9000.00 |
| 6 | Komal | 22 | MP | 5000.00 |
+----+----------+-----+-----------+----------+

Explicit Cursors
Explicit cursors are programmer defined cursors for gaining more control over the context area. An explicit cursor should be
defined in the declaration section of the PL/SQL Block. It is created on a SELECT Statement which returns more than one row.

The syntax for creating an explicit cursor is :

CURSOR cursor_name IS select_statement;

Working with an explicit cursor involves four steps:

 Declaring the cursor for initializing in the memory

 Opening the cursor for allocating memory

 Fetching the cursor for retrieving data

 Closing the cursor to release allocated memory

Declaring the Cursor


Declaring the cursor defines the cursor with a name and the associated SELECT statement. For example:

CURSOR c_customers IS
SELECT id, name, address FROM customers;

Opening the Cursor


Opening the cursor allocates memory for the cursor, and makes it ready for fetching the rows returned by the SQL statement into it.
For example, we will open above defined cursor as follows:

OPEN c_customers;

Fetching the Cursor


Fetching the cursor involves accessing one row at a time. For example we will fetch rows from the above opend cursor as follows:

FETCH c_customers INTO c_id, c_name, c_addr;

Closing the Cursor


Closing the cursor means releasing the allocated memory. For example, we will close above opened cursor as follows:
CLOSE c_customers;

Example:
Following is a complete example to illustrate the concepts of explicit curosrs:

DECLARE
c_id customers.id%type;
c_name customers.name%type;
c_addr customers.address%type;
CURSOR c_customers is
SELECT id, name, address FROM customers;
BEGIN
OPEN c_customers;
LOOP
FETCH c_customers into c_id, c_name, c_addr;
dbms_output.put_line(c_id || ' ' || c_name || ' ' || c_addr);
EXIT WHEN c_customers%notfound;
END LOOP;
CLOSE c_customers;
END;
/

When the above code is executed at SQL prompt, it produces the following result:

1 Ramesh Ahmedabad
2 Khilan Delhi
3 kaushik Kota
4 Chaitali Mumbai
5 Hardik Bhopal
6 Komal MP

PL/SQL procedure successfully completed.


Table-Based Records
The %ROWTYPE attribute enables a programmer to create table-based and cursor-based records.
The following example would illustrate the concept of table-based records. We will be using the CUSTOMERS table we had
created and used in the previous chapters:
DECLARE
customer_rec customers%rowtype;
BEGIN
SELECT * into customer_rec
FROM customers
WHERE id = 5;

dbms_output.put_line('Customer ID: ' || customer_rec.id);


dbms_output.put_line('Customer Name: ' || customer_rec.name);
dbms_output.put_line('Customer Address: ' || customer_rec.address);
dbms_output.put_line('Customer Salary: ' || customer_rec.salary);
END;
/

When the above code is executed at SQL prompt, it produces the following result:

Customer ID: 5
Customer Name: Hardik
Customer Address: Bhopal
Customer Salary: 9000

PL/SQL procedure successfully completed.

Cursor-Based Records
The following example would illustrate the concept of cursor-based records. We will be using the CUSTOMERS table we had
created and used in the previous chapters:
DECLARE
CURSOR customer_cur is
SELECT id, name, address
FROM customers;
customer_rec customer_cur%rowtype;
BEGIN
OPEN customer_cur;
LOOP
FETCH customer_cur into customer_rec;
EXIT WHEN customer_cur%notfound;
DBMS_OUTPUT.put_line(customer_rec.id || ' ' || customer_rec.name);
END LOOP;
END;
/

When the above code is executed at SQL prompt, it produces the following result:

1 Ramesh
2 Khilan
3 kaushik
4 Chaitali
5 Hardik
6 Komal

PL/SQL procedure successfully completed.

User-Defined Records
PL/SQL provides a user-defined record type that allows you to define different record structures. Records consist of different fields.
Suppose you want to keep track of your books in a library. You might want to track the following attributes about each book:

 Title

 Author
 Subject

 Book ID

Defining a Record
The record type is defined as:

TYPE
type_name IS RECORD
( field_name1 datatype1 [NOT NULL] [:= DEFAULT EXPRESSION],
field_name2 datatype2 [NOT NULL] [:= DEFAULT EXPRESSION],
...
field_nameN datatypeN [NOT NULL] [:= DEFAULT EXPRESSION);
record-name type_name;

Here is the way you would declare the Book record:

DECLARE
TYPE books IS RECORD
(title varchar(50),
author varchar(50),
subject varchar(100),
book_id number);
book1 books;
book2 books;

Accessing Fields
To access any field of a record, we use the dot (.) operator. The member access operator is coded as a period between the record
variable name and the field that we wish to access. Following is the example to explain usage of record:

DECLARE
type books is record
(title varchar(50),
author varchar(50),
subject varchar(100),
book_id number);
book1 books;
book2 books;
BEGIN
-- Book 1 specification
book1.title := 'C Programming';
book1.author := 'Nuha Ali ';
book1.subject := 'C Programming Tutorial';
book1.book_id := 6495407;

-- Book 2 specification
book2.title := 'Telecom Billing';
book2.author := 'Zara Ali';
book2.subject := 'Telecom Billing Tutorial';
book2.book_id := 6495700;

-- Print book 1 record


dbms_output.put_line('Book 1 title : '|| book1.title);
dbms_output.put_line('Book 1 author : '|| book1.author);
dbms_output.put_line('Book 1 subject : '|| book1.subject);
dbms_output.put_line('Book 1 book_id : ' || book1.book_id);

-- Print book 2 record


dbms_output.put_line('Book 2 title : '|| book2.title);
dbms_output.put_line('Book 2 author : '|| book2.author);
dbms_output.put_line('Book 2 subject : '|| book2.subject);
dbms_output.put_line('Book 2 book_id : '|| book2.book_id);
END;
/
When the above code is executed at SQL prompt, it produces the following result:

Book 1 title : C Programming


Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700

PL/SQL procedure successfully completed.

Records as Subprogram Parameters


You can pass a record as a subprogram parameter in very similar way as you pass any other variable. You would access the
record fields in the similar way as you have accessed in the above example:

DECLARE
type books is record
(title varchar(50),
author varchar(50),
subject varchar(100),
book_id number);
book1 books;
book2 books;

PROCEDURE printbook (book books) IS


BEGIN
dbms_output.put_line ('Book title : ' || book.title);
dbms_output.put_line('Book author : ' || book.author);
dbms_output.put_line( 'Book subject : ' || book.subject);
dbms_output.put_line( 'Book book_id : ' || book.book_id);
END;

BEGIN
-- Book 1 specification
book1.title := 'C Programming';
book1.author := 'Nuha Ali ';
book1.subject := 'C Programming Tutorial';
book1.book_id := 6495407;

-- Book 2 specification
book2.title := 'Telecom Billing';
book2.author := 'Zara Ali';
book2.subject := 'Telecom Billing Tutorial';
book2.book_id := 6495700;

-- Use procedure to print book info


printbook(book1);
printbook(book2);
END;
/

When the above code is executed at SQL prompt, it produces the following result:

Book title : C Programming


Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

PL/SQL procedure successfully completed.


Example:
The following program provides a more complete package. We will use the CUSTOMERS table stored in our database with the
following records:

Select * from customers;

+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 3000.00 |
| 2 | Khilan | 25 | Delhi | 3000.00 |
| 3 | kaushik | 23 | Kota | 3000.00 |
| 4 | Chaitali | 25 | Mumbai | 7500.00 |
| 5 | Hardik | 27 | Bhopal | 9500.00 |
| 6 | Komal | 22 | MP | 5500.00 |
+----+----------+-----+-----------+----------+

THE PACKAGE SPECIFICATION:


CREATE OR REPLACE PACKAGE c_package AS
-- Adds a customer
PROCEDURE addCustomer(c_id customers.id%type,
c_name customers.name%type,
c_age customers.age%type,
c_addr customers.address%type,
c_sal customers.salary%type);

-- Removes a customer
PROCEDURE delCustomer(c_id customers.id%TYPE);
--Lists all customers
PROCEDURE listCustomer;

END c_package;
/

When the above code is executed at SQL prompt, it creates the above package and displays following result:

Package created.

CREATING THE PACKAGE BODY:


CREATE OR REPLACE PACKAGE BODY c_package AS
PROCEDURE addCustomer(c_id customers.id%type,
c_name customers.name%type,
c_age customers.age%type,
c_addr customers.address%type,
c_sal customers.salary%type)
IS
BEGIN
INSERT INTO customers (id,name,age,address,salary)
VALUES(c_id, c_name, c_age, c_addr, c_sal);
END addCustomer;

PROCEDURE delCustomer(c_id customers.id%type) IS


BEGIN
DELETE FROM customers
WHERE id = c_id;
END delCustomer;

PROCEDURE listCustomer IS
CURSOR c_customers is
SELECT name FROM customers;
TYPE c_list is TABLE OF customers.name%type;
name_list c_list := c_list();
counter integer :=0;
BEGIN
FOR n IN c_customers LOOP
counter := counter +1;
name_list.extend;
name_list(counter) := n.name;
dbms_output.put_line('Customer(' ||counter|| ')'||name_list(counter));
END LOOP;
END listCustomer;
END c_package;
/
Above example makes use of nested table which we will discuss in the next chapter. When the above code is executed at SQL
prompt, it produces following result:
Package body created.

USING THE PACKAGE:


The following program uses the methods declared and defined in the package c_package.
DECLARE
code customers.id%type:= 8;
BEGIN
c_package.addcustomer(7, 'Rajnish', 25, 'Chennai', 3500);
c_package.addcustomer(8, 'Subham', 32, 'Delhi', 7500);
c_package.listcustomer;
c_package.delcustomer(code);
c_package.listcustomer;
END;
/

When the above code is executed at SQL prompt, it produces following result:

Customer(1): Ramesh
Customer(2): Khilan
Customer(3): kaushik
Customer(4): Chaitali
Customer(5): Hardik
Customer(6): Komal
Customer(7): Rajnish
Customer(8): Subham
Customer(1): Ramesh
Customer(2): Khilan
Customer(3): kaushik
Customer(4): Chaitali
Customer(5): Hardik
Customer(6): Komal
Customer(7): Rajnish

PL/SQL procedure successfully completed


SQL DML and DDL
SQL can be divided into two parts: The Data Manipulation Language (DML) and the Data Definition Language
(DDL).

The query and update commands form the DML part of SQL:

 SELECT - extracts data from a database


 UPDATE - updates data in a database
 DELETE - deletes data from a database
 INSERT INTO - inserts new data into a database

The DDL part of SQL permits database tables to be created or deleted. It also defines indexes (keys), specifies
links between tables, and imposes constraints between tables. The most important DDL statements in SQL are:

 CREATE DATABASE - creates a new database


 ALTER DATABASE - modifies a database
 CREATE TABLE - creates a new table
 ALTER TABLE - modifies a table
 DROP TABLE - deletes a table
 CREATE INDEX - creates an index (search key)
 DROP INDEX - deletes an index

The IN Operator
The IN operator allows you to specify multiple values in a WHERE clause.

SQL IN Syntax
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...)

The BETWEEN Operator


The BETWEEN operator selects a range of data between two values. The values can be numbers, text, or dates.

SQL BETWEEN Syntax


SELECT column_name(s)
FROM table_name
WHERE column_name
BETWEEN value1 AND value2

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo


FROM Persons
INNER JOIN Orders
ON Persons.P_Id=Orders.P_Id
ORDER BY Persons.LastName
The result-set will look like this:

LastName FirstName OrderNo

Hansen Ola 22456

Hansen Ola 24562

Pettersen Kari 77895

Pettersen Kari 44678

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo


FROM Persons
LEFT JOIN Orders
ON Persons.P_Id=Orders.P_Id
ORDER BY Persons.LastName

The result-set will look like this:

LastName FirstName OrderNo

Hansen Ola 22456

Hansen Ola 24562

Pettersen Kari 77895

Pettersen Kari 44678

Svendson Tove  

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo


FROM Persons
RIGHT JOIN Orders
ON Persons.P_Id=Orders.P_Id
ORDER BY Persons.LastName

The result-set will look like this:

LastName FirstName OrderNo

Hansen Ola 22456

Hansen Ola 24562

Pettersen Kari 77895

Pettersen Kari 44678

    34764

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo


FROM Persons
FULL JOIN Orders
ON Persons.P_Id=Orders.P_Id
ORDER BY Persons.LastName
The result-set will look like this:

LastName FirstName OrderNo

Hansen Ola 22456

Hansen Ola 24562

Pettersen Kari 77895

Pettersen Kari 44678

Svendson Tove  

    34764

You might also like