Sie sind auf Seite 1von 77

9.3 DECODE and CASE Examples http://etutorials.

org
https://www.1keydata.com
The following sections present a variety of examples illustrating the uses of conditional logic in SQL
statements. Although we recommend that you use the CASE expression rather than the DECODE
function, where feasible we provide both DECODE and CASE versions of each example to help
illustrate the differences between the two approaches.

9.3.1 Result Set Transformations


You may have run into a situation where you are performing aggregations over a finite set of values,
such as days of the week or months of the year, but you want the result set to contain one row with
N columns rather than N rows with two columns. Consider the following query, which aggregates
sales data for each day of the week:

SELECT TO_CHAR(order_dt, 'DAY') day_of_week,

SUM(sale_price) tot_sales

FROM cust_order

WHERE sale_price IS NOT NULL

GROUP BY TO_CHAR(order_dt, 'DAY')

ORDER BY 2 DESC;

DAY_OF_WEEK TOT_SALES

------------ ----------

SUNDAY 396

WEDNESDAY 180
MONDAY 112

FRIDAY 50

SATURDAY 50

In order to transform this result set into a single row with seven columns (one for each day in the
week), you will need to fabricate a column for each day of the week and, within each column, sum
only those records whose order date falls in the desired day. You can do that with DECODE:

SELECT

SUM(DECODE(TO_CHAR (order_dt, 'DAY'), 'SUNDAY ', sale_price, 0)) SUN,

SUM(DECODE(TO_CHAR (order_dt, 'DAY'), 'MONDAY ', sale_price, 0)) MON,

SUM(DECODE(TO_CHAR (order_dt, 'DAY'), 'TUESDAY ', sale_price, 0)) TUE,

SUM(DECODE(TO_CHAR (order_dt, 'DAY'), 'WEDNESDAY', sale_price, 0)) WED,

SUM(DECODE(TO_CHAR (order_dt, 'DAY'), 'THURSDAY ', sale_price, 0)) THU,

SUM(DECODE(TO_CHAR (order_dt, 'DAY'), 'FRIDAY ', sale_price, 0)) FRI,

SUM(DECODE(TO_CHAR (order_dt, 'DAY'), 'SATURDAY ', sale_price, 0)) SAT

FROM cust_order

WHERE sale_price IS NOT NULL;

SUN MON TUE WED THU FRI SAT


--------- --------- --------- --------- --------- --------- ---------

396 112 0 180 0 50 50

Each of the seven columns in the previous query are identical, except for the day being checked by
the DECODE function. For the SUN column, for example, a value of 0 is returned unless an order
was booked on a Sunday, in which case the sale_price column is returned. When the values from
all orders are summed, only Sunday orders are added to the total, which has the effect of summing
all Sunday orders while ignoring orders for all other days of the week. The same logic is used for
Monday, Tuesday, etc., to sum orders for each of the other days.
The CASE version of this query is as follows:

SELECT

SUM(CASE WHEN TO_CHAR(order_dt, 'DAY') = 'SUNDAY '

THEN sale_price ELSE 0 END) SUN,

SUM(CASE WHEN TO_CHAR(order_dt, 'DAY') = 'MONDAY '

THEN sale_price ELSE 0 END) MON,

SUM(CASE WHEN TO_CHAR(order_dt, 'DAY') = 'TUESDAY '

THEN sale_price ELSE 0 END) TUE,

SUM(CASE WHEN TO_CHAR(order_dt, 'DAY') = 'WEDNESDAY'

THEN sale_price ELSE 0 END) WED,

SUM(CASE WHEN TO_CHAR(order_dt, 'DAY') = 'THURSDAY '

THEN sale_price ELSE 0 END) THU,

SUM(CASE WHEN TO_CHAR(order_dt, 'DAY') = 'FRIDAY '


THEN sale_price ELSE 0 END) FRI,

SUM(CASE WHEN TO_CHAR(order_dt, 'DAY') = 'SATURDAY '

THEN sale_price ELSE 0 END) SAT

FROM cust_order

WHERE sale_price IS NOT NULL;

SUN MON TUE WED THU FRI SAT

--------- --------- --------- --------- --------- --------- ---------

396 112 0 180 0 50 50

Obviously, such transformations are only practical when the number of values is relatively small.
Aggregating sales for each weekday or month works fine, but expanding the query to aggregate
sales for each week, with a column for each week, would quickly become tedious.

9.3.2 Selective Function Execution


Imagine you're generating an inventory report. Most of the information resides in your local
database, but a trip across a gateway to an external, non-Oracle database is required to gather
information for parts supplied by Acme Industries. The round trip from your database through the
gateway to the external server and back takes 1.5 seconds on average. There are 10,000 parts in
your database, but only 100 require information via the gateway. You create a user-defined function
called get_resupply_date to retrieve the resupply date for parts supplied by ACME, and include it
in your query:

SELECT s.name supplier_name, p.name part_name, p.part_nbr part_number

p.inventory_qty in_stock, p.resupply_date resupply_date,

my_pkg.get_resupply_date(p.part_nbr) acme_resupply_date
FROM part p INNER JOIN supplier s

ON p.supplier_id = s.supplier_id;

You then include logic in your reporting tool to use the acme_resupply_date instead of
the resupply_date column if the supplier's name is Acme Industries. You kick off the report, sit
back, and wait for the results. And wait. And wait...
Unfortunately, the server is forced to make 10,000 trips across the gateway when only 100 are
required. In these types of situations, it is far more efficient to call the function only when necessary,
instead of always calling the function and discarding the results when not needed:

SELECT s.name supplier_name, p.name part_name, p.part_nbr part_number,

p.inventory_qty in_stock,

DECODE(s.name, 'Acme Industries',

my_pkg.get_resupply_date(p.part_nbr),

p.resupply_date) resupply_date

FROM part p INNER JOIN supplier s

ON p.supplier_id = s.supplier_id;

The DECODE function checks if the supplier name is 'Acme Industries'. If so, it calls the function
to retrieve the resupply date via the gateway; otherwise, it returns the resupply date from the local
part table. The CASE version of this query looks as follows:

SELECT s.name supplier_name, p.name part_name, p.part_nbr part_number,

p.inventory_qty in_stock,

CASE WHEN s.name = 'Acme Industries'


THEN my_pkg.get_resupply_date(p.part_nbr)

ELSE p.resupply_date

END resupply_date

FROM part p INNER JOIN supplier s

ON p.supplier_id = s.supplier_id;

Now the user-defined function is only executed if the supplier is Acme, reducing the query's
execution time drastically. For more information on calling user-defined functions from SQL, see
Chapter 11.

9.3.3 Conditional Update


If your database design includes denormalizations, you may run nightly routines to populate the
denormalized columns. For example, the part table contains the denormalized column status, the
value for which is derived from the inventory_qty and resupply_date columns. To update
the status column, you could run four separate UPDATE statements each night, one for each of
the four possible values for the status column. For example:

UPDATE part SET status = 'INSTOCK'

WHERE inventory_qty > 0;

UPDATE part SET status = 'ENROUTE'

WHERE inventory_qty = 0 AND resupply_date < SYSDATE + 5;

UPDATE part SET status = 'BACKORD'


WHERE inventory_qty = 0 AND resupply_date > SYSDATE + 5;

UPDATE part SET status = 'UNAVAIL'

WHERE inventory_qty = 0 and resupply_date IS NULL;

Given that columns such as inventory_qty and resupply_date are unlikely to be indexed, each
of the four UPDATE statements would require a full table-scan of the part table. By adding
conditional expressions to the statement, however, the four UPDATE statements can be combined,
resulting in a single scan of the part table:

UPDATE part SET status =

DECODE(inventory_qty, 0,

DECODE(resupply_date, NULL, 'UNAVAIL',

DECODE(LEAST(resupply_date, SYSDATE + 5), resupply_date,

'ENROUTE', 'BACKORD')),

'INSTOCK');

The CASE version of this UPDATE is as follows:

UPDATE part SET status =

CASE WHEN inventory_qty > 0 THEN 'INSTOCK'

WHEN resupply_date IS NULL THEN 'UNAVAIL'

WHEN resupply_date < SYSDATE + 5 THEN 'ENROUTE'


WHEN resupply_date > SYSDATE + 5 THEN 'BACKORD'

ELSE 'UNKNOWN' END;

The readability advantage of the CASE expression is especially apparent here, since the DECODE
version requires three nested levels to implement the same conditional logic handled by a single
CASE expression.

9.3.4 Optional Update


In some situations, you may need to modify data only if certain conditions exist. For example, you
have a table that records information such as the total number of orders and the largest order
booked during the current month. Here's the table definition:[2]
[2] For this example, we will ignore the European and North American totals.

describe mtd_orders;

Name Null? Type

----------------------------------------- -------- ------------

TOT_ORDERS NOT NULL NUMBER(7)

TOT_SALE_PRICE NOT NULL NUMBER(11,2)

MAX_SALE_PRICE NOT NULL NUMBER(9,2)

EUROPE_TOT_ORDERS NOT NULL NUMBER(7)

EUROPE_TOT_SALE_PRICE NOT NULL NUMBER(11,2)

EUROPE_MAX_SALE_PRICE NOT NULL NUMBER(9,2)


NORTHAMERICA_TOT_ORDERS NOT NULL NUMBER(7)

NORTHAMERICA_TOT_SALE_PRICE NOT NULL NUMBER(11,2)

NORTHAMERICA_MAX_SALE_PRICE NOT NULL NUMBER(9,2)

Each night, the table is updated with that day's order information. While most of the columns will be
modified each night, the column for the largest order, which is called max_sale_price, will only
change if one of the day's orders exceeds the current value of the column. The following PL/SQL
block shows how this might be accomplished using a procedural language:

