DATABASE FOR A CHAIN OF SUPERSTORES - Staff...

39

Transcript of DATABASE FOR A CHAIN OF SUPERSTORES - Staff...

Section 1 Database Description

Our database models a chain of super-stores such as Rajani’s. The management of such a corporation would require the maintenance and handling of information that is beneficial to decision making by the corporation. The chain of superstores that we are modeling wishes to maintain information concerning various products, branches, transactions, and finally, privileged customers. This information is to be managed in a logical fashion and is to be used to determine the prevalent trends in the tastes of the customers, as well as the popularity of the various products and services that the corporation offers. 1.1 Management structure of the enterprise A good example of a chain of superstores is Rajani’s. For the purpose of our project, we chose the Rajani’s chain, due to their rigid and professional management structure, and their willingness to accept and employ new technologies. Currently, the Rajani’s chain uses a semi automated filing system that involves a two step process: • Periodic generation and accumulation of all receipts from all cash registers and

terminals, and • Manual data entry into a central filing system. Management decisions are based

on information gleaned from this filing system. As is obvious, this process can be very tedious, and possesses all the demerits associated with filing systems. Although the initial purpose of our DBMS project was simply the creation of a viable database system, we seized this opportunity to put our database designing knowledge to the test by designing and creating a database model that should form part of any future upgrades to the current Rajani’s system. The database system we have designed only handles information related to storekeeping and privileged customer credit management. It models part of a proposed fully automated information system that would handle all kinds of information necessary for a real company, including economic factors, taxation information, employee records management etc. The proposed database serves to link all the branches by storing the inventory information for each branch in a central database. Both the management and the storekeepers may modify the database, but whereas the management has full access to all data via database queries, the storekeepers have only limited access. Changes to be affected on the database by transactions made at the branches are identified by the storekeepers and then implemented on the centralized database. An additional feature of our project is the provision of support for handling customer credit. Each customer applying for this service is issued a loyalty card, and is identified using a unique customer number. This privileged customer can then use the card at any of Rajani’s outlets for purchasing on credit. The complete information about these purchases is stored in the central database, including particulars of the customer, his entire purchase history, and his credit payment record. This

information is used to determine the trustworthiness of the customer, and decisions regarding extension of credit, or cancellation of membership, etc may be taken. In the next section, we describe all the data fields involved in our model.

Section 2 Data Dictionary

In this section we define all the fields used in our database, and describe their use. We will also discuss the reasoning that led us to deem any field useful or necessary. 2.1 Product code (P_NO) This field serves as a unique identifier for each product available, and may correspond to the bar code of the product, etc. Since each product has its own unique code, this field may be used as a primary key in a relation listing all available products. 2.2 Product Description (P_DESC) This is a text field that describes each product, for e.g. “Aquafresh toothpaste”, “Kashmir Banaspati” etc.

2.3 Selling Price of Product (SELL_P) This field holds the current retail price associated with any product. 2.4 Cost Price of Product (COST_P) This field holds the per unit purchase cost of any product. 2.5 Branch Name (BR_NAME) This field serves as a unique identifier for each branch of Rajani’s. In our database, it is the only attribute of the branch entity, because in order to keep things simple, we have assumed that no two branches will have the same name, and that no other branch particulars are necessary as yet. Of course, as the database expands, more fields may be added, as appropriate.

2.6 Order Code (O_NO) This can either be either a numeric, or an alphanumeric field, as required. It uniquely identifies all retail transactions carried out between any of the store’s branches and its customers. The value of this field may also be understood as a unique identifier printed on each receipt generated by any cash register or terminal at any branch. 2.7 Order Date (ORD_DATE) A date field that is associated with each Order Number; it specifies the date at which any transaction is made between the store and its customers. 2.8 Quantity Ordered (QTY_ORD) In every transaction carried out between the store and its customers, a customer buys at least one or more units of a particular product. This field specifies the quantity of that product, which has a unique product number, which was ordered. Each

QTY_ORD field is therefore associated with its respective P_NO field. As is obvious, this is a numeric field. 2.9 Client Number (CLIENT_NO) This is the unique customer number that is assigned to the privileged customers of the company. This field can either be numeric or alphanumeric, as required. Since this field uniquely identifies each privileged customer, it can be used as a primary key. 2.10 Client Name (NAME) This is a character field that holds a privileged customer’s name. 2.11 Client City (CITY) This is a character field that holds a privileged customer’s city of residence. 2.12 Client Address (ADDRESS) This is a character field that holds a privileged customer’s address. This may be used for home delivery services if such a service is to be provided; or it may be used for mailing promotions etc. 2.13 Member Since (MEM_SINCE) This is a date field that holds the date from which the privileged customer’s membership became valid. Special services, benefits, concessions etc may be provided to the most loyal and trustworthy customers, i.e. the customers that have been members for the longest period and have made their payments on time. 2.14 Credit Remaining (CREDIT_REM) Whenever a customer becomes a privileged customer, an account of credit is created and is associated to his or her customer number. Every time the customer makes a purchase using his loyalty card, the value of that purchase is deducted from the remaining credit in his credit account. The Credit Remaining field is a numeric field that holds the amount of remaining credit for any particular customer. 2.15 Account Status (SUSPENDED) This is a logical field that holds the status of the Credit Account of any privileged customer. If the purchases of a customer exceed his allotted credit limit, or if his membership is cancelled, this field is set to ‘YES’, else this field holds ‘NO’, i.e. for active members. 2.16 Assigned Credit Return Date (DUE_DATE) All privileged customers may be required to reimburse their used credit periodically, or at previously fixed dates. This date field holds the next date at which the payment has to be done.

2.17 Actual Credit Return Date (PAY_DATE) This date field holds the actual payment date for each privileged customer, as opposed to the assigned payment date. This field, along with the previous one, may be used to determine member trustworthiness, and can be used to decide whether any more credit should be extended to the customer or not, or whether the membership needs to be cancelled etc. 2.18 Quantity Purchased (QTY_PCH) This field and the next two pertain to all transactions carried out between the store and its wholesale suppliers. The Quantity Purchased field is a numeric field that holds the amount of a particular product that is bought from a supplier during one purchase. Thus each QTY_PCH field is associated with its corresponding P_NO field, and is also different for different BR_NAME fields. 2.19 Date of Purchase (DATE) This is another date field that holds the date at which the store purchased an amount of a certain product from its wholesale dealer. The DATE field is stored along with its corresponding QTY_PCH and P_NO fields, in a way so as to maintain the entire history of purchases of a particular product at a particular BR_NAME. This information can be used to determine consumer choices and buying trends over a period of time and in a given area or locality, in order to actively forecast consumer behavior in the next season etc. 2.20 Stock Remaining (QIH) The Stock Remaining, or Quantity In Hand field, stores the number of units of a particular product specified by P_NO, that are currently available in a particular branch. This field is decremented by QTY_ORD each time a purchase of the product P_NO is made at a branch BR_NAME. Every time new stock of an item is purchased from the suppliers, the most recent value of QTY_PCH is added to the QIH.

