Jan 24, 2014

LEFT OUTER JOIN: Oracle HR Employee Phones


If you ever worked with PER_PHONES table in Oracle EBS to get the employee phones, you must have seen that PER_PHONES table contains multiple lines for different phone types for an employee.

For example, if I run the following query for an employee whose PERSON_ID is 1444, I get three records:

SELECT *
  FROM per_phones p
 WHERE 1=1
   AND p.parent_id = 1444;





You can run the following query to get the meaning of the phone types:

SELECT lookup_type,
       lookup_code,
       meaning
  FROM hr_lookups
 WHERE 1=1
   AND lookup_type  = 'PHONE_TYPE'
   AND enabled_flag = 'Y';














Now the problem is, when you connect this PER_PHONES (parent_id) table with PER_ALL_PEOPLE_F (person_id) table , you end up with multiple rows. In the above example, it will return three rows.

Now of course, the client will never want to see more than one row per employee. In my case, the client specifically asked for a condition which goes like: pick up Mobile Phone of the employee first; if Mobile Phone is NULL, then pick up Home Phone; if Home Phone is NULL, then pick up Work Phone, and so on.

I assumed that there would already be a view for this from Oracle. Since I did not find any, I had to come up with a query (to create a custom view) to avoid multiple rows per employee, using LEFT OUTER JOIN function.


SELECT
       pp.parent_id      parent_id,
       pp.parent_table   parent_table,
       --
       ppm.phone_number  mobile_phone,
       pph.phone_number  home_phone,
       ppw.phone_number  work_phone,
       ppo.phone_number  other_phone
  FROM
       (SELECT DISTINCT
               parent_id,
               parent_table
          FROM per_phones
       ) pp
  -- mobile phone
  LEFT OUTER JOIN per_phones  ppm
    ON (     ppm.phone_type   = 'M'
         AND ppm.parent_id    = pp.parent_id
         AND ppm.parent_table = pp.parent_table
       )
  -- home phone
  LEFT OUTER JOIN per_phones  pph
    ON (     pph.phone_type   = 'H1'
         AND pph.parent_id    = pp.parent_id
         AND pph.parent_table = pp.parent_table
       )
  -- work phone
  LEFT OUTER JOIN per_phones  ppw
    ON (     ppw.phone_type   = 'W1'
         AND ppw.parent_id    = pp.parent_id
         AND ppw.parent_table = pp.parent_table
       )
  -- other phone
  LEFT OUTER JOIN per_phones  ppo
    ON (     ppo.phone_type   = 'O'
         AND ppo.parent_id    = pp.parent_id
         AND ppo.parent_table = pp.parent_table
       )
 WHERE 1 = 1;





Hopefully, this is helpful. However, if there is any other query which may be useful, I would certainly love to hear or know about it.

3 comments:

MegsA said...

How do I incorporate this query into a query for Employee listing, without selecting too many rows?

Rafeeuddin Shaik said...

you have use same table for each phone type in the same query.

AND TRUNC(LEAST(NVL(ppos.actual_termination_date+1,cp_effective_date),cp_effective_date)) BETWEEN papf.effective_start_date AND papf.effective_end_date
AND papf.person_id=paaf.person_id
AND TRUNC(LEAST(NVL(ppos.actual_termination_date+1,cp_effective_date),cp_effective_date)) BETWEEN paaf.effective_start_date AND paaf.effective_end_date
AND paaf.pay_basis_id =ppb.pay_basis_id (+)
AND paaf.position_id = pos.position_id(+)
AND papf.person_id = paddr.person_id (+)
AND paaf.payroll_id = payf.payroll_id
AND TRUNC(cp_effective_date)BETWEEN payf.effective_start_date AND payf.effective_end_date
AND papf.person_id = work_phone.parent_id(+)
AND work_phone.parent_table(+)='PER_ALL_PEOPLE_F'
AND work_phone.phone_type(+)= 'W1'
AND TRUNC(cp_effective_date) BETWEEN TRUNC(NVL(work_phone.date_from,cp_effective_date)) AND TRUNC(NVL(work_phone.date_to,cp_effective_date))
AND papf.person_id = mobile.parent_id(+)
AND mobile.parent_table(+)='PER_ALL_PEOPLE_F'
AND mobile.phone_type(+)= 'M'
AND TRUNC(cp_effective_date) BETWEEN TRUNC(NVL(mobile.date_from,cp_effective_date)) AND TRUNC(NVL(mobile.date_to,cp_effective_date))
AND papf.person_id = home_phone.parent_id(+)
AND home_phone.parent_table(+)='PER_ALL_PEOPLE_F'
AND home_phone.phone_type(+)= 'H1'