DECLARE

tot_ord NUMBER;

tot_price NUMBER;

max_price NUMBER;

prev_max_price NUMBER;

BEGIN

SELECT COUNT(*), SUM(sale_price), MAX(sale_price)

INTO tot_ord, tot_price, max_price

FROM cust_order

WHERE cancelled_dt IS NULL

AND order_dt >= TRUNC(SYSDATE);


UPDATE mtd_orders

SET tot_orders = tot_orders + tot_ord,

tot_sale_price = tot_sale_price + tot_price

RETURNING max_sale_price INTO prev_max_price;

IF max_price > prev_max_price THEN

UPDATE mtd_orders

SET max_sale_price = max_price;

END IF;

END;

After calculating the total number of orders, the aggregate order price, and the maximum order price
for the current day, the tot_orders and tot_sale_price columns of the mtd_orders table are
modified with today's sales data. After the update is complete, the maximum sale price is returned
from mtd_orders so that it can be compared with today's maximum sale price. If
today's max_sale_price exceeds that stored in the mtd_orders table, a second UPDATE
statement is executed to update the field.
Using DECODE or CASE, however, you can update
the tot_orders and tot_sale_price columns and optionally update the max_sale_pricecolumn
in the same UPDATE statement. Additionally, since you now have a single UPDATE statement, you
can aggregate the data from thecust_order table within a subquery and eliminate the need for
PL/SQL:

UPDATE mtd_orders mtdo

SET (mtdo.tot_orders, mtdo.tot_sale_price, mtdo.max_sale_price) =


(SELECT mtdo.tot_orders + day_tot.tot_orders,

mtdo.tot_sale_price + NVL(day_tot.tot_sale_price, 0),

DECODE(GREATEST(mtdo.max_sale_price,

NVL(day_tot.max_sale_price, 0)), mtdo.max_sale_price,

mtdo.max_sale_price, day_tot.max_sale_price)

FROM

(SELECT COUNT(*) tot_orders, SUM(sale_price) tot_sale_price,

MAX(sale_price) max_sale_price

FROM cust_order

WHERE cancelled_dt IS NULL

AND order_dt >= TRUNC(SYSDATE)) day_tot);

In this statement, the max_sale_price column is set equal to itself unless the value returned from
the subquery is greater than the current column value, in which case the column is set to the value
returned from the subquery. The next statement uses CASE to perform the same optional update:

UPDATE mtd_orders mtdo

SET (mtdo.tot_orders, mtdo.tot_sale_price, mtdo.max_sale_price) =

(SELECT mtdo.tot_orders + day_tot.tot_orders,

mtdo.tot_sale_price + day_tot.tot_sale_price,
CASE WHEN day_tot.max_sale_price > mtdo.max_sale_price

THEN day_tot.max_sale_price

ELSE mtdo.max_sale_price END

FROM

(SELECT COUNT(*) tot_orders, SUM(sale_price) tot_sale_price,

MAX(sale_price) max_sale_price

FROM cust_order

WHERE cancelled_dt IS NULL

AND order_dt >= TRUNC(SYSDATE)) day_tot);

One thing to keep in mind when using this approach is that setting a value equal to itself is still seen
as a modification by the database and may trigger an audit record, a new value for
the last_modified_date column, etc.

9.3.5 Selective Aggregation


To expand on the mtd_orders example in the previous section, imagine that you also want to store
total sales for particular regions such as Europe and North America. For the additional six columns,
individual orders will affect one set of columns or the other, but not both. An order will either be for a
European or North American customer, but not for both at the same time. To populate these
columns, you could generate two more update statements, each targeted to a particular region, as
in:

/* Europe buckets */

UPDATE mtd_orders mtdo

SET (mtdo.europe_tot_orders, mtdo.europe_tot_sale_price,


mtdo.europe_max_sale_price) =

(SELECT mtdo.europe_tot_orders + eur_day_tot.tot_orders,

mtdo.europe_tot_sale_price + nvl(eur_day_tot.tot_sale_price, 0),

CASE WHEN eur_day_tot.max_sale_price > mtdo.europe_max_sale_price

THEN eur_day_tot.max_sale_price

ELSE mtdo.europe_max_sale_price END

FROM

(SELECT COUNT(*) tot_orders, SUM(co.sale_price) tot_sale_price,

MAX(co.sale_price) max_sale_price

FROM cust_order co INNER JOIN customer c

ON co.cust_nbr = c.cust_nbr

WHERE co.cancelled_dt IS NULL

AND co.order_dt >= TRUNC(SYSDATE)

AND c.region_id IN

(SELECT region_id FROM region

START WITH name = 'Europe'


CONNECT BY PRIOR region_id = super_region_id)) eur_day_tot);

/* North America buckets */

UPDATE mtd_orders mtdo

SET (mtdo.northamerica_tot_orders, mtdo.northamerica_tot_sale_price,

mtdo.northamerica_max_sale_price) =

(SELECT mtdo.northamerica_tot_orders + na_day_tot.tot_orders,

mtdo.northamerica_tot_sale_price + nvl(na_day_tot.tot_sale_price, 0),

CASE WHEN na_day_tot.max_sale_price > mtdo.northamerica_max_sale_price

THEN na_day_tot.max_sale_price

ELSE mtdo.northamerica_max_sale_price END

FROM

(SELECT COUNT(*) tot_orders, SUM(co.sale_price) tot_sale_price,

MAX(co.sale_price) max_sale_price

FROM cust_order co INNER JOIN customer c

ON co.cust_nbr = c.cust_nbr

WHERE co.cancelled_dt IS NULL


AND co.order_dt >= TRUNC(SYSDATE) - 60

AND c.region_id IN

(SELECT region_id FROM region

START WITH name = 'North America'

CONNECT BY PRIOR region_id = super_region_id)) na_day_tot);

However, why not save yourself a trip through the cust_order table and aggregate the North
American and European totals at the same time? The trick here is to put conditional logic within the
aggregation functions so that only the appropriate rows influence each calculation. This approach is
similar to the example from Section 9.3.1. in that it selectively aggregates data based on data stored
in the table:

UPDATE mtd_orders mtdo

SET (mtdo.northamerica_tot_orders, mtdo.northamerica_tot_sale_price,

mtdo.northamerica_max_sale_price, mtdo.europe_tot_orders,

mtdo.europe_tot_sale_price, mtdo.europe_max_sale_price) =

(SELECT mtdo.northamerica_tot_orders + nvl(day_tot.na_tot_orders, 0),

mtdo.northamerica_tot_sale_price + nvl(day_tot.na_tot_sale_price, 0),

CASE WHEN day_tot.na_max_sale_price > mtdo.northamerica_max_sale_price

THEN day_tot.na_max_sale_price

ELSE mtdo.northamerica_max_sale_price END,


mtdo.europe_tot_orders + nvl(day_tot.eur_tot_orders, 0),

mtdo.europe_tot_sale_price + nvl(day_tot.eur_tot_sale_price, 0),

CASE WHEN day_tot.eur_max_sale_price > mtdo.europe_max_sale_price

THEN day_tot.eur_max_sale_price

ELSE mtdo.europe_max_sale_price END

FROM

(SELECT SUM(CASE WHEN na_regions.region_id IS NOT NULL THEN 1

ELSE 0 END) na_tot_orders,

SUM(CASE WHEN na_regions.region_id IS NOT NULL THEN co.sale_price

ELSE 0 END) na_tot_sale_price,

MAX(CASE WHEN na_regions.region_id IS NOT NULL THEN co.sale_price

ELSE 0 END) na_max_sale_price,

SUM(CASE WHEN eur_regions.region_id IS NOT NULL THEN 1

ELSE 0 END) eur_tot_orders,

SUM(CASE WHEN eur_regions.region_id IS NOT NULL THEN co.sale_price

ELSE 0 END) eur_tot_sale_price,

MAX(CASE WHEN eur_regions.region_id IS NOT NULL THEN co.sale_price


ELSE 0 END) eur_max_sale_price

FROM cust_order co INNER JOIN customer c

ON co.cust_nbr = c.cust_nbr

LEFT OUTER JOIN (SELECT region_id FROM region

START WITH name = 'North America'

CONNECT BY PRIOR region_id = super_region_id) na_regions

ON c.region_id = na_regions.region_id

LEFT OUTER JOIN (SELECT region_id FROM region

START WITH name = 'Europe'

CONNECT BY PRIOR region_id = super_region_id) eur_regions

ON c.region_id = eur_regions.region_id

WHERE co.cancelled_dt IS NULL

AND co.order_dt >= TRUNC(SYSDATE)) day_tot);

This is a fairly robust statement, so let's break it down. Within the day_tot inline view, you are
joining the cust_order table to the customer table, and then outer-joining
from customer.region_id to each of two inline views (na_regions and eur_regions) that
perform hierarchical queries on the region table. Thus, orders from European customers will have a
non-null value for eur_regions.region_id, since the outer join would find a matching row in
the eur_regions inline view. Six aggregations are performed on this result set; three check for a
join against the na_regions inline view (North American orders), and three check for a join against
the eur_regions inline view (European orders). The six aggregations are then used to modify the
six columns in mtd_orders.
This statement could (and should) be combined with the statement from the previous example
(which updated the first three columns) to create an UPDATE statement that touches every column
in the mtd_orders table via one pass through the cust_order table. For data warehouse
applications, where large data sets must be manipulated each night within tight time constraints,
such an approach can often make the difference between success and failure.

9.3.6 Checking for Existence