Section 3 The ER Model

PLACED BY

ORDER

CONTAINS

PURCHASED

CUSTOMER

QUANTITY

PRODUCT BRANCH STOCKED IN

CREDIT REM

ADDRESS

CITY

MEM_SINCE

PAY DATE

DUE_DATE

SUSPENDED

CLIENT_NO

NAME

O_NO 0RD DATE ISSUED

FROM

P_NO

P_DESC SELL_P

COST_P QIH

QTY_PCH

BR_NAME

DATE

Section 4 The Relational Model

In this section, we convert the ER model into the relational model, which is significantly easier to use when describing queries. Using the rules of table formation, the following tables can be derived from the ER diagram. The attributes in red represent the primary key of the corresponding table while the attributes in blue are the foreign keys. PRODUCT (P_NO, P_DESC, SELL_P, COST_P) CUSTOMERS (CLIENT_NO, NAME, CITY, ADDRESS, MEM_SINCE, CREDIT_REM, SUSPENDED, DUE_DATE, PAY_DATE) ORDER (O_NO, BR_NAME, ORD_DATE) BRANCH (BR_NAME) PURCHASE (P_NO, BR_NAME, DATE, QTY_PCH) ORDER_PRODUCT (O_NO, P_NO, QTY_ORD) ORDER_CLIENT (O_NO, CLIENT_NO) BRANCH_QUANTITY (P_NO, BR_NAME, QIH) All the tables above are in the ‘Third Normal Form’ (3NF) except the CUSTOMERS relation, which is in ‘First Normal Form’ (1NF), due to the existence of partial dependencies as shown: CUSTOMERS CLIENT_NO, DUE_DATE, NAME, CITY, ADDRESS, MEM_SINCE, CREDIT_REM, SUSPENDED, PAY_DATE Converting to 2NF results in the following two relations: CUSTOMERS (CLIENT_NO, NAME, CITY, ADDRESS, MEM_SINCE, CREDIT_REM, SUSPENDED) CREDIT_INFO (CLIENT_NO, DUE_DATE, PAY_DATE) Since there are no transitive dependencies, the above tables are also in 3NF.

Section 5 Integrity Constraints

In this section we discuss in detail all forms of constraints that apply to our database. We start by discussing Domain and Referential Integrity constraints, followed by a description of assertions and Triggers. 5.1 Domain Constraints Domain constraints are the most elementary type of integrity constraints. They deal with basic limits or conditions that need to be enforced on certain fields. Below is a list of the domain constraints that apply on our database. 1. The cost price and selling price of a product should be greater than zero. 2. Credit remaining for a customer should not fall below a fixed minimum. This

was proposed as a means of maintaining customer loyalty, as well as reducing the risk of credit misuse. For example if the customer is allotted a credit limit of Rs 1000 for one month, he or she may make purchases at the store of value no greater than Rs 900. Thus Rs 100 is set as the minimum value for credit remaining. The customer will not be able to use this remaining credit until he reimburses the spent Rs 900, before the end of the month. The thought of useable credit remaining may provide an inclination to customers to pay up their dues.

3. Quantity purchased for a product should be greater than zero. 4. Quantity ordered for a product in any order should be greater than zero. 5. Product number for an order cannot be NULL. 6. Quantity in stock should be greater than or equal to zero. Apart from no. 2, all the domain constraints were trivial. 5.2 Referential Integrity Constraints Referential integrity constraints help to ensure that a value that appears in one relation for a given set of attributes, also appears for a certain set of attributes in another relation. They are generally used to prevent inconsistencies in the database. 1. P_NO in any order placed should belong to PRODUCTS. This means that no

customer can possibly order a product that is not available at a branch or store. 2. CLIENT_NO should belong to CUSTOMERS. A client being referred to should

exist in the store’s database before that client makes any purchase on credit. 3. P_NO in any purchase should belong to PRODUCTS. This constraint states that

before a quantity of any new product is added to the store’s inventory, it must first be present in the PRODUCTS table.

4. BR_NAME of purchase or ORDER should belong to BRANCH. Every transaction made by the store, either with a customer, or with a supplier, should have a valid branch associated with it.

5.3 Assertions An assertion is a predicate expressing a condition that we wish the database to always satisfy. 1. The QTY_ORD should be less than or equal to the QIH, (Quantity in hand). 2. SELL_P must be greater than COST_P. We have assumed no special cases.

3. A client cannot purchase on credit if he is suspended. 4. A client cannot purchase on credit when his credit reaches a certain minimum

limit.

5.4 Triggers A Trigger is a statement that is executed automatically by the system as a side effect of a modification to the database. Below we specify the conditions under which the triggers are to be executed, along with the actions to be performed when the trigger executes. 1. Condition: when a client’s credit becomes less than or equal to the minimum

limit; Action: account suspension.

2. Condition: when a client’s DUE_DATE for reimbursement falls behind the current date and the PAY_DATE is still NULL i.e. the payment has not been made; Action: account suspension.

3. Condition: when a new client is registered; Action: the first PAY_DATE is automatically entered as well as DUE_DATE as the current date (dummy value).

4. Condition: when PAY_DATE is entered. Action: next DUE_DATE is calculated automatically.

5. Condition: when a client conducts a transaction; Action: the amount is deducted from his CREDIT_REM (credit remaining).

6. Condition: when a new purchase is made from the supplier; Action: the QTY_PCH is added to QIH. Note: If there is no entry for a particular product at a given branch, i.e. the specified {P_NO, BR_NAME} combination is not present in the BRANCH_QUANTITY relation, a new tuple is created in it.

7. Condition: when a transaction is made at a branch; Action: the QTY_ORD is deducted from QIH.

Section 6 Queries and Explanations

In this section we list and describe the queries that we expected would be most useful for a database of this type. The actual implementations of these queries appear in the appendix. 6.1 The most/least sold product(s), within a given period at a given branch This query may be used to identify any given number of the most or least sold product or products in a given branch during a certain time period. If the branch is not specified, then the query takes into account quantity sold at all branches. Similarly, the starting and ending dates may or may not be specified. This query might help the store management ascertain the relative popularity of products in different seasons, and thus maintain the stock accurately when the season returns. This query uses the PRODUCT, ORDER_PRODUCT, and ORDER relations and will output the following values for each product.

P_NO P_DESC Sold Profit Profit is calculated by this formula:

