Oracle SQL
Advanced course
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
This document has been prepared by MICROS-Fidelio and is available to a select group of
individuals for information purposes. This is a confidential document that contains concepts,
methods and other proprietary information. Readers are to treat the information herein as
confidential.
Information in this document is subject to change without notice.
MICROS-Fidelio makes no warranty of any kind with regard to this material, including but not
limited to the implied warranties of marketability and fitness for a particular purpose.
MICROS-Fidelio shall not be liable for errors contained herein or for incidental or
consequential damages in connection with the furnishing, performance, or use of this material.
Copyright © 2014 MICROS-Fidelio. All Rights Reserved. No part of this publication may be
reproduced, photocopied, stored on a retrieval system, or transmitted without the express prior
written consent of the publisher.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 2 of 56
Document version
Version Date Author Changes
1.0 21/05/2014 Mark Cook Initial
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 3 of 56
Table of content
Introduction...............................................................................................................................6
Finding duplicates.....................................................................................................................7
Example 1 | OCIS Profile Subscriptions..................................................................................7
Example 2 | Profile Addresses.................................................................................................8
Example 3 | Profile Contacts...................................................................................................9
Example 4 | Duplicate Reservations........................................................................................9
Finding duplicates..................................................................................................................10
Example 1 | A simple example to display the name and membership card number of a
profile/guest...........................................................................................................................10
Example 2 | Comparing reservation creation to deliver to ORS............................................11
Trunc function and dates.......................................................................................................16
ORS Initialization.....................................................................................................................18
Date and Time Formatting......................................................................................................21
General..................................................................................................................................21
Calculating Time Permutations..............................................................................................23
OEDS Rollover......................................................................................................................24
Calculating the duration between 2 times..............................................................................26
How to find number of rows in a table between two timestamp using BETWEEN................27
How and when to use NVL.....................................................................................................28
How to use DECODE...............................................................................................................30
How to use CASE....................................................................................................................31
How to use SUBSTR...............................................................................................................32
How to use ROLLUP...............................................................................................................34
How to use ROUND.................................................................................................................36
How to use OR.........................................................................................................................39
Example.................................................................................................................................39
The Rules of Precedence......................................................................................................40
Further example of OR..........................................................................................................41
How to find dependant foreign keys.....................................................................................42
How to find and replace special characters.........................................................................44
Using OR and LIKE...............................................................................................................44
Using INSTR..........................................................................................................................44
Using ow_pattern_match.......................................................................................................46
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 4 of 56
How to replace special characters.........................................................................................47
How to use concatenation......................................................................................................48
How to find the transaction code rollup for a PMS reservation.........................................49
How to use subqueries...........................................................................................................50
How to compare the application parameters between 2 different resorts in the same
schema.....................................................................................................................................51
PL/SQL.....................................................................................................................................52
Initialazation examples..........................................................................................................52
ORS Alternative.....................................................................................................................52
Example of PL/SQL to resolve possible issue in DC.............................................................53
PL/SQL use in the troubleshooting the purge........................................................................54
Monitored Alerts example......................................................................................................55
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 5 of 56
Introduction
This document will help using SQL queries/scripts as powerful tools to troubleshoot and solve
issues.
Should you need a refresh on basic SQL, please refer to this guide.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 6 of 56
Finding duplicates
Example 1 | OCIS Profile Subscriptions
You need to find how many profiles have duplicate subscriptions in OCIS/ORS for the resort
DSHU02. The primary column will be name_id to identify the profiles themselves. The
database_id column is required for the filter and also as a results check. The
database_name_id count function is the number of unique subscriptions for that database for
that profile.
Running this query lists the number of subscriptions each profile has for that resort:
select name_id, database_id, count(database_name_id)
from name_subscriptions
where database_id='DSHU02'
group by name_id, database_id
To identify the profiles with duplicate subscriptions then you add a HAVING clause to the script
like so:
select name_id, database_id, count(database_name_id)
from name_subscriptions
where database_id='DSHU02'
group by name_id, database_id
having count(database_name_id) > 1
This clause filters out the profiles with more than one subscription, and displays the profiles
with duplicate subscriptions to an external system (note that in real life we would also include
filters on inactive_date to further drill into the data).
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 7 of 56
Example 2 | Profile Addresses
You want to check how many profiles have duplicated addresses but only want to see the
worst affected with more than 100 addresses per profile.
To achieve this we use an inline view.
Firstly we need a script to find the duplicates. Using the principles above then:
select name_id, count(*) as count_addresses
from name_address
group by name_id
having count(*) > 100
The result just returns 1 name_id which is -100 the default name_id storing orphaned
addresses.
In general no profile should have more than 100 addresses configured so a result like this
would mean all is OK. If there are several thousand profiles with more than 100 addresses on
the profile then we need to limit the results to the most affected. This is achieved by using the
initial query result set as an inline view including an order clause in the main query to find the
10 profiles most affected.
select name_id, count_addresses from (select name_id, count(*) as count_addresses
from name_address
group by name_id
having count(*) > 100
order by 2 desc) /*this sorts the profiles by number of addresses in descending order*/
where rownum < 10 /*this limits the result set to the top 10 rows*/
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 8 of 56
Example 3 | Profile Contacts
You need to know which profiles have multiples of communication types. The table for this
information is name_phone. Stored in Opera is the phone role (e.g. BUSINESS, HOME etc..)
and the phone type (PHONE, EMAIL etc..) so it is necessary to include both these columns in
the group by clause to uncover the real duplicates.
select name_id, phone_type,phone_role, count(*)
from name_phone
group by name_id, phone_type, phone_role
having count(*) > 2
Example 4 | Duplicate Reservations
You need to check for duplicate reservations in ORS made for future dates that were emailed.
select resort, resv_name_id, to_char(a.delivery_date, 'HH24:MI') delivery_time, count(delivery_method)
from reservation_delivery_history a
where trunc(a.insert_date) >= '01-JAN-2013'
and a.delivery_method='EMAIL'
and a.status='5'
group by a.resort, a.resv_name_id, to_char(a.delivery_date, 'HH24:MI')
having count(delivery_method) > 2
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 9 of 56
Finding duplicates
Example 1 | A simple example to display the name and membership
card number of a profile/guest
You need to display the title first name, surname and membership details of a profile.
>Title, first name and surname are stored in the name table
select n.name_id, n.title, n.first, n.last from name n
>Membership type and membership card numbers are stored in the memberships table.
select m.name_id, m.membership_type, m.membership_card_no from memberships m
To join these 2 tables together use the name_id as the 1st filter in the where clause and
reference column names and tables names with letters.
select n.name_id, n.title, n.first, n.last, m.membership_type, m.membership_card_no
from name n, memberships m
where n.name_id=m.name_id
You can then add any additional filters as where clauses from either table:
select n.name_id, n.title, n.first, n.last, m.membership_type, m.membership_card_no
from name n, memberships m
where n.name_id=m.name_id
and n.last=’Persson’
and m.membership_type=’GUESTPR’
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 10 of 56
Example 2 | Comparing reservation creation to deliver to ORS
You need to unravel the path of a reservations delivery history in ORS/MYFIDELIO from the
time it was created to the time it was queued to be sent out of OXIHUB.
Firstly we find the reservations confirmation number, resv_name_id and creation time from the
reservation_name table.
select resv_name_id, confirmation_no, trunc(insert_date) from reservation_name where resort='DSHMICK' and
confirmation_no='1971013'
Then we need to find out the time it was created:
select resv_name_id, confirmation_no, TO_CHAR(insert_date, 'DD-MON-YYYY HH24:MI:SS') from reservation_name where
resort='DSHMICK' and confirmation_no='1971013'
When a reservation is created in ORS for delivery to resorts via OXIHUB the logging is stored
in the reservation_delivery_history table. From the script above find the resv_name_id of the
reservation and then use that to find the reservation delivery details of the reservation
(resv_name_id is the common denominator between the 2 tables).
select * from reservation_delivery_history where resv_name_id=550076
The reservation_delivery_history table stores ORS’s attempts to deliver a reservation including
failed attempts, retries etc…however for a normal reservation it looks like the above with 3
rows.
Because of this, and because we need to find out the latest of the three rows we use the
following script to find this:
select resort, resv_name_id, max(TO_CHAR(delivery_date, 'DD-MON-YYYY HH24:MI:SS')) delivery_time
from reservation_delivery_history
where resv_name_id='550076'
group by resort, resv_name_id
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 11 of 56
This is the time the reservation left ORS for OXIHUB.
Going back to reservation_name to find out the time the reservation was created we use:
select resv_name_id, confirmation_no, TO_CHAR(insert_date, 'DD-MON-YYYY HH24:MI:SS') insert_time
from reservation_name where resv_name_id='550076'
Now we can see the delay which is in this case is only a matter of seconds.
Once the reservation has left ORS it is queued into OXIHUB and appears like this on the
OHUB forms.
Messages being sent from OXIHUB to the resorts are stored in the oxihub schema in the
int_upload_status_vw view. Attributes of these messages can also be used in SQL to find
information about reservation delivery. The most important is enqueue_time which is the time
OXIHUB started to process the message from the queue to the destination.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 12 of 56
If you run this from Opera SQL:
select * FROM oxihub.int_upload_status_vw
No results will return since the view also stores the physical XML file (or a pointer to it) and
Opera SQL cannot display these. So you must list your column names individually to query
this view (and other like it for example reports and work_orders).
SELECT be_action_type, message_id, TO_CHAR(update_date, 'DD-MON-YYYY HH24:MI:SS') hub_enqueue_time, be_oh_ref
FROM oxihub.int_upload_status_vw
where be_oh_ref='1971013'
*be_oh_ref is the column that stores the reservation confirmation number.
So now you know the time the reservation was created in Opera (table | reservation_name),
the time it was processed from ORS to OXIHUB (table | reservation_delivery_history) and the
time it was queued up in OXIHUB (table | int_upload_status_vw). To compare the times
across each table it is necessary to join the results together to obtain an overall picture of what
is going on and if there is a delivery problem.
To join to tables together you need do 2 things:
>find at least one unique value in both tables that is the same and use them in the first where
clause of your query.
> name your tables with a letter or word and precede each column with that string in order to
control the results.
In this example we will use a subquery result set as the first table and the reservation_name
table as the second.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 13 of 56
select a.resort, a.resv_name_id, a.delivery_time, rn.confirmation_no, TO_CHAR(insert_date, 'DD-MON-YYYY HH24:MI:SS')
created
from
(select resort, resv_name_id, delivery_time from
(select resort, resv_name_id, max(TO_CHAR(delivery_date, 'DD-MON-YYYY HH24:MI:SS')) delivery_time
from reservation_delivery_history
where resv_name_id='550076'
group by resort, resv_name_id)) a, reservation_name rn/* a is the subquery being referenced as a table a*/
where a.resv_name_id=rn.resv_name_id
and a.resort=rn.resort
The results show in one table the delivery time (from reservation_delivery_history) and the
time the reservation was created (from reservation_name).
In another example we can compare creation time with the enqueue time in OXIHUB. This is a
simpler example and is a classic example of a simple join.
SELECT rn.resort, rn.confirmation_no, TO_CHAR(rn.insert_date, 'DD-MON-YYYY HH24:MI:SS') created, rn.res_insert_source,
TO_CHAR(UP.update_date, 'DD-MON-YYYY HH24:MI:SS') hub_enqueue_time
FROM oxihub.int_upload_status_vw UP, reservation_name rn
WHERE up.be_oh_ref=rn.confirmation_no
and up.be_oh_ref='1971013'
*each column is preceded by the referenced table e.g. rn.resort
*the common denominator is the reservation confirmation number and this is the 1 st where clause in the query
*in Opera SQL to reference tables in schemas other than opera you must precede the table name with the schema (oxi, oxihub).
By utilizing these two techniques the following results were revealed for a case and assisted in
pinpointing when the delay was occurring, at what point in the delivery process and the time
between creation and enqueue.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 14 of 56
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 15 of 56
Trunc function and dates
Consider the following query and the results.
select confirmation_no, insert_date from reservation_name
order by insert_date asc
From the results you would observe that there are 5 reservations that were created on the 5 th
April, right ? But when you run this query they are not being reported…
select count(*) from reservation_name where insert_date='20-APR-2011'
The reason is that within the DATE datatype Oracle is also storing a time in hours, minutes
and seconds and a where clause will not return results unless the match is exact.
To display the times you use this function on your column.
TO_CHAR(column_name, 'DD-MON-YYYY HH24:MI:SS')
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 16 of 56
Mostly this will be in the insert_date and update_date columns of opera tables. When using
functions such as COUNT against these columns always use the TRUNC function to suppress
the additional time details. So if you are looking for the number of reservations created on 20-
APR-2011 then you use…
select count(*) from reservation_name where trunc(insert_date)='20-APR-2011'
Now the 5 reservations appear.
To display the insert_date column as a time of day in addition to all other table columns you
can use this:
select a.*, TO_CHAR(a.insert_date, 'DD-MON-YYYY HH24:MI:SS')
from reservation_name a
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 17 of 56
ORS Initialization
Most of the details in a reservation are stored in 3 main tables….
reservation_name > confirmations, dates, sources, block ids
reservation_daily_element_name > profile ids (company, guest, group etc…)
reservation_daily_elements >rates (per day) and packages
Although it is possible to join these tables together in a three way join the sql becomes
unwieldy. It is much better in ORS to use the reservation_general_view which itself is based
on the values of these three tables.
In ORS if you run:
select * from reservation_general_view
You will receive this response:
So you have to individually select the columns.
select resv_name_id from reservation_general_view
In ORS this still returns no results as we need to initialize the view in Opera SQL.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 18 of 56
To do this enter the following in Opera SQL
BEGIN
reservation_i.search_in_all_property;
END;
Then use the same window for your query.
select resv_name_id from reservation_general_view
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 19 of 56
You can use this query as the basis for troubleshooting the issues you need to research.
select
resort,
resv_name_id,
resv_status,
arrival,
nights,
departure,
payment_method,
confirmation_no,
guest_name,
guest_first_name,
guest_name_id,
guarantee_code,
products,
promotions,
external_reference,
TO_CHAR(insert_date, 'DD-MON-YYYY HH24:MI:SS') insert_time,
insert_user,
update_date,
update_user,
discount_amt,
discount_prcnt,
membership_id,
membership_number,
membership_type,
membership_level,
adults,
children,
share_amount,
company_id,
travel_agent_id,
group_id,
source_id,
origin_of_booking_desc,
market_code,
rate_code,
allotment_header_id,
block_code,
room_category,
room_category_label,
no_of_rooms,
room,
effective_rate_amount,
currency_code,
total_revenue,
room_revenue,
fb_revenue,
channel,
res_insert_source,
res_insert_source_type,
physical_quantity,
block_id
from reservation_general_view
And apply your filters when necessary. Note > when querying reservation_name and
reservation_general_view the time it takes to return the response can be lengthy (where you
are hourglassed). Always try and include resv_name_id in the column listing and the where
filters (since this is the primary index on these objects) to try and make the script run faster.
This is not always possible if you are filtering on insert_date and looking for chronological
patterns however but it will improve response time.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 20 of 56
Date and Time Formatting
General
Examples of some format masks and these can all be used in group by clauses.
Earliest
to_char(min(update_date), 'DD-MON-YYYY HH24:MI:SS')
Latest
to_char(max(update_date), 'DD-MON-YYYY HH24:MI:SS')
By Hour
TO_CHAR(insert_date, ' HH24')
By Minute
TO_CHAR(update_date, ' HH24:MI')
By Year
TO_CHAR(update_date, ' YYYY')
Example
select
insert_date column_date,
trunc(insert_date) trunc_func,
TO_CHAR(insert_date, 'DD-MON-YYYY HH24:MI:SS') time,
to_char(insert_date, 'YYYY') year,
to_char(insert_date, 'MM') month,
to_char(insert_date, 'DD') day,
to_char(insert_date, 'MI') minutes,
to_char(insert_date, 'SS') seconds
from reservation_name
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 21 of 56
When troubleshooting aspects of Opera such as the Opera Purge or the OEDS rollover you
will need to calculate the date 180 days prior for example (or ahead). In order to do this you
can use the virtual table dual to hold your result.
You need to find out what was date 180 days ago.
select sysdate today, trunc(sysdate)-180 from dual
If you are exporting your data to a flat file for import into Excel and you are using a time
function on a column then you must add a pseudonym to your column otherwise Opera SQL
will not export it.
Example
select a.*, TO_CHAR(a.insert_date, 'DD-MON-YYYY HH24:MI:SS')
from reservation_name a
Hit the Export button on the Opera SQL form and the results do not export. Now try again with
a column name for the time
select a.*, TO_CHAR(a.insert_date, 'DD-MON-YYYY HH24:MI:SS') insert_time
from reservation_name a
And Opera obliges…
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 22 of 56
Calculating Time Permutations
For customers with GDS or Session Control functionality active then you can use the following
script to determine if there are reservations that are outside the purge interval as follows:
1. Find the session purge interval in minutes from the OEDS Configuration Editor:
2. Change the highlighted value in the script to match the value in minutes from the setting:
SELECT a.confirmation_no,
a.resv_status,
a.insert_date,
a.booking_source
FROM gds_reservation_header a
WHERE a.resv_status in ( 'SESSION_NEW', 'REINSTATE_CANCELLED','SESSION_CHANGE','SESSION_CANCEL')
AND a.update_date < sysdate - (90 / (24 * 60))
The results then are the reservations that are older than 90 minutes compared to the current
time. This is the critical clause…
AND a.update_date < sysdate - (90 / (24 * 60))
The same method and technique can be applied to any investigation where small amounts of
time are required for research. Use this to get and check your timings before adding the filter
to the main script.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 23 of 56
select systimestamp, TO_CHAR(time, 'DD-MON-YYYY HH24:MI:SS') time
from
(select sysdate, sysdate - (90 / (24 * 60)) time from dual)
90 minutes
select systimestamp, TO_CHAR(time, 'DD-MON-YYYY HH24:MI:SS') time
from
(select sysdate, sysdate - (240/ (24 * 60)) time from dual)
4 hours
OEDS Rollover
The Rollover functionality in OEDS is also an area where Oracle dates and their manipulation
can help with support troubleshooting. In this example we see the customer has set Future
Rate Upload Days as 365. This means then that on the 365th day at 23:59:59 the OEDS
rollover should be pushing the rates out to Expedia so that the 366th days rates are
automatically updated. Use of Oracle date calculations and manipulations can assist this, see
enclosed script.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 24 of 56
SELECT name, /*this is the name of the channel*/
sysdate today, /*today’s date*/
max_dataload_days max_rate_days, /*the number of days set from the CHANNEL_SETUP form above*/
(sysdate + max_dataload_days) rate_future, /*today’s date plus the number of max days and the date that represents*/
rate_rollover_date /*the actual date the rollover last calculated*/,
future_availability_days /*the number of days in the future availability needs to be published*/,
(sysdate+ future_availability_days) avail_future /*todays date plus the value of the availability days parameter*/,
last_rollover_date /*the date as per the last rollover*/,
initial_upload_days /*the number of initial upload days for inventory*/,
update_date /* the date the user last updated the channel configuration on this form*/
FROM gds_hosts
WHERE inactive_date IS NULL
AND gds_host ='EXPEDIA'
And the results are as follows:
Here we can see the rollover is behind since rate_rollover_date should be the same as
rate_future however this example is just to illustrate date manipulation using sysdate and
existing date column values.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 25 of 56
Calculating the duration between 2 times
You need to calculate the difference between 2 timestamps. Using the following script replace
the start_time and end_time with the times whose difference you need to calculate. The output
is in days/hours/minutes
DECLARE
start_time TIMESTAMP := TIMESTAMP '2014-05-06 10:11:00.00';
end_time TIMESTAMP := TIMESTAMP '2014-05-07 04:40:30.00';
diff INTERVAL DAY TO SECOND;
BEGIN
diff := end_time-start_time;
DBMS_OUTPUT.PUT_LINE('Time difference is'|| diff);
END;
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 26 of 56
How to find number of rows in a table between two timestamp using
BETWEEN
select a.*, TO_CHAR(a.insert_date, 'DD-MON-YYYY HH24:MI:SS') insert_time
from oeds_request_monitor a
where trunc(request_date)='07-JAN-2013'
and request_source='GDS'
and insert_date
BETWEEN
to_date('07-JAN-2013 15:00:00','DD-MON-YYYY HH24:MI:SS')
and
to_date('07-JAN-2013 15:45:10','DD-MON-YYYY HH24:MI:SS')
GROUP BY with dates
By Year
select count(*), to_char(insert_date, 'YYYY')
from name
group by to_char(insert_date, 'YYYY')
By Hour
select TO_CHAR( insert_date, 'DD-MON-YYYY HH24') Day_Hour, count(*)
from int_upload_status_vw
group by TO_CHAR( insert_date, 'DD-MON-YYYY HH24')
By Minute
select TO_CHAR(update_date, ' HH24:MI') time, count(echo_token) number_messages
from gds_avail_upd_message
where gds_host='EXPEDIA'
and trunc(update_date)> '04-MAR-2014'
group by rollup(TO_CHAR(update_date, ' HH24:MI'))
order by 1 asc
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 27 of 56
How and when to use NVL
When using aggregate or grouping functions sometimes column values are not populated with
a value and are deemed to be NULL. Especially for revenue amounts it is important to counter
omitted values by using NVL function to replace null with 0 since this effectively counteracts
the omission of the target column and forces Oracle to consider those values.
Example
select table_name, num_rows, avg_row_len from dba_tables
SELECT owner, table_name, num_rows*avg_row_len bytes
FROM dba_tables
WHERE table_name='ATEMPTAB$'
ORDER BY owner,table_name
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 28 of 56
SELECT owner, table_name, nvl(num_rows*avg_row_len, 0) bytes
FROM dba_tables
WHERE table_name='ATEMPTAB$'
ORDER BY owner,table_name
A script to show the largest tables in the schema
SELECT owner, table_name, nvl(num_rows*avg_row_len, 0) bytes
FROM dba_tables
where owner=’DAN’
ORDER BY 3 desc
Another example where NVL is used to populate any missing column values from
allotment_date.allotment_detail .
delete from allotment_detail where room_category in (10040,10041) and resort='BE1602' and
NVL(allotment_date,(pms_p.business_date-100))>=pms_p.business_date
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 29 of 56
How to use DECODE
DECODE takes a string of values and converts them into user specified values.
Example
select parameter_name, parameter_type, decode(parameter_type, 'F', 'Function', 'P', 'Parameter', 'S', 'Setting', NULL) decoded
from application_parameters
where resort='DSHU02'
order by 1 asc
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 30 of 56
How to use CASE
CASE function has superceded DECODE now since it has additional evaluation features
relating to calculations that DECODE does not have i.e. you can do things with CASE that you
can’t do with DECODE but no vice versa.
Example
SELECT a.resort ,
a.name ,
c.country_name ,
a.region_code ,
a.currency_code,
a.begin_date ,
a.end_date ,
CASE
WHEN b.INTERFACE_ID = 'OXI-V6'
THEN 'V6 IFC'
WHEN b.INTERFACE_ID = 'OXI-OPERA'
THEN 'OPERA IFC'
WHEN b.INTERFACE_ID = 'OXI-V7'
THEN 'NON-IFC'
ELSE 'NOT_DEFINED_RECORD'
END AS interface_id
FROM resort a ,
int_interface_setup b,
country$ c
WHERE a.RESORT=b.PMS_RESORT
AND a.resort LIKE 'K%'
AND a.resort !='KEMPI'
AND a.country_code =c.country_code
AND b.interface_id IN ('OXI-V6','OXI-OPERA','OXI-V7')
ORDER BY c.country_name, a.resort
Both DECODE and CASE are useful when you need to export data from Opera SQL and are
sending the information to the customer as formatting techniques.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 31 of 56
How to use SUBSTR
SUBSTR takes a value in the column and then displays the string length and at the start point
of the user values. The following examples show examples from the profile_action table since
I have found for support purposes the function is quite handy. The profile_action table contains
the change log for profiles. The SUBSTR function is useful for both searching and export
purposes. The action_description column contains the history of what actually happened to the
profile at that time.
Example
We have 3 columns in a table
select action_id, action_type, action_description
from profile_action
where action_type=’NEW PROFILE’
So if we use SUBSTR we can cut out un-necessary verbiage CREATED NEW PROFILE and
just see the names of the profiles created.
select action_id, action_type, substr(action_description, 20, 50)
from profile_action
where action_type='NEW PROFILE'
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 32 of 56
substr(action_description, 20, 50)
20 is the number of characters to start the string from in this case 20 since CREATED NEW
PROFILE is 20 characters long so to omit this we start at character 20 in the string.
50 is the number of characters to cease displaying following the 20th character. This is useful
since many times when exporting data from profile_action during the import into Excel the
amount of data in the column wraps around Excel and formatting is either skewed or
impossible. So use SUBSTR to find just what you want and export that.
You can also use SUBSTR as a filter like this…
select action_id, action_type, substr(action_description, 20, 50)
from profile_action
where action_type='NEW PROFILE'
and substr(action_description, 20, 50) like '%Tour serie%'
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 33 of 56
How to use ROLLUP
ROLLUP function works in a similar way to Excels subtotal functionality in that it creates a
subtotal at the bottom of each group
Example
select resort, room_label, sum(nvl(room_revenue,0))
from stay_records
group by resort, room_label
order by 1, 2
Here we can see the room revenue per room per resort. But what if we wanted to see a
subtotal for each resort calculating all the revenue from all the rooms.
select resort, room_label, sum(nvl(room_revenue,0))
from stay_records
group by resort, rollup(room_label)
order by 1, 2
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 34 of 56
The functions add another row into the result set subtotaling the revenue for all the rooms per
resort.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 35 of 56
How to use ROUND
ROUND can be used to control the display of decimal places in the result set. To take the
previous example …
To display the revenue values as they exist at the moment.
select resort, room_label, sum(nvl(room_revenue,0))
from stay_records
group by resort, rollup(room_label)
order by 1, 2
At the moment value + 2 decimal places are showing in the 3rd column. By using ROUND we
can see how this is showing like so
select resort, room_label, sum(nvl(room_revenue,2))
from stay_records
group by resort, rollup(room_label)
order by 1, 2
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 36 of 56
The results are the same. To suppress the decimal points we just change the value in the nest
for ROUND.
select resort, room_label, sum(nvl(room_revenue,0))
from stay_records
group by resort, rollup(room_label)
order by 1, 2
You can also go the other way and round to the nearest 100.
select resort, room_label, round(sum(nvl(room_revenue,0)),-2)
from stay_records
group by resort, rollup(room_label)
order by 1, 2
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 37 of 56
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 38 of 56
How to use OR
Example
select resort, room_label,room_revenue
from stay_records
where room_revenue > 100 or resort='DSHU02'
In this condition the results return any row where resort is DSHU02 and room_revenue is
above 100. Care should be taken when using OR and the following needs to be considered,
when combining 2 expressions with OR the following applies
The OR Truth Table
OR TRUE FALSE NULL
TRUE TRUE TRUE TRUE
FALSE TRUE FALSE NULL
NULL TRUE NULL NULL
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 39 of 56
To take another example:
Select resort, room_label,room_revenue
from stay_records
where resort='DSHU02' OR
resort='DSHTEST'
and room_revenue > 100
The results are not what we expected or wanted, why are there rows showing revenue lower
than 100 ?
This is because in the Rules of precedence the following equates to
‘select the row if the revenue is above 100 and the resort is DSHTEST OR if the resort is
DSHU02.’
The Rules of Precedence
Order Evaluated Operator
1 Arithmetic operators
2 Concatenation operator
3 Comparison conditions
4 IS [NOT] NULL, LIKE, [NOT] IN
5 [NOT] BETWEEN
6 NOT logical condition
7 AND logical condition
8 OR logical condition
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 40 of 56
To force override the rules of precedence you wrap your preferred expression in parentheses
like this….
Select resort, room_label,room_revenue
from stay_records
where (resort='DSHU02' OR
resort='DSHTEST')
and room_revenue > 85
This now translates as > all the rows over 85 for ONLY DSHTEST and DSHU02.
Further example of OR
SELECT 'x'
FROM
ALLOTMENT_HEADER WHERE ( CONTACT_NAME_ID = :B1 OR MASTER_NAME_ID
= :B1 OR
SOURCE_NAME_ID = :B1 OR AGENT_NAME_ID = :B1 OR COMPANY_NAME_ID = :B1 )
AND
INACTIVE_DATE IS NULL
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 41 of 56
How to find dependant foreign keys
If you perform a search in Clarify solutions using strings such as
ORA%key
ORA%constraint
ORA%unique
You will find many cases with ORA-02291: integrity constraint, ORA-02292 integrity constraint.
This usually means that the user is trying to delete data that has a relationship to other data
and that has to either be removed first or in reverse order. To find the columns and tables
containing the data you can use this script to find the ‘foreign keys’. Just replace the table
name.
SELECT UC.TABLE_NAME,
UC.R_CONSTRAINT_NAME,
UCC.TABLE_NAME,
UCC.COLUMN_NAME
FROM USER_CONSTRAINTS UC,
USER_CONS_COLUMNS UCC
WHERE UC.R_CONSTRAINT_NAME = UCC.CONSTRAINT_NAME
AND uc.constraint_type = 'R'
and ucc.table_name='APP$_MODULES'
ORDER BY UC.TABLE_NAME,
UC.R_CONSTRAINT_NAME,
UCC.TABLE_NAME,
UCC.COLUMN_NAME
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 42 of 56
In this example user is trying to delete a confirmation letter from app$_modules but receives
this error. This is because the MODULE_ID column has a foreign key constraint on other
tables containing the same value.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 43 of 56
How to find and replace special characters
Using OR and LIKE
SELECT resort, rate_code, description
FROM rate_header
WHERE ( resort IN
(SELECT resort FROM resort WHERE end_date IS NULL
)
AND resort IN
(SELECT resort
FROM gds_conv_resorts
WHERE gds_host IN
(SELECT gds_host FROM gds_hosts WHERE channel_type='GDS'
)
))
AND (lower(description) LIKE '%é%'
OR lower(description) LIKE '%ù%'
OR lower(description) LIKE '%û%'
OR lower(description) LIKE '%ô%'
OR lower(description) LIKE '%à%'
OR lower(description) LIKE '%â%'
OR lower(description) LIKE '%è%'
OR lower(description) LIKE '%ê%'
OR lower(description) LIKE '%ß%'
OR lower(description) LIKE '%€%'
OR lower(description) LIKE '%ü%'
OR lower(description) LIKE '%$%'
OR lower(description) LIKE '%£%'
OR lower(description) LIKE '%!%'
OR lower(description) LIKE '%(%'
OR lower(description) LIKE '%)%'
OR lower(description) LIKE '%/%'
OR lower(description) LIKE '%–%')
ORDER BY 1
Using INSTR
select * from gds_conv_room_desc_globals
where instr(rd3, chr(14844051))!='0'
/*where gds_conv_room_desc_globals is the table name and rd3 is the column name */
To find the ASCII number for a character for example run
select ascii('é') from dual
50089
And then you replace that in the CHR(n) in the above script to find them.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 44 of 56
select resort, description from rate_header
where instr(description, chr(50102))!='0'
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 45 of 56
Using ow_pattern_match
BEGIN
FOR t IN (SELECT * FROM gds_conv_rate_codes where RESORT ='830' and to_CHAR(end_date,'DD-MON-YYYY') >
TO_CHAR(SYSDATE,'DD-MON-YYYY') order by gds_host,resort )
LOOP
IF
owa_pattern.match(t.rate_code, '^CS+[0-9]$') OR
owa_pattern.match(t.rate_code, '^CP+[0-9]$') OR
owa_pattern.match(t.rate_code, '^SPOR+[0-9]$') OR
owa_pattern.match(t.rate_code, '^OB+[0-9]$') OR
owa_pattern.match(t.rate_code, '^OD+[0-9]$') OR
owa_pattern.match(t.rate_code, '^CRRA+[0-9]$')THEN
Dbms_Output.Put_Line(t.gds_host||','||t.resort||','||t.Rate_Code||','||t.gds_rate_code);
END IF;
END LOOP;
END;
Assertions:
^ Matches the beginning of a line (or string)
$ Matches the end of a line (or string)
Quantifiers:
{n,m} Must match at least n times, but not more than m times
{n,} Must match at least n times
{n} Must match exactly n times.
* 0 or more occurances
+ 1 or more occurances
? 0 or 1 occurance(s)
Legal atoms:
. matches any character except \n
A list of characters in square brackets [] is a class of characters,
for example [0-9] indicates match any character from 0 to 9.
\n matches newlines
\t matches tabs
\d matches digits [0-9]
\D matches non-digits [^0-9]
\w matches word characters (alphanumeric) [0-9a-z_A-Z]
\W matches non-word characters [^0-9a-z_A-Z]
\s matches whitespace characters [ \t\n]
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 46 of 56
\S matches non-whitespace characters [^ \t\n]
\b matches on “word” boundaries (between \w and \W)
A backslashed x followed by two hexadecimal digits, such as \x7f,
matches the character having that hexadecimal value.
A backslashed 2 or 3 digit octal number such as \033 matches the
character with the specified value.
Any other “backslashed” character matches itself.
How to replace special characters
Let say you have a transaction code description with the word 'Pokòj' in it. You want to replace
this word with Pokoj. The syntax is as follows:
select * from trx$_code_arrangement where resort='V7TEST' and type='EB' and arrangement_desc like '%Po%'
update trx$_code_arrangement set arrangement_desc=REPLACE (arrangement_desc, 'Pokòj', 'Pokoj') where resort ='V7TEST'
and arrangement_desc like '%Pokòj%'
This replaces the column values (all of the matching the query filters ) where the column value
is 'Pokòj' with 'Pokoj'.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 47 of 56
How to use concatenation
Concatention is the combining together of more than one column into one. Again the most
useful purpose is with profiles.
There are 2 ways to use concatenate the function CONCAT and the || operators. Both perform
the same function.
If you just have 2 columns to join you can use CONCAT
select concat(address1, city) from name_view
If you need more then use the alternative || operator.
select address1||address2||address3||address4||city||state||country||zip_code from name_view
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 48 of 56
How to find the transaction code rollup for
a PMS reservation
Often there is a revenue comparison issue between PMS and ORS for interfaced resorts
usually related to revenue bucket configuration. To break down the issue by reservation you
can use the following script….
SELECT resv_name_id,
tc_group,
trx_code,
SUM(trx_amount),
SUM(posted_amount),
SUM(revenue_amt)
FROM
(SELECT resv_name_id,
net_amount,
gross_amount,
tax_inclusive_yn,
tc_group,
trx_code,
trx_amount,
posted_amount,
revenue_amt
FROM financial_transactions
WHERE resv_name_id IN
(SELECT resv_name_id
FROM reservation_name
WHERE confirmation_no IN ('10521873', '10521871', '10068208', '10967639')
)
ORDER BY resv_name_id,
tc_group,
trx_code
)
GROUP BY resv_name_id,
tc_group,
trx_code
ORDER BY 1,2,3
Replace the yellow values with your PMS confirmation numbers.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 49 of 56
How to use subqueries
As an alternative to joining tables together you can also use subqueries to view the results
from 2 tables.
Example.
select * from name
where name_id
in
(select name_id from reservation_name where trunc(end_date) > sysdate)
The columns in the where filter must match the columns in the subquery.
There can be several ‘layers’ of nesting (performance depending of course).
The above example displays all the profile information in the name table for the guests with
future reservations.
Using 2 columns togeter
select sr.resort, sr.pms_resv_no, /*^*/sr.crs_book_no
from stay_records sr
where (sr.resort, sr.pms_resv_no)
IN
(select resort, pms_resv_no
from stage_stay_records
where resort='KIMUC1'
and stage_stay_record_id in
(select stage_stay_record_id from stage_stay_errors where error_desc like '%Membership points %' ))
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 50 of 56
How to compare the application parameters
between 2 different resorts in the same
schema
select p1.parameter_group p_group,
p1.parameter_name int_name,
p1.parameter_display app_name,
p1.parameter_type p_type,
p1.parameter_value value1,
p2.parameter_value value2,
p1.display_yn visible_1,
p2.display_yn visible_2
from application_parameters p1,
application_parameters p2
where p1.parameter_name = p2.parameter_name
and p1.resort = 'AF'
and p2.resort = 'EU'
and p1.parameter_value <> p2.parameter_value
order by p_group, app_name
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 51 of 56
PL/SQL
Initialazation examples
begin
pms_p.initialize('SUPERVISOR','BETTERTHANV6','RESORT');
end;
*password must always be in CAPS*
BEGIN
reservation_i.search_in_all_property;
END;
/
- initialise to a specific date!!!!PER RESORT ONLY !!!
BEGIN
PMS_P.INITIALIZE(IN_USER=> 'NA_REPORTS',
IN_PASSWORD=> 'NA_REPORTS',
IN_RESORT=> 'HRKWA',
IN_BUSINESS_DATE=> '05-AUG-10');
END;
/
BEGIN
PMS_P.INITIALIZE(IN_USER=> 'SUPERVISOR',
IN_PASSWORD=> 'betterthanv7',
IN_RESORT=> 'VSL');
END;
/
ORS Alternative
begin
pms_p.initialize('SUPERVISOR', 'PASSWORD','CRO');
reservation_i.search_in_all_property;
olc.set_running_app('ORS');
end ;
/
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 52 of 56
Example of PL/SQL to resolve possible issue in DC
DECLARE
vBckDate VARCHAR2(200) := TO_CHAR(sysdate,'DDMM');
BEGIN
EXECUTE immediate 'create table BCK_REPORT_LOG_'||vBckDate||' AS
SELECT * FROM opera.report_log';
EXECUTE IMMEDIATE 'TRUNCATE TABLE opera.report_log';
END;
/
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 53 of 56
PL/SQL use in the troubleshooting the purge
select name_id,display_name
from name_view
where Purge_Pkg.can_purge_profile_yn(name_id,90,'N') = 'Y'
and name_type in ('D', 'PURGE')
and nvl (contact_yn, 'N') = 'N'
/
purge_Pkg | the package
can_purge_profile_yn | a procedure in the package
name_id | name_id of the assessed profile
90 | the PURGE DAYS application parameter
N | the Keep History flag on the profile
PL/SQL example with cursor
DECLARE
v_insert_user NUMBER :=130;
v_name VARCHAR2(20);
BEGIN
SELECT app_user
INTO v_name
FROM application$_user
WHERE app_user_id= v_insert_user;
DBMS_OUTPUT.PUT_LINE('The user is '||v_name);
END;
/
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 54 of 56
Monitored Alerts example
OXIHUB logs alert
DECLARE
v_zoxioperapar_nr NUMBER;
v_znoofdayspurge_nr NUMBER;
BEGIN
SELECT a.parameter_value
INTO v_zoxioperapar_nr
FROM oxihub.int_parameters a
WHERE a.parameter_name='PURGE_NO_DAYS'
AND a.parameter_group ='OXI_GENERIC'
AND a.interface_id ='OXI-OPERA';
SELECT COUNT(DISTINCT(TRUNC(c.enq_time)))
INTO v_znoofdayspurge_nr
FROM oxihub.int_xmlstatqueue_vw c;
IF v_znoofdayspurge_nr > v_zoxioperapar_nr + 2 THEN
dbms_output.put_line('1');
ELSE
dbms_output.put_line('0');
END IF;
END;
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 55 of 56
How to remove ASP mode when querying multi chain databases
If your queries are returning no results then it could be that the site you are working in is in
ASP mode. This compartmentalizes brands into chains and wraps viewership rigths around
the resorts in the database. Examples of brands with ASP mode.
Accor
Starwood
Marriott
Louvre
To check if the site you are working in is in ASP mode you can run this query.
select * from asp_mode
This returns a Y or N answer.
To break the link/connection in your Opera SQL session perform the following.
begin
asp.invalidate_context('NULL');
end;
Then your queries filtered by resort will apply to all resorts in the database.
Oracle SQL Advanced Course
Mark Cook
EAME Regional Support
21/05/2014
Document version 1.0
Page 56 of 56