When evaluating optional one-to-many relationships, there are certain cases where you want to
know whether the relationship is zero or greater than zero without regard for the actual data. For
example, you want to write a report showing each customer along with a flag showing whether the
customer has had any orders in the past five years. Using conditional logic, you can include a
correlated subquery on the cust_order table, check to see if the number of orders exceeds zero,
and then assign either a 'Y' or a 'N' to the column:

SELECT c.cust_nbr cust_nbr, c.name name,

DECODE(0, (SELECT COUNT(*) FROM cust_order co

WHERE co.cust_nbr = c.cust_nbr AND co.cancelled_dt IS NULL

AND co.order_dt > TRUNC(SYSDATE) - (5 * 365)),

'N', 'Y') has_recent_orders

FROM customer c;

CUST_NBR NAME H

---------- ------------------------------ -

1 Cooper Industries Y

2 Emblazon Corp. N
3 Ditech Corp. N

4 Flowtech Inc. Y

5 Gentech Industries Y

6 Spartan Industries N

7 Wallace Labs N

8 Zantech Inc. Y

9 Cardinal Technologies N

10 Flowrite Corp. N

11 Glaven Technologies N

12 Johnson Labs N

13 Kimball Corp. N

14 Madden Industries N

15 Turntech Inc. N

16 Paulson Labs N

17 Evans Supply Corp. N

18 Spalding Medical Inc. N

19 Kendall-Taylor Corp. N
20 Malden Labs N

21 Crimson Medical Inc. N

22 Nichols Industries N

23 Owens-Baxter Corp. N

24 Jackson Medical Inc. N

25 Worcester Technologies N

26 Alpha Technologies Y

27 Phillips Labs N

28 Jaztech Corp. N

29 Madden-Taylor Inc. N

30 Wallace Industries N

Here is the CASE version of the query:

SELECT c.cust_nbr cust_nbr, c.name name,

CASE WHEN EXISTS (SELECT 1 FROM cust_order co

WHERE co.cust_nbr = c.cust_nbr AND co.cancelled_dt IS NULL

AND co.order_dt > TRUNC(SYSDATE) - (5 * 365))


THEN 'Y' ELSE 'N' END has_recent_orders

FROM customer c;

9.3.7 Division by Zero Errors


As a general rule, you should write your code so that unexpected data values are handled gracefully.
One of the more common arithmetic errors is ORA-01476: divisor is equal to zero. Whether the
value is retrieved from a column, passed in via a bind variable, or returned by a function call, always
wrap divisors with DECODE or CASE, as illustrated by the following example:

SELECT p.part_nbr, SYSDATE + (p.inventory_qty /

DECODE(my_pkg.get_daily_part_usage(p.part_nbr), NULL, 1,

0, 1, my_pkg.get_daily_part_usage(p.part_nbr))) anticipated_shortage_dt

FROM part p

WHERE p.inventory_qty > 0;

The DECODE function ensures that the divisor is something other than zero. Here is the CASE
version of the statement:

SELECT p.part_nbr, SYSDATE + (p.inventory_qty /

CASE WHEN my_pkg.get_daily_part_usage(p.part_nbr) > 0

THEN my_pkg.get_daily_part_usage(p.part_nbr)

ELSE 1 END) anticipated_shortage_dt

FROM part p

WHERE p.inventory_qty > 0;


Of course, if you are bothered by the fact that the get_daily_part_usage function is called a
second time for each part that yields a positive response, simply wrap the function call in an inline
view, as in:

SELECT parts.part_nbr, SYSDATE + (parts.inventory_qty /

CASE WHEN parts.daily_part_usage > 0

THEN parts.daily_part_usage

ELSE 1 END) anticipated_shortage_dt

FROM

(SELECT p.part_nbr part_nbr, p.inventory_qty inventory_qty,

my_pkg.get_daily_part_usage(p.part_nbr) daily_part_usage

FROM part p

WHERE p.inventory_qty > 0) parts;

9.3.8 State Transitions


In certain cases, the order in which the values may be changed is constrained as well as the
allowable values for a column. Consider the diagram shown in Figure 9-1, which shows the
allowable state transitions for an order.
Figure 9-1. Order processing state transitions
As you can see, an order currently in the Processing state should only be allowed to move to either
Delayed or Filled. Rather than allowing each application to implement logic to change the state of an
order, write a user-defined function that returns the appropriate state depending on the current state
of the order and the transition type. In this example, two transition types are defined: positive (POS)
and negative (NEG). For example, an order in the Delayed state can make a positive transition to
Processing or a negative transition to Cancelled. If an order is in one of the final states (Rejected,
Cancelled, Shipped), the same state is returned. Here is the DECODE version of the PL/SQL
function:

FUNCTION get_next_order_state(ord_nbr in NUMBER,

trans_type in VARCHAR2 DEFAULT 'POS')

RETURN VARCHAR2 is

next_state VARCHAR2(20) := 'UNKNOWN';

BEGIN

SELECT DECODE(status,

'REJECTED', status,

'CANCELLED', status,

'SHIPPED', status,

'NEW', DECODE(trans_type, 'NEG', 'AWAIT_PAYMENT', 'PROCESSING'),

'AWAIT_PAYMENT', DECODE(trans_type, 'NEG', 'REJECTED', 'PROCESSING'),

'PROCESSING', DECODE(trans_type, 'NEG', 'DELAYED', 'FILLED'),

'DELAYED', DECODE(trans_type, 'NEG', 'CANCELLED', 'PROCESSING'),

'FILLED', DECODE(trans_type, 'POS', 'SHIPPED', 'UNKNOWN'),


'UNKNOWN')

INTO next_state

FROM cust_order

WHERE order_nbr = ord_nbr;

RETURN next_state;

EXCEPTION

WHEN NO_DATA_FOUND THEN

RETURN next_state;

END get_next_order_state;

As of Oracle8i, the PL/SQL language does not include the CASE expression in its grammar, so you
would need to be running Oracle9i or later to use the CASE version of the function:

FUNCTION get_next_order_state(ord_nbr in NUMBER,

trans_type in VARCHAR2 DEFAULT 'POS')

RETURN VARCHAR2 is

next_state VARCHAR2(20) := 'UNKNOWN';

BEGIN

SELECT CASE
WHEN status = 'REJECTED' THEN status

WHEN status = 'CANCELLED' THEN status

WHEN status = 'SHIPPED' THEN status

WHEN status = 'NEW' AND trans_type = 'NEG' THEN 'AWAIT_PAYMENT'

WHEN status = 'NEW' AND trans_type = 'POS' THEN 'PROCESSING'

WHEN status = 'AWAIT_PAYMENT' AND trans_type = 'NEG' THEN 'REJECTED'

WHEN status = 'AWAIT_PAYMENT' AND trans_type = 'POS' THEN 'PROCESSING'

WHEN status = 'PROCESSING' AND trans_type = 'NEG' THEN 'DELAYED'

WHEN status = 'PROCESSING' AND trans_type = 'POS' THEN 'FILLED'

WHEN status = 'DELAYED' AND trans_type = 'NEG' THEN 'CANCELLED'

WHEN status = 'DELAYED' AND trans_type = 'POS' THEN 'PROCESSING'

WHEN status = 'FILLED' AND trans_type = 'POS' THEN 'SHIPPED'

ELSE 'UNKNOWN'

END

INTO next_state

FROM cust_order
WHERE order_nbr = ord_nbr;

RETURN next_state;

EXCEPTION

WHEN NO_DATA_FOUND THEN

RETURN next_state;

END get_next_order_state;

This example handles only the simple case in which there are just two paths out of each state, but it
does demonstrate one strategy for managing state transitions in your database. To demonstrate how
the previous function could be used, here is the UPDATE statement used to change the status of an
order once it has made a successful state transition:

UPDATE cust_order

SET status = my_pkg.get_next_order_state(order_nbr, 'POS')

WHERE order_nbr = 1107;


Oracle DECODE Function Explained with
Examples
by Ben | Feb 19, 2015 | 7 comments

The Oracle DECODE function can be confusing to those who


have never used it. It’s a useful function for comparing values. Learn more about this
function and some examples in this video.
Purpose of the Oracle DECODE Function
The purpose of the Oracle DECODE function is to perform an IF-THEN-ELSE function.
It’s similar to a CASE statement, but CASE is a statement where DECODE is a function.
It allows you to provide a value, and then evaluate other values against it and show
different results. It works similar to an IF statement within other languages.

Syntax
The syntax of the DECODE function is:
DECODE ( expression, search, result [, search, result]... [,default] )
Get Your Free PDF: 9 Ways to Improve your Database Skills
Yes, Send Me The PDF

DECODE Function Parameters


The parameters of the Oracle DECODE function are:
 expression (mandatory): This is the value to compare.
 search (mandatory): This is the value to compare against the expression.
 result (mandatory): This is what is returned if the search value mentioned previously matches
the expression value. There can be multiple combinations of search and result values, and
the result value is attached to the previous search value.
 default (optional): If none of the search values match, then this value is returned. If the default
value is not provided, the DECODE function will return NULL if no matches are found.
If you compare this to an IF-THEN-ELSE statement, it would look like this:
IF (expression = search) THEN result
[ELSE IF (expression = search) THEN result]
ELSE default
END IF

These arguments can be of any numeric type (NUMBER, BINARY_FLOAT, BINARY


DOUBLE) or character types.
If both expression and search are character types, then a character comparison is used
and the returned value is a VARCHAR2 data type.
If the provided values are numeric, then Oracle determines the datatype to be returned
by checking all of the other data types.
The Oracle DECODE function also uses a feature called “short-circuit evaluation“,
which means that the search values are evaluated only before comparing them to the
expression value, rather than evaluating all search values before comparing any of
them to the expression. This means that Oracle never evaluates a search if a previous
search is equal to an expression.

Oracle DECODE vs CASE