Profit = (SELL_P – COST_P) * QTY_ORD 6.2 The product(s) with the Most/Least profit margin This query identifies any given number of the products with the largest, or smallest, difference between cost price and selling price. The PRODUCT relation is used and the following fields are displayed:

P_NO P_DESC Margin Margin is given by the equation:

Margin = SELL_P – COST_P This information may be used to decide which products need to be marketed more aggressively relative to others. Marketing a higher margin product aggressively can generate higher profits.

6.3 The Most/Least profitable product(s) within a given period at a given branch

This query determines any given number of most or least profitable product or products in a given branch during a certain time period. If the branch is not specified, then the query takes into account quantity sold at all branches. Similarly, the starting and ending dates may or may not be specified. This might help the store management ascertain the relative profitability of products in different seasons. This query uses the PRODUCT, ORDER_PRODUCT, and ORDER relations and will output the following values for each product:

P_NO P_DESC Sold Profit This query is similar to the first, but sorts in order of profit instead of quantity sold. 6.4 The branch(s) with the most/least revenue within a given period This query lists the branches in order of the total revenue at that branch. The starting and ending dates may or may not be specified. The output fields are:

BR_NAME Revenue Revenue is the net amount of cash received by a branch. This query uses the PRODUCT, ORDER_PRODUCT, and ORDER relations. 6.5 The branch(s) with the most/least profit within a given period This query lists the branches in order of the total profit at that branch. The starting and ending dates may or may not be specified. The output fields are:

BR_NAME Profit Profit is the Revenue, minus the cost of all items sold. This query uses the PRODUCT, ORDER_PRODUCT, and ORDER relations. 6.6 The branch(s) with the most/least transactions within a given period This query lists the branches in order of the total transactions at that branch. The starting and ending dates may or may not be specified. The output fields are:

BR_NAME No. of Transactions This query uses the ORDER relation. 6.7 Transactions made by client(s) This query deals with information relating to the privileged customers. The query lists the worth of purchases within a time period for a particular customer or group of customers. Information can be requested by using the CLIENT_NO field for a single

client, by specifying all active or suspended clients, or for all clients. This query uses the ORDER_INFO, ORDER_CLIENT, ORDER_PRODUCT, and PRODUCT relations, and output the following fields.

CLIENT_NO CIENT_NAME No of Transactions Worth The other part of the query lists the summary of all transactions carried out and outputs the following fields:

P_NO Quantity Ordered 6.8 Members with late payment history

This query lists all the clients that have not reimbursed their extended credit on time. It utilizes information from the CREDIT_INFO table. The output fields are these:

CLIENT_NO DUE_DATE PAY_DATE 6.9 Members with good payment history

This query is very similar to the one above. It lists all those clients who have a very reliable record, and always reimburse their extended credit on time. It too utilizes information from the CREDIT_INFO table. The output fields are these:

CLIENT_NO DUE_DATE PAY_DATE 6.10 All the purchases that are done within a period at a given branch

This query lists all products purchased at a branch during a period of time, along with their quantity purchased. The query uses the PURCHASE relation and the output fields are as follows:

P_NO BR_NAME DATE QTY_ PCH

APPENDIX A.1 The most/least sold product(s), within a given period at a given branch DECLARE NUM NUMBER(7); DATES_INCORRECT EXCEPTION; NUMBER_INCORRECT EXCEPTION; ENTER_BRANCHNAME EXCEPTION; CURSOR C1 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE BR_NAME=BRANCH AND ORD_DATE BETWEEN DATE1 AND DATE2) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 3 DESC; CURSOR C2 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE BR_NAME=BRANCH AND ORD_DATE BETWEEN DATE1 AND DATE2) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 3; CURSOR C3 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE ORD_DATE BETWEEN DATE1 AND DATE2) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 3 DESC; CURSOR C4 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE ORD_DATE BETWEEN DATE1 AND DATE2) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 3; CURSOR C5 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO

AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 3 DESC; CURSOR C6 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 3; CURSOR C7 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE BR_NAME=BRANCH) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 3 DESC; CURSOR C8 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE BR_NAME=BRANCH) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 3; BEGIN NUM := :QUERY1.NUMBERS; IF :QUERY1.DATE1> :QUERY1.DATE2 AND CHECKBOX_CHECKED('QUERY1.CHECK_BOX1')THEN RAISE DATES_INCORRECT; END IF; IF :QUERY1.NUMBERS <= 0 THEN RAISE NUMBER_INCORRECT; END IF; IF :QUERY1.BRANCHNAME = '' AND CHECKBOX_CHECKED('QUERY1.CHECK_BOX2') THEN RAISE ENTER_BRANCHNAME; END IF; GO_BLOCK('PRODUCT_DESC'); CLEAR_BLOCK(NO_VALIDATE); FIRST_RECORD; IF CHECKBOX_CHECKED('QUERY1.CHECK_BOX1') AND CHECKBOX_CHECKED('QUERY1.CHECK_BOX2') AND :QUERY1.RADIOGROUP2 = 1 THEN OPEN C1(:QUERY1.DATE1, :QUERY1.DATE2, :QUERY1.BRANCHNAME); LOOP FETCH C1 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C1%NOTFOUND; EXIT WHEN C1%ROWCOUNT = NUM; NEXT_RECORD;

END LOOP; CLOSE C1; END IF; IF CHECKBOX_CHECKED('QUERY1.CHECK_BOX1') AND CHECKBOX_CHECKED('QUERY1.CHECK_BOX2') AND :QUERY1.RADIOGROUP2 = 2 THEN OPEN C2(:QUERY1.DATE1, :QUERY1.DATE2, :QUERY1.BRANCHNAME); LOOP FETCH C2 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C2%NOTFOUND; EXIT WHEN C2%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C2; END IF; IF CHECKBOX_CHECKED('QUERY1.CHECK_BOX1') AND NOT(CHECKBOX_CHECKED('QUERY1.CHECK_BOX2')) AND :QUERY1.RADIOGROUP2 = 1 THEN OPEN C3(:QUERY1.DATE1, :QUERY1.DATE2, :QUERY1.BRANCHNAME); LOOP FETCH C3 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C3%NOTFOUND; EXIT WHEN C3%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C3; END IF; IF CHECKBOX_CHECKED('QUERY1.CHECK_BOX1') AND NOT(CHECKBOX_CHECKED('QUERY1.CHECK_BOX2')) AND :QUERY1.RADIOGROUP2 = 2 THEN OPEN C4(:QUERY1.DATE1, :QUERY1.DATE2, :QUERY1.BRANCHNAME); LOOP FETCH C4 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C4%NOTFOUND; EXIT WHEN C4%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C4; END IF; IF NOT(CHECKBOX_CHECKED('QUERY1.CHECK_BOX1')) AND NOT(CHECKBOX_CHECKED('QUERY1.CHECK_BOX2')) AND :QUERY1.RADIOGROUP2 = 1 THEN OPEN C5(:QUERY1.DATE1, :QUERY1.DATE2, :QUERY1.BRANCHNAME); LOOP FETCH C5 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C5%NOTFOUND; EXIT WHEN C5%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C5; END IF;