MegsA said...

THank you. THis is my code for the Employee Listing I want to incorporate the Left Outer Join code into it so that I get one row per EMployee:

SELECT distinct papf.employee_number "Employee Number",
haou.name "Department", pjobs.name "Job", ppos.name "Position", pgrade.name "Grade",
papf.first_name "First Name", papf.middle_names "Middle Names", papf.last_name "Last Name",
(select distinct meaning from apps.hr_lookups hrlnat, apps.per_all_people_f papf where hrlnat.Lookup_type = 'NATIONALITY' and hrlnat.lookup_code= 'TT' and papf.nationality = 'TT') "NATIONALITY" ,
pad.address_line1 , pad.address_line2 , pad.address_line3 ,
(select distinct ftt.TERRITORY_SHORT_NAME from apps.per_addresses pad,apps.fnd_territories_tl ftt where ftt.TERRITORY_CODE = 'TT') "COUNTRY",
papf.email_address "E-mail",
pad.telephone_number_1,


hrlsex.meaning "Sex",
hrlms.meaning "Marital Status",
papf.national_identifier "National ID",
papf.ATTRIBUTE1 "BIR No.",
TO_CHAR(papf.date_of_birth, 'DD-MON-RRRR') "Birth Date",
TO_CHAR(papf.original_date_of_hire, 'DD-MON-RRRR') "Hire Date"


FROM apps.per_all_people_f papf,
apps.per_all_assignments_f paaf,
apps.per_person_types_tl ppt,
apps.hr_lookups hrlsex,
apps.hr_lookups hrlnat,
apps.hr_lookups hrlms,
apps.hr_lookups hrleg,
apps.hr_lookups hrlat,
apps.per_jobs pjobs,
apps.per_all_positions ppos,
apps.per_addresses pad,
hr.per_phones phn,
apps.per_grades_tl pgrade,
apps.per_business_groups pbus,
hr.hr_all_organization_units haou,
apps.fnd_territories_tl ftt
WHERE 1 = 1
AND ppt.user_person_type = 'Employee'
AND haou.name not in ('Pensioner Organisation', 'Central Bank of Trinidad and Tobago') AND haou.name not like 'Retiree%' AND haou.name not like '%Pension%' AND haou.name not like 'Executive%'
AND ppos.name not like '%Director%' AND pjobs.name not like '%Manager%' AND pjobs.name not like '%Governor%'
AND pgrade.NAME not like 'MAN%'
AND hrlat.meaning = 'Primary Home Address'
AND hrlat.lookup_code(+) = pad.address_type
AND hrlat.lookup_type(+) = 'ADDRESS_TYPE'
AND hrlsex.lookup_code(+) = papf.sex
AND hrlsex.lookup_type(+) = 'SEX'
AND hrlnat.lookup_code(+) = papf.nationality
AND hrlnat.lookup_type(+) = 'NATIONALITY'
AND hrlms.lookup_code(+) = papf.marital_status
AND hrlms.lookup_type(+) = 'MAR_STATUS'
AND hrleg.lookup_code(+) = papf.per_information1
AND hrleg.lookup_type(+) = 'US_ETHNIC_GROUP'
AND ftt.territory_code(+) = pad.country
AND pad.business_group_id(+) = papf.business_group_id
AND pad.date_to IS NULL
AND papf.person_id = phn.parent_id
AND pad.person_id(+) = papf.person_id
AND pgrade.grade_id(+) = paaf.grade_id
AND haou.organization_id(+) = paaf.organization_id
AND haou.business_group_id(+) = paaf.business_group_id
AND pbus.business_group_id(+) = paaf.business_group_id
AND ppos.position_id(+) = paaf.position_id
AND pjobs.job_id(+) = paaf.job_id
AND ppt.person_type_id(+) = papf.person_type_id
AND TRUNC(SYSDATE) BETWEEN paaf.effective_start_date AND
paaf.effective_end_date
AND paaf.person_id = papf.person_id
AND TRUNC(SYSDATE) BETWEEN papf.effective_start_date AND
papf.effective_end_date