In another page, I go into detail on the Oracle CASE statement. It also allows for IF-
THEN-ELSE functionality, similar to the DECODE function.
So, what’s the difference between the Oracle DECODE function and CASE statement?
There are a few differences:
 DECODE is an older function. CASE was introduced with version 8, and DECODE was around
before then. CASE was introduced as a replacement for DECODE.
 CASE offers more flexibility than DECODE. Tasks that are hard using DECODE are easy
using CASE. This means it is likely to be easier for future developers to work with.
 CASE is easier to read. Even with the formatting of SQL queries, a DECODE statement can be
harder to read.
 The way they handle NULL values is different. DECODE treats NULL equal to NULL. CASE
treats NULL as not equal to NULL.
When it comes to the performance of both of these functions, there is minimal
difference. Some examples show that unless you’re doing iterations over millions of
records, you won’t get much of a difference, and even then it will be small and depend
on the CPU used. So, the performance should not be a determining factor when
deciding whether to use an Oracle CASE statement or DECODE function.

Oracle DECODE Function with NULL Values


As I mentioned above, the Oracle DECODE function is an exception to other functions
in how it handles NULL values. It treats a NULL expression and NULL search as equal
(so NULL == NULL).
So, this example will return 1:
SELECT DECODE(NULL, NULL, 1, 0) FROM DUAL;
The CASE statement treats NULL values as not equal, so this is an important distinction
when working with this function.
Can You Use The Oracle DECODE Function In The
WHERE Clause?
Yes, you can use DECODE in the WHERE clause. It’s done in the same way as any
other checks.
See the examples section below for an example on how to use the DECODE function in
the WHERE clause.

Can You Use The Oracle DECODE Function With LIKE?


The DECODE function is used to find exact matches. This is one of the drawbacks
when comparing it to the CASE statement, as the CASE statement can perform more
advanced checks.
However, it is possible to use the Oracle DECODE function with LIKE.
You can do this with a combination of the SIGN function and the INSTR function.
 INSTR will check if a string is contained within another string
 SIGN will check if the INSTR is positive or negative
You can then check the SIGN and INSTR against a value of 1 to see if the match is
found. See the examples section for more information on how to do this.

Can You Use The Oracle DECODE Function With Greater


Than?
Yes, you can use the DECODE function with greater than, but it’s not neat. Just like
using it with a LIKE comparison, it’s better to do with a CASE statement, but still
possible with a DECODE.
This can be done using subtraction and a SIGN function.
For example, to check if a value is greater than 1000:
1. Use 1000 – value to get a result, which will be positive if the value is less than 1000, and
negative if the value is greater than 1000.
2. Add this into a SIGN function, which returns -1 for negative and 1 for positive.
3. Compare the result to -1, and this will give you the greater than check using DECODE.
Once again, see the example section below for more information on how to do this.

Can You Use The Oracle DECODE Function In an


UPDATE Statement?
Yes, you can use the DECODE function in UPDATE statements. See the example
section below for more information.

What Is The Oracle DECODE Function Performance?


As mentioned earlier in this article, the performance of CASE vs DECODE is pretty
similar. It shouldn’t be used as a determining factor when deciding which method to use.
As a general rule, I would recommend using a CASE statement as it’s easier to read
and has more advanced logic.
Examples of the DECODE Function
Here are some examples of the DECODE function. I find that examples are the best
way for me to learn about code, even with the explanation above.
Example 1
This is an example of the DECODE function with one character search.
SELECT first_name, country,
DECODE(country, 'USA', 'North America') AS Decode_Result
FROM customers;
Result:

FIRST_NAME COUNTRY DECODE_RESULT

John USA North America

Sally USA North America

Steve Canada (null)

Mark UK (null)

Adam USA North America

Josh (null) (null)

Peter France (null)

You can see that when the country = ‘USA’, the DECODE_RESULT is ‘North America’,
otherwise it shows NULL.

Example 2
This is an example of the DECODE function with two character searches.
SELECT first_name, country,
DECODE(country, 'USA', 'North America', 'UK', 'Europe') AS Decode_Result
FROM customers;
Result:
FIRST_NAME COUNTRY DECODE_RESULT

John USA North America

Sally USA North America

Steve Canada (null)

Mark UK Europe

Adam USA North America

Josh (null) (null)

Peter France (null)

Similar to Example 1, this shows different results for USA and UK.

Example 3
This example shows the DECODE function with a default value.
SELECT first_name, country,
DECODE(country, 'USA', 'North America', 'UK', 'Europe', 'Other') AS Decode_Result
FROM customers;
Result:

FIRST_NAME COUNTRY DECODE_RESULT

John USA North America

Sally USA North America


Steve Canada Other

Mark UK Europe

Adam USA North America

Josh (null) Other

Peter France Other

This is the same query as above, but with a default value. You can see that it shows
Other instead of NULL.

Example 4
This is a DECODE function with many character searches.
SELECT first_name, country,
DECODE(country, 'USA', 'North America', 'Canada', 'North America', 'UK', 'Europe', 'France',
'Europe', 'Other') AS Decode_Result
FROM customers;
Result:

FIRST_NAME COUNTRY DECODE_RESULT

John USA North America

Sally USA North America

Steve Canada North America

Mark UK Europe

Adam USA North America


Josh (null) Other

Peter France Europe

This shows many different results from the DECODE function, as well as the Other for
anything that was not considered.

Example 5
This query performs a DECODE on number values.
SELECT first_name, employees,
DECODE(employees, 1, 'Small') AS Decode_Result
FROM customers;
Result:

FIRST_NAME EMPLOYEES DECODE_RESULT

John 4 (null)

Sally 10 (null)

Steve 15 (null)

Mark 23 (null)

Adam 55 (null)

Josh 1 Small

Peter (null) (null)

As there is only one check being done, there is only one matching result in this table.

Example 6
This uses the Oracle DECODE function with three number searches.
SELECT first_name, employees,
DECODE(employees, 1, 'Small', 10, 'Medium', 50, 'Large', 'Unknown') AS Decode_Result
FROM customers;
Result:

FIRST_NAME EMPLOYEES DECODE_RESULT

John 4 Unknown

Sally 10 Medium

Steve 15 Unknown

Mark 23 Unknown

Adam 55 Unknown

Josh 1 Small

Peter (null) Unknown

Notice that only exact matches are found, not a range or a greater than.

Example 7
This example uses the DECODE function with NULL to see how it works.
SELECT first_name, country,
DECODE(country, 'USA', 'North America', NULL, 'No Country') AS Decode_Result
FROM customers;
Result:

FIRST_NAME EMPLOYEES DECODE_RESULT

John USA North America


Sally USA North America

Steve Canada (null)

Mark UK (null)

Adam USA North America

Josh (null) No Country

Peter France (null)

You can see that the record with NULL for a country is shown as No Country, and
anything that does not match is shown as NULL.

Example 8
This is an example of using Oracle DECODE in a WHERE clause.
SELECT first_name, country
FROM customers
WHERE DECODE(country, 'USA', 'North America', 'Canada', 'North America', 'UK', 'Europe',
'France', 'Europe', 'Other') = 'North America';
Result:

FIRST_NAME COUNTRY

John USA

Sally USA

Steve Canada

Adam USA
This only shows records where the DECODE function returns ‘North America’.

Example 9
This example uses DECODE to find if a value is contained in another value, similar to
the LIKE function.
SELECT first_name, country,
DECODE(SIGN(INSTR(country, 'U')), 1, 'Found U', 0, 'Did not find U', 'Unsure') AS
Decode_Result
FROM customers;
Result:

FIRST_NAME COUNTRY DECODE_RESULT

John USA Found U

Sally USA Found U

Steve Canada Did not find U

Mark UK Found U

Adam USA Found U

Josh (null) Unsure

Peter France Did not find U

This checks for the value of U and displays a message if it finds it or not.

Example 10
This is an example of DECODE with greater than functionality.
SELECT first_name, employees,
DECODE(SIGN(20 - employees), 1, 'Less than 20', -1, 'Greater than 20', 'Unsure') AS
Decode_Result
FROM customers;
Result:
FIRST_NAME EMPLOYEES DECODE_RESULT

John 4 Less than 20

Sally 10 Less than 20

Steve 15 Less than 20

Mark 23 Greater than 20

Adam 55 Greater than 20

Josh 1 Less than 20

Peter (null) Unsure

As you can see, any record where employees is greater than 20 will show one value,
and less than will show another value.

Example 11
This is an example of using an UPDATE statement with DECODE.
SELECT first_name, last_name, country
FROM customers;
Result:

FIRST_NAME LAST_NAME COUNTRY

John Smith USA

Sally Jones USA


Steve Brown Canada

Mark Allan UK

Adam Cooper USA

Josh Thompson (null)

Peter Manson France

UPDATE customers
SET last_name = DECODE(country, 'USA', 'American', last_name);
7 rows updated.
SELECT first_name, last_name, country
FROM customers;
Result:

FIRST_NAME LAST_NAME COUNTRY

John American USA

Sally American USA

Steve Brown Canada

Mark Allan UK

Adam American USA


Josh Thompson (null)

Peter Manson France

As you can see, those records where country is USA have had their last name updated
to be ‘American’.

Similar Functions
Some functions which are similar to the Oracle DECODE function are:
 CASE – A statement that was introduced to replace DECODE. Offers more functionality and
easier readability compared to DECODE.
You can find a full list of Oracle functions here.
Get Your Free PDF: 9 Ways to Improve your Database Skills
Yes, Send Me The PDF

Image courtesy of digitalart / FreeDigitalPhotos.net


7 Comments

1.
Ravi on July 7, 2018 at 4:33 pm

how to convert the numbers to characters like 1 to ‘positive’ and -1 to ‘negative’ using
functions.
Reply