IF NOT(CHECKBOX_CHECKED('QUERY1.CHECK_BOX1')) AND NOT(CHECKBOX_CHECKED('QUERY1.CHECK_BOX2')) AND :QUERY1.RADIOGROUP2 = 2 THEN OPEN C6(:QUERY1.DATE1, :QUERY1.DATE2, :QUERY1.BRANCHNAME); LOOP FETCH C6 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C6%NOTFOUND; EXIT WHEN C6%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C6; END IF; IF NOT(CHECKBOX_CHECKED('QUERY1.CHECK_BOX1')) AND CHECKBOX_CHECKED('QUERY1.CHECK_BOX2') AND :QUERY1.RADIOGROUP2 = 1 THEN OPEN C7(:QUERY1.DATE1, :QUERY1.DATE2, :QUERY1.BRANCHNAME); LOOP FETCH C7 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C7%NOTFOUND; EXIT WHEN C7%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C7; END IF; IF NOT(CHECKBOX_CHECKED('QUERY1.CHECK_BOX1')) AND CHECKBOX_CHECKED('QUERY1.CHECK_BOX2') AND :QUERY1.RADIOGROUP2 = 2 THEN OPEN C8(:QUERY1.DATE1, :QUERY1.DATE2, :QUERY1.BRANCHNAME); LOOP FETCH C8 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C8%NOTFOUND; EXIT WHEN C8%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C8; END IF; EXCEPTION WHEN DATES_INCORRECT THEN MESSAGE('Dates should be properly entered'); WHEN NUMBER_INCORRECT THEN MESSAGE ('Number should be greater than zero'); WHEN ENTER_BRANCHNAME THEN MESSAGE ('Please Select a branch'); END; A.2 The product(s) with the Most/Least profit margin DECLARE CURSOR C1 IS SELECT P_NO, P_DESC, (SELL_P-COST_P) FROM SCOTT.PRODUCT_DESC ORDER BY (SELL_P-COST_P) DESC; BEGIN GO_BLOCK('QUERY2RES');

OPEN C1; LOOP FETCH C1 INTO :QUERY2RES.P_NO, :QUERY2RES.P_DESC, :QUERY2RES.MARGIN; EXIT WHEN C1%NOTFOUND; NEXT_RECORD; END LOOP; END; A.3 The Most/Least profitable product(s) within a given period at a given

branch DECLARE NUM NUMBER(7); DATES_INCORRECT EXCEPTION; NUMBER_INCORRECT EXCEPTION; ENTER_BRANCHNAME EXCEPTION; CURSOR C1 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE BR_NAME=BRANCH AND ORD_DATE BETWEEN DATE1 AND DATE2) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 4 DESC; CURSOR C2 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE BR_NAME=BRANCH AND ORD_DATE BETWEEN DATE1 AND DATE2) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 4; CURSOR C3 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE ORD_DATE BETWEEN DATE1 AND DATE2) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 4 DESC; CURSOR C4 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO

WHERE ORD_DATE BETWEEN DATE1 AND DATE2) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 4; CURSOR C5 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 4 DESC; CURSOR C6 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 4; CURSOR C7 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE BR_NAME=BRANCH) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 4 DESC; CURSOR C8 (DATE1 DATE, DATE2 DATE, BRANCH VARCHAR2)IS SELECT ORDER_PRODUCT.P_NO, P_DESC, SUM(QTY_ORD), SUM(QTY_ORD)*(SELL_P-COST_P) FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC WHERE STORE.ORDER_PRODUCT.P_NO = SCOTT.PRODUCT_DESC.P_NO AND O_NO IN (SELECT O_NO FROM STORE.ORDER_INFO WHERE BR_NAME=BRANCH) GROUP BY STORE.ORDER_PRODUCT.P_NO, P_DESC, (SELL_P-COST_P) ORDER BY 4; BEGIN NUM := :QUERY3.NUMBERS; IF :QUERY3.DATE1> :QUERY3.DATE2 AND CHECKBOX_CHECKED('QUERY3.CHECK_BOX1')THEN RAISE DATES_INCORRECT; END IF; IF :QUERY3.NUMBERS <= 0 THEN RAISE NUMBER_INCORRECT; END IF; IF :QUERY3.BRANCHNAME = '' AND CHECKBOX_CHECKED('QUERY3.CHECK_BOX2') THEN RAISE ENTER_BRANCHNAME; END IF; GO_BLOCK('PRODUCT_PROFIT'); CLEAR_BLOCK(NO_VALIDATE); FIRST_RECORD;

IF CHECKBOX_CHECKED('QUERY3.CHECK_BOX1') AND CHECKBOX_CHECKED('QUERY3.CHECK_BOX2') AND :QUERY3.RADIOGROUP2 = 1 THEN OPEN C1(:QUERY3.DATE1, :QUERY3.DATE2, :QUERY3.BRANCHNAME); LOOP FETCH C1 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C1%NOTFOUND; EXIT WHEN C1%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C1; END IF; IF CHECKBOX_CHECKED('QUERY3.CHECK_BOX1') AND CHECKBOX_CHECKED('QUERY3.CHECK_BOX2') AND :QUERY3.RADIOGROUP2 = 2 THEN OPEN C2(:QUERY3.DATE1, :QUERY3.DATE2, :QUERY3.BRANCHNAME); LOOP FETCH C2 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C2%NOTFOUND; EXIT WHEN C2%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C2; END IF; IF CHECKBOX_CHECKED('QUERY3.CHECK_BOX1') AND NOT(CHECKBOX_CHECKED('QUERY3.CHECK_BOX2')) AND :QUERY3.RADIOGROUP2 = 1 THEN OPEN C3(:QUERY3.DATE1, :QUERY3.DATE2, :QUERY3.BRANCHNAME); LOOP FETCH C3 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C3%NOTFOUND; EXIT WHEN C3%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C3; END IF; IF CHECKBOX_CHECKED('QUERY3.CHECK_BOX1') AND NOT(CHECKBOX_CHECKED('QUERY3.CHECK_BOX2')) AND :QUERY3.RADIOGROUP2 = 2 THEN OPEN C4(:QUERY3.DATE1, :QUERY3.DATE2, :QUERY3.BRANCHNAME); LOOP FETCH C4 INTO :PRODUCT_DESC.P_NO, :PRODUCT_DESC.P_DESC, :PRODUCT_DESC.QUANTITY, :PRODUCT_DESC.PROFIT; EXIT WHEN C4%NOTFOUND; EXIT WHEN C4%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C4; END IF; IF NOT(CHECKBOX_CHECKED('QUERY3.CHECK_BOX1')) AND NOT(CHECKBOX_CHECKED('QUERY3.CHECK_BOX2')) AND :QUERY3.RADIOGROUP2 = 1 THEN OPEN C5(:QUERY3.DATE1, :QUERY3.DATE2, :QUERY3.BRANCHNAME); LOOP