Ben on July 8, 2018 at 10:19 am

Hi Ravi, you could use the DECODE function in this article. However I
recommend using the CASE function to check number and convert to
‘positive’ if 1 or ‘negative’ if -1. You can use the SIGN function to determine
if a number is positive or negative, or use greater than or less than.
Reply
2.
Ravi on July 8, 2018 at 12:54 pm

Sir, please send the systax.


Reply


Ben on July 9, 2018 at 4:49 am

Try this:
SELECT
CASE WHEN numvalue < 0 THEN 'negative' CASE WHEN numvalue > 0
THEN ‘positive’
ELSE ‘even’
END AS numtest
FROM yourtable;
Reply


Ravi on July 9, 2018 at 2:51 pm

Thank you sir.


Reply

3.
Ravi on July 9, 2018 at 2:49 pm

Hi sir,
I have one table like tester2 val1 val2 val3
A B 10
C D 20
E A 25
B A 10
A E 25
D C 20
E F 25 and output is given below
val1 val2 val3
A B 10
C D 20
A E 25
E F 25
we can use the functions or joins. So,please send the syntax and which function used in
this problem.
Reply

4.
Ravi on July 14, 2018 at 2:38 am

Hi Sir,
I have string like x12abde#_13-89. I want to print out the only ‘xabde’ by using functions
so, give an syntax for this problem

SQL Functions
INSTR