FETCH C5 INTO :PRODUCT_PROFIT.P_NO, :PRODUCT_PROFIT.P_DESC, :PRODUCT_PROFIT.QUANTITY, :PRODUCT_PROFIT.PROFIT; EXIT WHEN C5%NOTFOUND; EXIT WHEN C5%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C5; END IF; IF NOT(CHECKBOX_CHECKED('QUERY3.CHECK_BOX1')) AND NOT(CHECKBOX_CHECKED('QUERY3.CHECK_BOX2')) AND :QUERY3.RADIOGROUP2 = 2 THEN OPEN C6(:QUERY3.DATE1, :QUERY3.DATE2, :QUERY3.BRANCHNAME); LOOP FETCH C6 INTO :PRODUCT_PROFIT.P_NO, :PRODUCT_PROFIT.P_DESC, :PRODUCT_PROFIT.QUANTITY, :PRODUCT_PROFIT.PROFIT; EXIT WHEN C6%NOTFOUND; EXIT WHEN C6%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C6; END IF; IF NOT(CHECKBOX_CHECKED('QUERY3.CHECK_BOX1')) AND CHECKBOX_CHECKED('QUERY3.CHECK_BOX2') AND :QUERY3.RADIOGROUP2 = 1 THEN OPEN C7(:QUERY3.DATE1, :QUERY3.DATE2, :QUERY3.BRANCHNAME); LOOP FETCH C7 INTO :PRODUCT_PROFIT.P_NO, :PRODUCT_PROFIT.P_DESC, :PRODUCT_PROFIT.QUANTITY, :PRODUCT_PROFIT.PROFIT; EXIT WHEN C7%NOTFOUND; EXIT WHEN C7%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C7; END IF; IF NOT(CHECKBOX_CHECKED('QUERY3.CHECK_BOX1')) AND CHECKBOX_CHECKED('QUERY3.CHECK_BOX2') AND :QUERY3.RADIOGROUP2 = 2 THEN OPEN C8(:QUERY3.DATE1, :QUERY3.DATE2, :QUERY3.BRANCHNAME); LOOP FETCH C8 INTO :PRODUCT_PROFIT.P_NO, :PRODUCT_PROFIT.P_DESC, :PRODUCT_PROFIT.QUANTITY, :PRODUCT_PROFIT.PROFIT; EXIT WHEN C8%NOTFOUND; EXIT WHEN C8%ROWCOUNT = NUM; NEXT_RECORD; END LOOP; CLOSE C8; END IF; EXCEPTION WHEN DATES_INCORRECT THEN MESSAGE('Dates should be properly entered'); WHEN NUMBER_INCORRECT THEN MESSAGE ('Number should be greater than zero'); WHEN ENTER_BRANCHNAME THEN MESSAGE ('Please Select a branch'); END;

A.4 The branch(s) with the most/least revenue within a given period DECLARE NUM NUMBER(7); DATES_INCORRECT EXCEPTION; CURSOR C1 (DATE1 DATE, DATE2 DATE) IS SELECT BR_NAME, SUM(QTY_ORD*SELL_P)"REVENUE" FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC, STORE.ORDER_INFO WHERE STORE.ORDER_INFO.O_NO=STORE.ORDER_PRODUCT.O_NO AND STORE.ORDER_PRODUCT.P_NO=SCOTT.PRODUCT_DESC.P_NO AND ORD_DATE BETWEEN DATE1 AND DATE2 GROUP BY BR_NAME ORDER BY 2 DESC; CURSOR C2 (DATE1 DATE, DATE2 DATE) IS SELECT BR_NAME, SUM(QTY_ORD*SELL_P)"REVENUE" FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC, STORE.ORDER_INFO WHERE STORE.ORDER_INFO.O_NO=STORE.ORDER_PRODUCT.O_NO AND STORE.ORDER_PRODUCT.P_NO=SCOTT.PRODUCT_DESC.P_NO AND ORD_DATE BETWEEN DATE1 AND DATE2 GROUP BY BR_NAME ORDER BY 2; CURSOR C3 IS SELECT BR_NAME, SUM(QTY_ORD*SELL_P)"REVENUE" FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC, STORE.ORDER_INFO WHERE STORE.ORDER_INFO.O_NO=STORE.ORDER_PRODUCT.O_NO AND STORE.ORDER_PRODUCT.P_NO=SCOTT.PRODUCT_DESC.P_NO GROUP BY BR_NAME ORDER BY 2 DESC; CURSOR C4 IS SELECT BR_NAME, SUM(QTY_ORD*SELL_P)"REVENUE" FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC, STORE.ORDER_INFO WHERE STORE.ORDER_INFO.O_NO=STORE.ORDER_PRODUCT.O_NO AND STORE.ORDER_PRODUCT.P_NO=SCOTT.PRODUCT_DESC.P_NO GROUP BY BR_NAME ORDER BY 2; BEGIN IF :QUERY4.DATE1> :QUERY4.DATE2 AND CHECKBOX_CHECKED('QUERY4.CHECK_BOX1')THEN RAISE DATES_INCORRECT; END IF; GO_BLOCK('QUERY4RES'); CLEAR_BLOCK(NO_VALIDATE); FIRST_RECORD; IF CHECKBOX_CHECKED('QUERY4.CHECK_BOX1') AND :QUERY4.RADIOGROUP2 = 1 THEN OPEN C1(:QUERY4.DATE1, :QUERY4.DATE2); LOOP FETCH C1 INTO :QUERY4RES.BRANCH, :QUERY4RES.REVENUE; EXIT WHEN C1%NOTFOUND;

NEXT_RECORD; END LOOP; CLOSE C1; END IF; IF CHECKBOX_CHECKED('QUERY4.CHECK_BOX1') AND :QUERY4.RADIOGROUP2 = 2 THEN OPEN C2(:QUERY4.DATE1, :QUERY4.DATE2); LOOP FETCH C2 INTO :QUERY4RES.BRANCH, :QUERY4RES.REVENUE; EXIT WHEN C2%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C2; END IF; IF NOT(CHECKBOX_CHECKED('QUERY4.CHECK_BOX1')) AND :QUERY4.RADIOGROUP2 = 1 THEN OPEN C3; LOOP FETCH C3 INTO :QUERY4RES.BRANCH, :QUERY4RES.REVENUE; EXIT WHEN C3%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C3; END IF; IF NOT(CHECKBOX_CHECKED('QUERY4.CHECK_BOX1')) AND :QUERY4.RADIOGROUP2 = 2 THEN OPEN C4; LOOP FETCH C4 INTO :QUERY4RES.BRANCH, :QUERY4RES.REVENUE; EXIT WHEN C4%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C4; END IF; EXCEPTION WHEN DATES_INCORRECT THEN MESSAGE('Dates should be properly entered'); END; A.5 The branch(s) with the most/least profit within a given period DECLARE NUM NUMBER(7); DATES_INCORRECT EXCEPTION; CURSOR C1 (DATE1 DATE, DATE2 DATE) IS SELECT BR_NAME, SUM(QTY_ORD*(SELL_P-COST_P))"PROFIT" FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC, STORE.ORDER_INFO WHERE ORDER_INFO.O_NO=ORDER_PRODUCT.O_NO AND ORDER_PRODUCT.P_NO=PRODUCT_DESC.P_NO AND ORD_DATE BETWEEN DATE1 AND DATE2 GROUP BY BR_NAME ORDER BY 2 DESC;

CURSOR C2 (DATE1 DATE, DATE2 DATE) IS SELECT BR_NAME, SUM(QTY_ORD*(SELL_P-COST_P))"PROFIT" FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC, STORE.ORDER_INFO WHERE ORDER_INFO.O_NO=ORDER_PRODUCT.O_NO AND ORDER_PRODUCT.P_NO=PRODUCT_DESC.P_NO AND ORD_DATE BETWEEN DATE1 AND DATE2 GROUP BY BR_NAME ORDER BY 2; CURSOR C3 IS SELECT BR_NAME, SUM(QTY_ORD*(SELL_P-COST_P))"PROFIT" FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC, STORE.ORDER_INFO WHERE ORDER_INFO.O_NO=ORDER_PRODUCT.O_NO AND ORDER_PRODUCT.P_NO=PRODUCT_DESC.P_NO GROUP BY BR_NAME ORDER BY 2 DESC; CURSOR C4 IS SELECT BR_NAME, SUM(QTY_ORD*(SELL_P-COST_P))"PROFIT" FROM STORE.ORDER_PRODUCT, SCOTT.PRODUCT_DESC, STORE.ORDER_INFO WHERE ORDER_INFO.O_NO=ORDER_PRODUCT.O_NO AND ORDER_PRODUCT.P_NO=PRODUCT_DESC.P_NO GROUP BY BR_NAME ORDER BY 2; BEGIN IF :QUERY5.DATE1> :QUERY5.DATE2 AND CHECKBOX_CHECKED('QUERY5.CHECK_BOX1')THEN RAISE DATES_INCORRECT; END IF; GO_BLOCK('QUERY5RES'); CLEAR_BLOCK(NO_VALIDATE); FIRST_RECORD; IF CHECKBOX_CHECKED('QUERY5.CHECK_BOX1') AND :QUERY5.RADIOGROUP2 = 1 THEN OPEN C1(:QUERY5.DATE1, :QUERY5.DATE2); LOOP FETCH C1 INTO :QUERY5RES.BRANCH, :QUERY5RES.PROFIT; EXIT WHEN C1%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C1; END IF; IF CHECKBOX_CHECKED('QUERY5.CHECK_BOX1') AND :QUERY5.RADIOGROUP2 = 2 THEN OPEN C2(:QUERY5.DATE1, :QUERY5.DATE2); LOOP FETCH C2 INTO :QUERY5RES.BRANCH, :QUERY5RES.PROFIT; EXIT WHEN C2%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C2; END IF;

IF NOT(CHECKBOX_CHECKED('QUERY5.CHECK_BOX1')) AND :QUERY5.RADIOGROUP2 = 1 THEN OPEN C3; LOOP FETCH C3 INTO :QUERY5RES.BRANCH, :QUERY5RES.PROFIT; EXIT WHEN C3%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C3; END IF; IF NOT(CHECKBOX_CHECKED('QUERY5.CHECK_BOX1')) AND :QUERY5.RADIOGROUP2 = 2 THEN OPEN C4; LOOP FETCH C4 INTO :QUERY5RES.BRANCH, :QUERY5RES.PROFIT; EXIT WHEN C4%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C4; END IF; EXCEPTION WHEN DATES_INCORRECT THEN MESSAGE('Dates should be properly entered'); END; A.6 The branch(s) with the most/least transactions within a given period DECLARE NUM NUMBER(7); DATES_INCORRECT EXCEPTION; CURSOR C1 (DATE1 DATE, DATE2 DATE) IS SELECT BR_NAME, COUNT(O_NO) FROM STORE.ORDER_INFO WHERE ORD_DATE BETWEEN DATE1 AND DATE2 GROUP BY BR_NAME ORDER BY 2 DESC; CURSOR C2 (DATE1 DATE, DATE2 DATE) IS SELECT BR_NAME, COUNT(O_NO) FROM STORE.ORDER_INFO WHERE ORD_DATE BETWEEN DATE1 AND DATE2 GROUP BY BR_NAME ORDER BY 2; CURSOR C3 IS SELECT BR_NAME, COUNT(O_NO) FROM STORE.ORDER_INFO GROUP BY BR_NAME ORDER BY 2 DESC; CURSOR C4 IS SELECT BR_NAME, COUNT(O_NO)

FROM STORE.ORDER_INFO GROUP BY BR_NAME ORDER BY 2; BEGIN IF :QUERY6.DATE1> :QUERY6.DATE2 AND CHECKBOX_CHECKED('QUERY6.CHECK_BOX1')THEN RAISE DATES_INCORRECT; END IF; GO_BLOCK('QUERY6RES'); CLEAR_BLOCK(NO_VALIDATE); FIRST_RECORD; IF CHECKBOX_CHECKED('QUERY6.CHECK_BOX1') AND :QUERY6.RADIOGROUP2 = 1 THEN OPEN C1(:QUERY6.DATE1, :QUERY6.DATE2); LOOP FETCH C1 INTO :QUERY6RES.BRANCH, :QUERY6RES.TRANSACTIONS; EXIT WHEN C1%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C1; END IF; IF CHECKBOX_CHECKED('QUERY6.CHECK_BOX1') AND :QUERY6.RADIOGROUP2 = 2 THEN OPEN C2(:QUERY6.DATE1, :QUERY6.DATE2); LOOP FETCH C2 INTO :QUERY6RES.BRANCH, :QUERY6RES.TRANSACTIONS; EXIT WHEN C2%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C2; END IF; IF NOT(CHECKBOX_CHECKED('QUERY6.CHECK_BOX1')) AND :QUERY6.RADIOGROUP2 = 1 THEN OPEN C3; LOOP FETCH C3 INTO :QUERY6RES.BRANCH, :QUERY6RES.TRANSACTIONS; EXIT WHEN C3%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C3; END IF; IF NOT(CHECKBOX_CHECKED('QUERY6.CHECK_BOX1')) AND :QUERY6.RADIOGROUP2 = 2 THEN OPEN C4; LOOP FETCH C4 INTO :QUERY6RES.BRANCH, :QUERY6RES.TRANSACTIONS; EXIT WHEN C4%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C4; END IF;