SQL > SQL String Functions > INSTR Function(https://www.1keydata.com)

The INSTR function in SQL is used to find the starting location of a pattern in a string. This function is avail
MySQL and Oracle, though they have slightly different syntaxes:

Syntax

The syntax for the INSTR function is as follows:

MySQL:

INSTR (str, pattern)

Find the staring location of pattern in string str.

Oracle:

INSTR (str, pattern, [starting position, [nth occurrence]])

Find the starting location of the nth occurrence of pattern beginning in the starting position-th position in str

Examples

We use the following table for our examples.

Table Geography

Region_Name Store_Name

East Boston

East New York

West Los Angeles

West San Diego

Example 1 (both Oracle and MySQL)

SELECT INSTR (Store_Name, 'o')


FROM Geography
WHERE Store_Name = 'Los Angeles';

Result:

The first occurrence of 'o' is the second character in the word 'Los Angeles.'

Example 2 (both Oracle and MySQL)

SELECT INSTR (Store_Name, 'p')


FROM Geography
WHERE Store_Name = 'Los Angeles';

Result:

In this case, the pattern p does not exist in string 'Los Angeles,' so the function returns 0.

Example 3 (Oracle only)

SELECT INSTR(Store_Name,'e', 1, 2)
FROM Geography
WHERE Store_Name = 'Los Angeles';

Result:

10

In this case, we are looking for the second occurrence of the character 'e' in the word 'Los Angeles,' and we
the start with the first character of the word.

The function returns 10 as the second occurrence of 'e' is in the 10th position.

Next: SQL TRIM

Copyright © 2019 1keydata.com All Rights Reserved Privacy Policy About Contact
COALESCE

This function is a generalization of the NVL function.

You can also use COALESCE as a variety of the CASE expression. For example,

COALESCE (expr1, expr2)

is equivalent to:

CASE WHEN expr1 IS NOT NULL THEN expr1 ELSE expr2 END

Similarly,

COALESCE (expr1, expr2, ..., exprn), for n>=3

is equivalent to:

CASE WHEN expr1 IS NOT NULL THEN expr1

ELSE COALESCE (expr2, ..., exprn) END


Example:

The following example uses the sample oe.product_information table to organize a clearance sale of products. It
gives a 10% discount to all products with a list price. If there is no list price, then the sale price is the minimum price.
If there is no minimum price, then the sale price is "5":

SELECT product_id, list_price, min_price,

COALESCE(0.9*list_price, min_price, 5) "Sale"

FROM product_information

WHERE supplier_id = 102050

ORDER BY product_id, list_price, min_price, "Sale";

PRODUCT_ID LIST_PRICE MIN_PRICE Sale

---------- ---------- ---------- ----------

1769 48 43.2

1770 73 73

2378 305 247 274.5

2382 850 731 765

3355 5

Joins
A join is a query that combines rows from two or more tables, views, or materialized views. Oracle Database
performs a join whenever multiple tables appear in the FROM clause of the query. The select list of the query can
select any columns from any of these tables. If any two of these tables have a column name in common, then you
must qualify all references to these columns throughout the query with table names to avoid ambiguity.

Join Conditions
Most join queries contain at least one join condition, either in the FROM clause or in the WHERE clause. The join condition
compares two columns, each from a different table. To execute a join, Oracle Database combines pairs of rows, each containing
one row from each table, for which the join condition evaluates to TRUE. The columns in the join conditions need not also appear
in the select list.

To execute a join of three or more tables, Oracle first joins two of the tables based on the join conditions comparing their
columns and then joins the result to another table based on join conditions containing columns of the joined tables and the new
table. Oracle continues this process until all tables are joined into the result. The optimizer determines the order in which Oracle
joins tables based on the join conditions, indexes on the tables, and, any available statistics for the tables.

IA WHERE clause that contains a join condition can also contain other conditions that refer to columns of only one table. These
conditions can further restrict the rows returned by the join query.

Note:
You cannot specify LOB columns in the WHERE clause if the WHERE clause contains the join condition. The use of LOBs
in WHERE clauses is also subject to other restrictions. See Oracle Database SecureFiles and Large Objects
Developer's Guide for more information.

Equijoins
An equijoin is a join with a join condition containing an equality operator. An equijoin combines rows that have equivalent
values for the specified columns. Depending on the internal algorithm the optimizer chooses to execute the join, the total size of
the columns in the equijoin condition in a single table may be limited to the size of a data block minus some overhead. The size
of a data block is specified by the initialization parameter DB_BLOCK_SIZE.

See Also:
"Using Join Queries: Examples"

Self Joins
A self join is a join of a table to itself. This table appears twice in the FROM clause and is followed by table aliases that qualify
column names in the join condition. To perform a self join, Oracle Database combines and returns rows of the table that satisfy
the join condition.

See Also:
"Using Self Joins: Example"

Cartesian Products
If two tables in a join query have no join condition, then Oracle Database returns their Cartesian product. Oracle combines each
row of one table with each row of the other. A Cartesian product always generates many rows and is rarely useful. For example,
the Cartesian product of two tables, each with 100 rows, has 10,000 rows. Always include a join condition unless you specifically
need a Cartesian product. If a query joins three or more tables and you do not specify a join condition for a specific pair, then the
optimizer may choose a join order that avoids producing an intermediate Cartesian product.

Inner Joins
An inner join (sometimes called a simple join) is a join of two or more tables that returns only those rows that satisfy the join
condition.

Outer Joins
An outer join extends the result of a simple join. An outer join returns all rows that satisfy the join condition and also returns
some or all of those rows from one table for which no rows from the other satisfy the join condition.

 To write a query that performs an outer join of tables A and B and returns all rows from A (a left outer join), use
the LEFT [OUTER] JOIN syntax in the FROM clause, or apply the outer join operator (+) to all columns of B in the join
condition in the WHERE clause. For all rows in A that have no matching rows in B, Oracle Database returns null for any
select list expressions containing columns of B.
 To write a query that performs an outer join of tables A and B and returns all rows from B (a right outer join), use
the RIGHT [OUTER] JOINsyntax in the FROM clause, or apply the outer join operator (+) to all columns of A in the join
condition in the WHERE clause. For all rows in B that have no matching rows in A, Oracle returns null for any select list
expressions containing columns of A.
 To write a query that performs an outer join and returns all rows from A and B, extended with nulls if they do not
satisfy the join condition (a full outer join), use the FULL [OUTER] JOIN syntax in the FROM clause.

You cannot compare a column with a subquery in the WHERE clause of any outer join, regardless which form you specify.

You can use outer joins to fill gaps in sparse data. Such a join is called a partitioned outer join and is formed using
the query_partition_clause of the join_clause syntax. Sparse data is data that does not have rows for all possible values
of a dimension such as time or department. For example, tables of sales data typically do not have rows for products that had no
sales on a given date. Filling data gaps is useful in situations where data sparsity complicates analytic computation or where some
data might be missed if the sparse data is queried directly.

See Also:

 join_clause for more information about using outer joins to fill gaps in sparse data
 Oracle Database Data Warehousing Guide for a complete discussion of group outer joins and filling gaps in sparse
data

Oracle recommends that you use the FROM clause OUTER JOIN syntax rather than the Oracle join operator. Outer join queries that
use the Oracle join operator (+) are subject to the following rules and restrictions, which do not apply to
the FROM clause OUTER JOIN syntax:

 You cannot specify the (+) operator in a query block that also contains FROM clause join syntax.
 The (+) operator can appear only in the WHERE clause or, in the context of left-correlation (when specifying
the TABLE clause) in the FROMclause, and can be applied only to a column of a table or view.
 If A and B are joined by multiple join conditions, then you must use the (+) operator in all of these conditions. If you
do not, then Oracle Database will return only the rows resulting from a simple join, but without a warning or error to
advise you that you do not have the results of an outer join.
 The (+) operator does not produce an outer join if you specify one table in the outer query and the other table in an
inner query.
 You cannot use the (+) operator to outer-join a table to itself, although self joins are valid. For example, the following
statement is not valid:
 -- The following statement is not valid:

 SELECT employee_id, manager_id

 FROM employees

 WHERE employees.manager_id(+) = employees.employee_id;

However, the following self join is valid:

SELECT e1.employee_id, e1.manager_id, e2.employee_id

FROM employees e1, employees e2

WHERE e1.manager_id(+) = e2.employee_id

ORDER BY e1.employee_id, e1.manager_id, e2.employee_id;

 The (+) operator can be applied only to a column, not to an arbitrary expression. However, an arbitrary expression can
contain one or more columns marked with the (+) operator.
 A WHERE condition containing the (+) operator cannot be combined with another condition using the OR logical
operator.
 A WHERE condition cannot use the IN comparison condition to compare a column marked with the (+) operator with an
expression.

If the WHERE clause contains a condition that compares a column from table B with a constant, then the (+) operator must be
applied to the column so that Oracle returns the rows from table A for which it has generated nulls for this column. Otherwise
Oracle returns only the results of a simple join.

In a query that performs outer joins of more than two pairs of tables, a single table can be the null-generated table for only one
other table. For this reason, you cannot apply the (+) operator to columns of B in the join condition for A and B and the join
condition for B and C. Refer to SELECT for the syntax for an outer join.

Antijoins
An antijoin returns rows from the left side of the predicate for which there are no corresponding rows on the right side of the
predicate. It returns rows that fail to match (NOT IN) the subquery on the right side.

See Also:
"Using Antijoins: Example"

Semijoins
A semijoin returns rows that match an EXISTS subquery without duplicating rows from the left side of the predicate when
multiple rows on the right side satisfy the criteria of the subquery.

Semijoin and antijoin transformation cannot be done if the subquery is on an OR branch of the WHERE clause.

--USE OF CONCATINATION OPERATOR


If we want to add Inverted comma at the start and end of the columns fields…….
Select branch_code,''''|| branch_name ||''''||',' as Branch_name from fbtm_branch_info order by
branch_code;

Use of SUBSTR function in ID card number to display dashes;

--0075077159842

Select substr(cust.UNIQUE_ID_VALUE,1,5) || '-' || substr(cust.UNIQUE_ID_VALUE, 6,7) || '-' ||


substr(cust.UNIQUE_ID_VALUE, 13,1) CON_BRWR

from sttm_customer cust where cust.unique_id_value IN('0075077159842');


Concept of Having clause to select > 1 rows:

--For Processing of Manual Batches:

--Final_Query first to identify how many branches are working in manual group Session_ID from

--BY putting Session_ID and count >1 Developed By Adeel

--Select Session_ID from aetb_eoc_branches where branch_code IN('082');

select
branch_code,EOC_REF_NO,EOC_SEQ_NO,EOD_DATE,BRANCH_DATE,CURR_STAGE,TARGET_STAGE,RUN
_MODE,RUNNING_STAGE,EOC_STATUS

from AETB_EOC_BRANCHES

where SESSION_ID + SERIAL_NO in (select SESSION_ID + SERIAL_NO

from AETB_EOC_BRANCHES

group by SESSION_ID + SERIAL_NO

having count(SESSION_ID + SERIAL_NO) > 1) and EOC_STATUS IN('N','W') and Session_ID


IN('750') and EOD_Date ='18-FEB-2019' order by

branch_code,Session_ID;

Use of description in Sql Queries:

Select 'Outstanding Loans' Description,count(am.branch_code) Total_Number from


cltb_account_apps_master am;
How to select rows with no matching entry
in another table?
Ask Question

246

55

I'm doing some maintenance work on a database application and I've discovered that, joy of joys, even though values from
one table are being used in the style of foreign keys, there's no foreign key constraints on the tables.

I'm trying to add FK constraints on these columns, but I'm finding that, because there's already a whole load of bad data in
the tables from previous errors which have been naively corrected, I need to find the rows which don't match up to the
other table and then delete them.

I've found some examples of this kind of query on the web, but they all seem to provide examples rather than explanations,
and I don't understand why they work.

Can someone explain to me how to construct a query which returns all the rows with no matches in another table, and
what it's doing, so that I can make these queries myself, rather than coming running to SO for every table in this mess that
has no FK constraints?
sql foreign-keys

shareimprove this question

edited May 26 '17 at 21:34

Kara

4,024104353

asked Nov 2 '10 at 8:47

Frosty840

2,84684075

add a comment
9 Answers
activeoldest votes

473

Here's a simple query:

SELECT t1.ID
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.ID = t2.ID
WHERE t2.ID IS NULL
The key points are:

1. LEFT JOIN is used; this will return ALL rows from Table1, regardless of whether or not there is a matching row
in Table2.
2. The WHERE t2.ID IS NULL clause; this will restrict the results returned to only those rows where the ID returned
from Table2 is null - in other words there is NO record in Table2 for that particular ID from Table1. Table2.ID will
be returned as NULL for all records from Table1 where the ID is not matched in Table2.
shareimprove this answer

edited Mar 16 '16 at 12:59

Toby Speight

17.1k134367

answered Nov 2 '10 at 8:56

AdaTheDev

108k22164175

 3
Fails if an ID is NULL – Michael Aug 13 '13 at 3:53

 120
@Michael - If having a NULL ID is valid in your schema, you might have bigger problems, wouldn't you agree? :) – rinogo Nov 7 '13 at
4:44

 5
@Martin - if this (correct example) "crashes" your MySQL server, I think you are blaming (and downvoting) the wrong thing. There
are of course many ways to skin a cat, of which this is a perfectly valid one. – AdaTheDev Mar 24 '14 at 14:05
 will this work even if table1 has more records then table2? if table1 has 100 records and table2 has 200 records (100 that match/join
and 100 that don't match/join) would we get all 200 records returned?– Juan Velez Aug 8 '16 at 20:15
 1
@pokerplayer23 - yes (see point 1 above) – AdaTheDev Aug 9 '16 at 8:14

show 4 more comments

48

I would use EXISTS expression since it is more powerfull, you can i.e more precisely choose rows you would like to join,
in case of LEFT JOIN you have to take everything what's in joined table. Its efficiency is probably same as in case of LEFT
JOIN with null test.
SELECT t1.ID
FROM Table1 t1
WHERE NOT EXISTS (SELECT t2.ID FROM Table2 t2 WHERE t1.ID = t2.ID)
shareimprove this answer

answered Apr 18 '16 at 12:48

Ondrej Bozek

6,41934061

 Something this simple is easily handled by the query optimizer for best execution. – Andrew WolfeFeb 7 '17 at 0:44
 1
Yes, main advantage of EXISTS is its variability. – Ondrej Bozek Feb 7 '17 at 12:31

 is it supposed to work in mysql ? I keep getting #1064 - You have an error in your SQL syntax; check the manual that corresponds
to your MySQL server version for the right syntax to use near – Pavel Niedoba Mar 21 '18 at 13:46
 It shoudl work for MySQL see docs: dev.mysql.com/doc/refman/5.5/en/… – Ondrej Bozek Mar 26 '18 at 10:03
 1
Simple, elegant and it solved my problem! Nice one! – Mike D Wakelyn Nov 10 '18 at 20:17

 1
Actually reduced the speed of one query i had from 7 sec to 200ms... (compared to WHERE t2.id IS NULL ) Thank You. – Moti
Korets Feb 12 at 20:56

add a comment

SELECT id FROM table1 WHERE foreign_key_id_column NOT IN (SELECT id FROM table2)


Table 1 has a column that you want to add the foreign key constraint to, but the values in the foreign_key_id_column don't
all match up with an id in table 2.
1. The initial select lists the ids from table1. These will be the rows we want to delete.
2. The NOT IN clause in the where statement limits the query to only rows where the value in
the foreign_key_id_column is not in the list of table 2 ids.
3. The SELECT statement in parenthesis will get a list of all the ids that are in table 2.
shareimprove this answer

edited Feb 23 at 15:23


zb226

5,80232954

answered May 31 '16 at 17:36

Theo Voss

11112

 @zb226: Your link to has to do with limits on the IN clause with a list of literal values. It doesn't apply to using an IN clause with the
result of a sub-query. That accepted answer to that question actually solves the problem by using a sub-query. (A large list of literal
values is problematic because it creates a huge SQL expression. A sub-query works fine because, even if the resulting list is large,
the SQL expression itself is small.) – Kannan Goundan Feb 8 at 0:26
 @KannanGoundan You're absolute right. Withdrawing the flawed comment. – zb226 Feb 8 at 9:46
add a comment

Where T2 is the table to which you're adding the constraint:


SELECT *
FROM T2
WHERE constrained_field NOT
IN (
SELECT DISTINCT t.constrained_field
FROM T2
INNER JOIN T1 t
USING ( constrained_field )
)
And delete the results.

shareimprove this answer

edited Feb 23 at 15:24

zb226

5,80232954

answered Apr 16 '15 at 17:48


Karel

7912

add a comment

Let we have the following 2 tables(salary and

employee)
Now i want those records from employee table which are not in salary. We can do this in 3 ways-
1. Using inner Join
select * from employee where id not in(select e.id from employee e inner join salary s on e.id=s.id)

2. Using Left outer join


select * from employee e left outer join salary s on e.id=s.id where s.id is null

3. Using Full Join


select * from employee e full outer join salary s on e.id=s.id where e.id not in(select id from salary)
shareimprove this answer

edited Jan 14 '18 at 15:32

answered Jan 14 '18 at 15:16

Debendra Dash

2,2911922

add a comment

From similar question here MySQL Inner Join Query To Get Records Not Present in Other Table I got this to work
SELECT * FROM bigtable
LEFT JOIN smalltable ON bigtable.id = smalltable.id
WHERE smalltable.id IS NULL
smalltable is where you have missing records, bigtable is where you have all the records. The query list all the records
that not exist in smalltable but exists on the bigtable. You could replace id by any other matching criteria.
shareimprove this answer

answered Dec 21 '18 at 0:45

Luis H Cabrejo

577

add a comment

I Dont Knew Which one Is Optimized (compared to @AdaTheDev ) but This one seems to be quicker when I use (atleast
for me)

SELECT id FROM table_1 EXCEPT SELECT DISTINCT (table1_id) table1_id FROM table_2
If You want to get any other specific attribute you can use:

SELECT COUNT(*) FROM table_1 where id in (SELECT id FROM table_1 EXCEPT SELECT DISTINCT (table1_id)
table1_id FROM table_2);
shareimprove this answer
answered Jan 25 '18 at 6:59

Jerin K. John

353313

add a comment

You could opt for Views as shown below:


CREATE VIEW AuthorizedUserProjectView AS select t1.username as username, t1.email as useremail, p.id as projectid,
(select m.role from userproject m where m.projectid = p.id and m.userid = t1.id) as role
FROM authorizeduser as t1, project as p
and then work on the view for selecting or updating:

select * from AuthorizedUserProjectView where projectid = 49


which yields the result as shown in the picture below i.e. for non-matching column null has been filled in.

[Result of select on the view][1]


shareimprove this answer

answered Nov 14 '18 at 15:06

Nitesh singh

51

add a comment

-4

How to select rows with no matching entry in Both table?

select * from [dbo].[EmppDetails] e

right join [Employee].[Gender] d on e.Gid=d.Gid

where e.Gid is Null

union

select * from [dbo].[EmppDetails] e

left join [Employee].[Gender] d on e.Gid=d.Gid

where d.Gid is Null


Difference b/w Count(*) and count(1)

Clearly, COUNT(*) and COUNT(1) will always return the same result. Therefore, if one were slower than the
other it would effectively be due to an optimiser bug. Since both forms are used very frequently in queries, it
would make no sense for a DBMS to allow such a bug to remain unfixed. Hence you will find that the
performance of both forms is (probably) identical in all major SQL DBMSs.

Example of count(*)

Example of count(1)
User of Joins using Trial Balance concept in Oracle Flexcube:

SELECT

sum(gl_bal.DR_BAL_LCY) - sum(gl_bal.CR_BAL_LCY) "Balance in GL"

FROM

GLTB_GL_BAL gl_bal

JOIN GLTM_GLMASTER glm oN (glm.gl_code = gl_bal.GL_CODE)

left outer join STTM_BRANCH br on (br.BRANCH_CODE = gl_bal.branch_code)

WHERE

gl_bal.LEAF = 'Y'

AND gl_bal.period_code = 'M02'

AND gl_bal.DR_BAL_LCY - gl_bal.CR_BAL_LCY <> 0

and gl_bal.FIN_YEAR = 'FY2019'

and gl_bal.gl_code = '404070501' ;

Select * from gltm_glmaster where gl_code IN('404070501');

CONCEPT OF INSERT VALUES IN TABLE:

insert into dormant_active_close (BRANCH_CODE, CUST_AC_NO, ACCOUNT_CLASS,


AC_STAT_DORMANT) values ('070', '0701010396165019', 'CUR', 'Y');

Oracle / PLSQL: CREATE TABLE AS Statement


https://www.techonthenet.com/oracle/tables/create_table2.php
This Oracle tutorial explains how to use the Oracle CREATE TABLE AS statement with syntax and
examples.
Description
You can also use the Oracle CREATE TABLE AS statement to create a table from an existing table by
copying the existing table's columns.
It is important to note that when creating a table in this way, the new table will be populated with the
records from the existing table (based on the SELECT Statement).

Create TAble - By Copying all columns from another table

Syntax
The syntax for the CREATE TABLE AS statement that copies all of the columns in Oracle/PLSQL is:

CREATE TABLE new_table


AS (SELECT * FROM old_table);

Example
Let's look at a CREATE TABLE AS example that shows how to create a table by copying all columns
from another table.

CREATE TABLE suppliers


AS (SELECT *
FROM companies
WHERE company_id < 5000);

This example would create a new table called suppliers that included all columns from
the companies table.
If there were records in the companies table, then the new suppliers table would be populated with the
records returned by the SELECT statement.

Create TAble - By Copying selected columns from another table

Syntax
The syntax for the CREATE TABLE AS statement that copies the selected columns in Oracle/PLSQL is:

CREATE TABLE new_table


AS (SELECT column_1, column2, ... column_n
FROM old_table);
Example
Let's look at a CREATE TABLE AS example that shows how to create a table by copying selected
columns from another table.
For Example:

CREATE TABLE suppliers


AS (SELECT company_id, address, city, state, zip
FROM companies
WHERE company_id < 5000);

This example would create a new table called suppliers, but the new table would only include the
specified columns (ie: company_id, address, city, state, and zip) from the companies table.
Again, if there were records in the companies table, then the new suppliers table would be populated with
the records returned by the SELECT statement.

Create table - By Copying selected columns from multiple tables

Syntax
The syntax for the CREATE TABLE AS statement that copies columns from multiple tables in
Oracle/PLSQL is:

CREATE TABLE new_table


AS (SELECT column_1, column2, ... column_n
FROM old_table_1, old_table_2, ... old_table_n);

Example
Let's look at a CREATE TABLE AS example that shows how to create a table by copying selected
columns from multiple tables.
For example:

CREATE TABLE suppliers


AS (SELECT companies.company_id, companies.address, categories.category_type
FROM companies, categories
WHERE companies.company_id = categories.category_id
AND companies.company_id < 5000);

This example would create a new table called suppliers based on columns definitions from both
the companies and categories tables (ie: company_id, address, and category_type).
Frequently Asked Questions
Question: How can I create an Oracle table from another table without copying any values from the old
table?
Answer: To do this, the Oracle CREATE TABLE syntax is:

CREATE TABLE new_table


AS (SELECT *
FROM old_table WHERE 1=2);

For example:

CREATE TABLE suppliers


AS (SELECT *
FROM companies WHERE 1=2);

Use of two columns condtion in where clause + use of Brackets in where clause instead of = operator:

‘select * from sttm_cust_account_dormancy where (branch_code, cust_ac_no) in (select branch_code,


cust_ac_no from dormant_active_close) and dormancy_end_dt is NULL;

Use of brackets after where clause condition in sql

select * from sttm_account_class where account_class = (select account_class from sttm_cust_account


where cust_ac_no = '&acc');
Use of FOR LOOP IN ORACLE FLEXCUBE:

set array 1

set head on

set colsep ";"

set feedback on

set line 1000

set pagesize 10000

set echo on

SET SERVEROUTPUT ON;

SPOOL C:\MULTI_BRN_EODM_MANUAL.SPL

BEGIN

for i in (select branch_code from sttm_branch

where record_stat = 'O'

and auth_stat = 'A'

and branch_code not in

(select BRANCH_CODE from sttb_brn_eodm where RUN_DATE = '25-FEB-2019')) loop

DBMS_OUTPUT.PUT_LINE('Running EODM for branch: '|| i.branch_code);

--DBMS_OUTPUT.PUT_LINE('RESETTING FBTB_TILL_TOTALS');

INSERT INTO fbtb_till_totals


(TILL_ID,

CCYCODE,

BRANCHCODE,

POSTINGDATE,

OPENINGBALANCE,

INFLOW,

OUTFLOW)

SELECT totals.TILL_ID,

totals.CCYCODE,

totals.BRANCHCODE,

info.nextpostingdate,

NVL(totals.openingbalance, 0) + NVL(totals.inflow, 0) -

NVL(totals.outflow, 0),

0.00,

0.00

FROM fbtm_branch_info info, fbtb_till_totals totals

where totals.branchcode = info.branch_code

AND totals.postingdate = info.currentpostingdate

and info.branch_code = i.branch_code;

--DBMS_OUTPUT.PUT_LINE('RESETTING FBTB_TILL_DETAIL_CCY');

UPDATE fbtb_till_detail_ccy

SET OPENINGBALANCE = DENOMCOUNT, INFLOW = 0, OUTFLOW = 0

WHERE BRANCHCODE = i.branch_code;


--DBMS_OUTPUT.PUT_LINE('RESETTING FBTB_CUST_ACCOUNT FOR OFF_TXN_AMT');

UPDATE FBTB_CUST_ACCOUNT

SET OFF_TXN_AMT = 0.0

WHERE OFF_TXN_AMT > 0

AND BRANCH_CODE = i.branch_code;

--DBMS_OUTPUT.PUT_LINE( 'MARKING EODM');

INSERT INTO STTB_BRN_EODM

(BRANCH_CODE, RUN_DATE, EOD_RUN)

SELECT branch_code, currentpostingdate, 'Y'

FROM fbtm_branch_info

WHERE branch_code = i.branch_code;

UPDATE FBTM_BRANCH_INFO BI

SET BI.CURRENTPOSTINGDATE = NEXTPOSTINGDATE,

NEXTPOSTINGDATE = TO_DATE('27-FEB-2019', 'DD-MON-YYYY')

WHERE BRANCH_CODE = i.branch_code;

end loop;

END;

COMMIT;

SPOOL OFF
USE OF SIMPLE LOOP IN ORACLE FLEXCUBE:

BEGIN

FOR BR IN (select branch_code from sttm_branch where branch_code in ('002', '003', '011',
'012', '020', '021', '022', '024', '025', '026', '027', '028', '029', '030', '032',
'033', '034', '035', '036', '037', '038', '039', '040', '041', '042', '043', '044',
'045', '046', '047', '048', '049', '051', '052', '053', '054', '055', '056', '057',
'058', '059', '061', '065', '066', '067', '068', '069', '070', '071', '072', '073',
'074', '075', '076', '077', '078', '079', '080', '081', '082', '083', '084', '085',
'086', '087', '088', '089', '090', '091', '092', '093', '094', '095', '096', '097',
'098', '099', '100', '101', '102', '103', '104', '105', '106', '108', '109', '110',
'111', '112', '113', '114', '115', '116', '117', '118', '119', '120', '121', '122',
'123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134',
'135', '136', '137', '138', '139', '140', '141', '142', '143', '144', '145', '146',
'147', '150', '151', '155', '156', '157', '158', '159', '160', '161', '162', '163',
'165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176',
'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188',
'189', '190', '192', '193', '194', '195', '196', '197', '201', '202', '203', '204',
'205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216',
'217', '218', '220', '221', '222', '224', '225', '226') order by 1) LOOP

--===============================================================================

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP1' and COLLETRAL_CATEGORY =


'GROUP_GUARANTEE' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP1' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP1' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP1' and COLLETRAL_CATEGORY =


'PROPERTY' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP1' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP2' and COLLETRAL_CATEGORY =


'GROUP_GUARANTEE' and branch_code = BR.Branch_code;
delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP2' and COLLETRAL_CATEGORY =
'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP2' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP2' and COLLETRAL_CATEGORY =


'PROPERTY' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'AFP2' and COLLETRAL_CATEGORY =


'NSC_BULLET' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP1' and COLLETRAL_CATEGORY =


'GROUP_GUARANTEE' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP1' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP1' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP1' and COLLETRAL_CATEGORY =


'PROPERTY' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP1' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP2' and COLLETRAL_CATEGORY =


'GROUP_GUARANTEE' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP2' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP2' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP2' and COLLETRAL_CATEGORY =


'PROPERTY' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP2' and COLLETRAL_CATEGORY =


'NSC_BULLET' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP3' and COLLETRAL_CATEGORY =


'GROUP_GUARANTEE' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP3' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;
delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP3' and COLLETRAL_CATEGORY =
'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP3' and COLLETRAL_CATEGORY =


'PROPERTY' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LFP3' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'EFP1' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'GLP1' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'GLP2' and COLLETRAL_CATEGORY =


'GROUP_GUARANTEE' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'GLP2' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'GLP2' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'GLP2' and COLLETRAL_CATEGORY =


'NSC_BULLET' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LSL1' and COLLETRAL_CATEGORY =


'SAL_CAT_A' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LSL1' and COLLETRAL_CATEGORY =


'SAL_CAT_B' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'LSL1' and COLLETRAL_CATEGORY =


'SAL_CAT_C' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'MPL1' and COLLETRAL_CATEGORY =


'PEN_CAT_A' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'MPL1' and COLLETRAL_CATEGORY =


'PEN_CAT_B' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'MPL1' and COLLETRAL_CATEGORY =


'PEN_CAT_C' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'MPL1' and COLLETRAL_CATEGORY =


'PEN_CAT_D' and branch_code = BR.Branch_code;
delete from MFTM_COLL_RATE_CUSTOM where product_code = 'MPL2' and COLLETRAL_CATEGORY =
'PEN_CAT_A' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'MPL2' and COLLETRAL_CATEGORY =


'PEN_CAT_B' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'MPL2' and COLLETRAL_CATEGORY =


'PEN_CAT_C' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'MPL2' and COLLETRAL_CATEGORY =


'PEN_CAT_D' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'SFP1' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'SFP1' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'SFP2' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'SFP2' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP1' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP2' and COLLETRAL_CATEGORY =


'NSC_BULLET' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP3' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP4' and COLLETRAL_CATEGORY =


'HPA_NEW' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP4' and COLLETRAL_CATEGORY =


'HPA_USED' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP5' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP5' and COLLETRAL_CATEGORY =


'PG_PENSION' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP5' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;
delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP5' and COLLETRAL_CATEGORY =
'PROPERTY' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP5' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP6' and COLLETRAL_CATEGORY =


'PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP6' and COLLETRAL_CATEGORY =


'PG_PENSION' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP6' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP6' and COLLETRAL_CATEGORY =


'PROPERTY' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP6' and COLLETRAL_CATEGORY =


'NSC_BULLET' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP7' and COLLETRAL_CATEGORY =


'HPA_NEW' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'RZP7' and COLLETRAL_CATEGORY =


'HPA_USED' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'HFS1' and COLLETRAL_CATEGORY =


'SALARIED_PENSIONER' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'HFS1' and COLLETRAL_CATEGORY =


'SEB_SEP' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'PIF1' and COLLETRAL_CATEGORY =


'3PG' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'PIF1' and COLLETRAL_CATEGORY =


'PROPERTY' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'PIF1' and COLLETRAL_CATEGORY =


'NSC_INSTALLMENT' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'HFN1' and COLLETRAL_CATEGORY =


'SALARIED_PENSIONER' and branch_code = BR.Branch_code;

delete from MFTM_COLL_RATE_CUSTOM where product_code = 'HFN1' and COLLETRAL_CATEGORY =


'SEB_SEP' and branch_code = BR.Branch_code;
insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)
values (BR.BRANCH_CODE, 'AFP1', 'GROUP_GUARANTEE',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP1', 'PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP1', '3PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP1', 'PROPERTY',28);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP1', 'NSC_INSTALLMENT',21.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP2', 'GROUP_GUARANTEE',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP2', 'PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP2', '3PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP2', 'PROPERTY',26);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'AFP2', 'NSC_BULLET',21.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP1', 'GROUP_GUARANTEE',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP1', 'PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP1', '3PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP1', 'PROPERTY',28);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP1', 'NSC_INSTALLMENT',21.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP2', 'GROUP_GUARANTEE',30.9);
insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)
values (BR.BRANCH_CODE, 'LFP2', 'PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP2', '3PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP2', 'PROPERTY',26);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP2', 'NSC_BULLET',21.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP3', 'GROUP_GUARANTEE',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP3', 'PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP3', '3PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP3', 'PROPERTY',28);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LFP3', 'NSC_INSTALLMENT',21.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'EFP1', 'NSC_INSTALLMENT',21.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'GLP1', 'NSC_INSTALLMENT',21.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'GLP2', 'GROUP_GUARANTEE',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'GLP2', 'PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'GLP2', '3PG',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'GLP2', 'NSC_BULLET',21.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LSL1', 'SAL_CAT_A',30.9);
insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)
values (BR.BRANCH_CODE, 'LSL1', 'SAL_CAT_B',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'LSL1', 'SAL_CAT_C',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'MPL1', 'PEN_CAT_A',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'MPL1', 'PEN_CAT_B',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'MPL1', 'PEN_CAT_C',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'MPL1', 'PEN_CAT_D',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'MPL2', 'PEN_CAT_A',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'MPL2', 'PEN_CAT_B',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'MPL2', 'PEN_CAT_C',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'MPL2', 'PEN_CAT_D',30.9);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'SFP1', '3PG',16.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'SFP1', 'PG',16.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'SFP2', '3PG',16.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'SFP2', 'PG',16.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP1', 'NSC_INSTALLMENT',19.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP2', 'NSC_BULLET',19.5);
insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)
values (BR.BRANCH_CODE, 'RZP3', 'NSC_INSTALLMENT',19.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP4', 'HPA_NEW',22.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP4', 'HPA_USED',22.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP5', 'PG',28.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP5', 'PG_PENSION',25.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP5', '3PG',27.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP5', 'PROPERTY',24.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP5', 'NSC_INSTALLMENT',17.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP6', 'PG',28.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP6', 'PG_PENSION',25.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP6', '3PG',27.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP6', 'PROPERTY',24.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP6', 'NSC_BULLET',17.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP7', 'HPA_NEW',19.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'RZP7', 'HPA_USED',19.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'HFS1', 'SALARIED_PENSIONER',20.5);
insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)
values (BR.BRANCH_CODE, 'HFS1', 'SEB_SEP',20.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'PIF1', '3PG',27);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'PIF1', 'PROPERTY',24.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'PIF1', 'NSC_INSTALLMENT',17.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'HFN1', 'SALARIED_PENSIONER',20.5);