EXCEPTION WHEN DATES_INCORRECT THEN MESSAGE('Dates should be properly entered'); END; A.7 Transactions made by client(s) DECLARE NUM NUMBER(7); DATES_INCORRECT EXCEPTION; CURSOR C1 (DATE1 DATE, DATE2 DATE) IS SELECT CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME, COUNT(CREDIT_HOLDERS.CLIENT_NO), SUM(QTY_ORD*SELL_P) FROM STORE.ORDER_INFO, CREDIT_HOLDERS, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT, PRODUCT_DESC WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO AND ORDER_CLIENT.CLIENT_NO=CREDIT_HOLDERS.CLIENT_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_PRODUCT.P_NO = PRODUCT_DESC.P_NO AND ORD_DATE BETWEEN DATE1 AND DATE2 GROUP BY CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME ORDER BY 1; CURSOR C2 IS SELECT CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME, COUNT(CREDIT_HOLDERS.CLIENT_NO), SUM(QTY_ORD*SELL_P) FROM STORE.ORDER_INFO, CREDIT_HOLDERS, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT, PRODUCT_DESC WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO AND ORDER_CLIENT.CLIENT_NO=CREDIT_HOLDERS.CLIENT_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_PRODUCT.P_NO = PRODUCT_DESC.P_NO GROUP BY CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME ORDER BY 1; CURSOR C3 (DATE1 DATE, DATE2 DATE, CLIENT NUMBER) IS SELECT CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME, COUNT(CREDIT_HOLDERS.CLIENT_NO), SUM(QTY_ORD*SELL_P) FROM STORE.ORDER_INFO, CREDIT_HOLDERS, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT, PRODUCT_DESC WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO AND ORDER_CLIENT.CLIENT_NO=CREDIT_HOLDERS.CLIENT_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_PRODUCT.P_NO = PRODUCT_DESC.P_NO AND ORD_DATE BETWEEN DATE1 AND DATE2 AND CREDIT_HOLDERS.CLIENT_NO = CLIENT GROUP BY CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME ORDER BY 1; CURSOR C4 (CLIENT NUMBER) IS SELECT CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME, COUNT(CREDIT_HOLDERS.CLIENT_NO), SUM(QTY_ORD*SELL_P) FROM STORE.ORDER_INFO, CREDIT_HOLDERS, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT, PRODUCT_DESC WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO

AND ORDER_CLIENT.CLIENT_NO=CREDIT_HOLDERS.CLIENT_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_PRODUCT.P_NO = PRODUCT_DESC.P_NO AND CREDIT_HOLDERS.CLIENT_NO = CLIENT GROUP BY CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME ORDER BY 1; CURSOR C5 (DATE1 DATE, DATE2 DATE) IS SELECT CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME, COUNT(CREDIT_HOLDERS.CLIENT_NO), SUM(QTY_ORD*SELL_P) FROM STORE.ORDER_INFO, CREDIT_HOLDERS, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT, PRODUCT_DESC WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO AND ORDER_CLIENT.CLIENT_NO=CREDIT_HOLDERS.CLIENT_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_PRODUCT.P_NO = PRODUCT_DESC.P_NO AND ORD_DATE BETWEEN DATE1 AND DATE2 AND CREDIT_HOLDERS.SUSPENDED = 'NO' GROUP BY CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME ORDER BY 1; CURSOR C6 IS SELECT CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME, COUNT(CREDIT_HOLDERS.CLIENT_NO), SUM(QTY_ORD*SELL_P) FROM STORE.ORDER_INFO, CREDIT_HOLDERS, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT, PRODUCT_DESC WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO AND ORDER_CLIENT.CLIENT_NO=CREDIT_HOLDERS.CLIENT_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_PRODUCT.P_NO = PRODUCT_DESC.P_NO AND CREDIT_HOLDERS.SUSPENDED = 'NO' GROUP BY CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME ORDER BY 1; CURSOR C7 (DATE1 DATE, DATE2 DATE) IS SELECT CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME, COUNT(CREDIT_HOLDERS.CLIENT_NO), SUM(QTY_ORD*SELL_P) FROM STORE.ORDER_INFO, CREDIT_HOLDERS, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT, PRODUCT_DESC WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO AND ORDER_CLIENT.CLIENT_NO=CREDIT_HOLDERS.CLIENT_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_PRODUCT.P_NO = PRODUCT_DESC.P_NO AND ORD_DATE BETWEEN DATE1 AND DATE2 AND CREDIT_HOLDERS.SUSPENDED = 'YES' GROUP BY CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME ORDER BY 1; CURSOR C8 IS SELECT CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME, COUNT(CREDIT_HOLDERS.CLIENT_NO), SUM(QTY_ORD*SELL_P) FROM STORE.ORDER_INFO, CREDIT_HOLDERS, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT, PRODUCT_DESC WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO AND ORDER_CLIENT.CLIENT_NO=CREDIT_HOLDERS.CLIENT_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_PRODUCT.P_NO = PRODUCT_DESC.P_NO AND CREDIT_HOLDERS.SUSPENDED = 'YES' GROUP BY CREDIT_HOLDERS.CLIENT_NO, CREDIT_HOLDERS.CLIENT_NAME ORDER BY 1;

BEGIN IF :QUERY7.DATE1> :QUERY7.DATE2 AND CHECKBOX_CHECKED('QUERY7.CHECK_BOX1')THEN RAISE DATES_INCORRECT; END IF; GO_BLOCK('QUERY7RES'); CLEAR_BLOCK(NO_VALIDATE); FIRST_RECORD; IF CHECKBOX_CHECKED('QUERY7.CHECK_BOX1') AND :QUERY7.RADIO_GROUP = 4 THEN OPEN C1(:QUERY7.DATE1, :QUERY7.DATE2); LOOP FETCH C1 INTO :QUERY7RES.CLIENT_NO, :QUERY7RES.CNAME, :QUERY7RES.TRANSACTIONS, :QUERY7RES.WORTH; EXIT WHEN C1%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C1; FIRST_RECORD; END IF; IF NOT(CHECKBOX_CHECKED('QUERY7.CHECK_BOX1')) AND :QUERY7.RADIO_GROUP = 4 THEN OPEN C2; LOOP FETCH C2 INTO :QUERY7RES.CLIENT_NO, :QUERY7RES.CNAME, :QUERY7RES.TRANSACTIONS, :QUERY7RES.WORTH; EXIT WHEN C2%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C2; FIRST_RECORD; END IF; IF CHECKBOX_CHECKED('QUERY7.CHECK_BOX1') AND :QUERY7.RADIO_GROUP = 1 THEN OPEN C3(:QUERY7.DATE1, :QUERY7.DATE2, :QUERY7.NUM); LOOP FETCH C3 INTO :QUERY7RES.CLIENT_NO, :QUERY7RES.CNAME, :QUERY7RES.TRANSACTIONS, :QUERY7RES.WORTH; EXIT WHEN C3%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C3; FIRST_RECORD; END IF; IF NOT(CHECKBOX_CHECKED('QUERY7.CHECK_BOX1')) AND :QUERY7.RADIO_GROUP = 1 THEN OPEN C4(:QUERY7.NUM); LOOP FETCH C4 INTO :QUERY7RES.CLIENT_NO, :QUERY7RES.CNAME, :QUERY7RES.TRANSACTIONS, :QUERY7RES.WORTH; EXIT WHEN C4%NOTFOUND;

NEXT_RECORD; END LOOP; CLOSE C4; FIRST_RECORD; END IF; IF CHECKBOX_CHECKED('QUERY7.CHECK_BOX1') AND :QUERY7.RADIO_GROUP = 2 THEN OPEN C5(:QUERY7.DATE1, :QUERY7.DATE2); LOOP FETCH C5 INTO :QUERY7RES.CLIENT_NO, :QUERY7RES.CNAME, :QUERY7RES.TRANSACTIONS, :QUERY7RES.WORTH; EXIT WHEN C5%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C5; FIRST_RECORD; END IF; IF NOT(CHECKBOX_CHECKED('QUERY7.CHECK_BOX1')) AND :QUERY7.RADIO_GROUP = 2 THEN OPEN C6; LOOP FETCH C6 INTO :QUERY7RES.CLIENT_NO, :QUERY7RES.CNAME, :QUERY7RES.TRANSACTIONS, :QUERY7RES.WORTH; EXIT WHEN C6%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C6; FIRST_RECORD; END IF; IF CHECKBOX_CHECKED('QUERY7.CHECK_BOX1') AND :QUERY7.RADIO_GROUP = 3 THEN OPEN C7(:QUERY7.DATE1, :QUERY7.DATE2); LOOP FETCH C7 INTO :QUERY7RES.CLIENT_NO, :QUERY7RES.CNAME, :QUERY7RES.TRANSACTIONS, :QUERY7RES.WORTH; EXIT WHEN C5%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C7; FIRST_RECORD; END IF; IF NOT(CHECKBOX_CHECKED('QUERY7.CHECK_BOX1')) AND :QUERY7.RADIO_GROUP = 3 THEN OPEN C8; LOOP FETCH C8 INTO :QUERY7RES.CLIENT_NO, :QUERY7RES.CNAME, :QUERY7RES.TRANSACTIONS, :QUERY7RES.WORTH; EXIT WHEN C8%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C8; FIRST_RECORD; END IF;

EXCEPTION WHEN DATES_INCORRECT THEN MESSAGE('Dates should be properly entered'); END; The second part of this query is DECLARE CURSOR C3 (CLIENT NUMBER) IS SELECT STORE.ORDER_PRODUCT.P_NO, STORE.ORDER_PRODUCT.QTY_ORD FROM STORE.ORDER_INFO, STORE.ORDER_CLIENT, STORE.ORDER_PRODUCT WHERE ORDER_INFO.O_NO=ORDER_CLIENT.O_NO AND ORDER_PRODUCT.O_NO=ORDER_INFO.O_NO AND STORE.ORDER_CLIENT.CLIENT_NO = CLIENT ORDER BY 1 DESC; BEGIN GO_BLOCK('QUERY7RES2'); CLEAR_BLOCK; FIRST_RECORD; OPEN C3(:QUERY7RES.CLIENT_NO); LOOP FETCH C3 INTO :QUERY7RES2.P_NO, :QUERY7RES2.QTY_ORD; EXIT WHEN C3%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C3; END; A.8 Members with late payment history DECLARE CURSOR C1 IS SELECT CLIENT_NO, DUE_DATE, PAY_DATE FROM CREDIT_INFO WHERE DUE_DATE < PAY_DATE; BEGIN GO_BLOCK('QUERY8RES'); CLEAR_BLOCK; FIRST_RECORD; OPEN C1; LOOP FETCH C1 INTO :QUERY8RES.CLIENT_NO, :QUERY8RES.DUEDATE, :QUERY8RES.PAYMENTDATE; EXIT WHEN C1%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C1; END; A.9 Members with good payment history DECLARE CURSOR C1 IS

SELECT CLIENT_NO, DUE_DATE, PAY_DATE FROM CREDIT_INFO WHERE DUE_DATE = PAY_DATE AND CLIENT_NO NOT IN (SELECT CLIENT_NO FROM CREDIT_INFO WHERE DUE_DATE < PAY_DATE); BEGIN GO_BLOCK('QUERY9RES'); CLEAR_BLOCK; FIRST_RECORD; OPEN C1; LOOP FETCH C1 INTO :QUERY9RES.CLIENT_NO, :QUERY9RES.DUEDATE, :QUERY9RES.PAYMENTDATE; EXIT WHEN C1%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C1; END; A.10 All the purchases that are done within a period at a given branch DECLARE DATES_INCORRECT EXCEPTION; CURSOR C1 (DATE1 DATE, DATE2 DATE) IS SELECT P_NO, BR_NAME, PRH_DATE, QTY_PCH FROM PURCHASE_HIST WHERE PRH_DATE BETWEEN DATE1 AND DATE2 ORDER BY 1; BEGIN IF :QUERY10.DATE1 > :QUERY10.DATE2 THEN RAISE DATES_INCORRECT; END IF; GO_BLOCK('QUERY10RES'); CLEAR_BLOCK(NO_VALIDATE); FIRST_RECORD; OPEN C1(:QUERY7.DATE1, :QUERY7.DATE2); LOOP FETCH C1 INTO :QUERY10RES.P_NO, :QUERY10RES.BRANCH, :QUERY10RES.DATE, :QUERY10RES.QUANTITY; EXIT WHEN C1%NOTFOUND; NEXT_RECORD; END LOOP; CLOSE C1; FIRST_RECORD;

EXCEPTION WHEN DATES_INCORRECT THEN MESSAGE('Dates should be properly entered'); END;