insert into MFTM_COLL_RATE_CUSTOM(Branch_code, Product_code, COLLETRAL_CATEGORY, rate)


values (BR.BRANCH_CODE, 'HFN1', 'SEB_SEP',20.5);

--===============================================================================

commit;

END LOOP;

END;
USE OF TIME IN ORACLE:

--Written by Adeel

Select global.* from(

Select a.* from ( select * from(Select

x.branch_code,

x.eod_date,

x.eoc_stage,

x.eoc_stage_seq,

TO_CHAR( min(x.start_time),'HH:MM:SS AM') start_time,

TO_CHAR( max(x.end_time),'HH:MM:SS AM') end_time,

round((max(x.end_time) - min(x.start_time)) * 24 * 60,

2) total_min_taken

from aetb_eoc_runchart_history x

--where x.branch_code IN('003') and eod_date In('20-MAR-2019')

group by x.branch_code, x.eod_date, x.eoc_stage,x.eoc_stage_seq) order by eoc_stage_seq)a

union all

--Simple Run chart

Select b.* from(

Select * from(

select

i.branch_code,

i.eod_date,

i.eoc_stage,
i.eoc_stage_seq,

TO_CHAR(min(i.start_time),'HH:MM:SS AM') start_time,

TO_CHAR(max(i.end_time),'HH:MM:SS AM') end_time,

round((max(i.end_time) - min(i.start_time)) * 24 * 60,

2) tot_min_taken

from aetb_eoc_runchart i

-- where i.branch_code IN('003') and eod_date In('20-MAR-2019')

group by i.branch_code, i.eod_date, i.eoc_stage,i.eoc_stage_seq)order by


eoc_stage_seq)b)global where global.branch_code ='&BRANCH_CODE' and global.eod_date
In'&EOD_DAY_DATE';

Das könnte Ihnen auch gefallen