I am trying to solve the matching of different customers, from different entities. Using only SQL select and "with" syntax, no PL/SQL. Below is a simple example. There are three customers, who are each 3 different individuals, but are recorded slightly different in different entities (1,2,3). I am matching them by P1, P2 and P3 field. In addition, P2 and P3 needs to have a cross-field check.
Customer David - only in entity 1 and 2, in both entities has P1 = 100. Easy match. Gets 'G1'
Customer Lloyd - only in entity 1 and 3, matches with cross-field check of P2 = P3. Gets 'G2'
Customer Mark - in all three entities. In entity 1 and 3 they match by P1. But the row in entity 2 matches only with cross-field check with entity 1, P2. This person needs to have 'G3' assigned in all three entities. Thoughest case.
The G, eg. G3243 represents customer's unique group ID. It is the same for one customer inside different entities and different from all other customers' Group IDs.
Any ideas how to do this? Sample table below:
table
sample data:
with
sample as (
select 1 as entity, 'DAVID' as customer, 100 as P1, 'hjk' as P2, null as P3 from dual
union all
select 2 as entity, 'DAVID' as customer, 100 as P1, 'heeee' as P2, null as P3 from dual
union all
select 1 as entity, 'Lloyd' as customer, null as P1, 'dfe' as P2, null as P3 from dual
union all
select 1 as entity, 'LLOYD' as customer, null as P1, null as P2, 'dfe' as P3 from dual
union all
select 1 as entity, 'MARK' as customer, 300 as P1, 'abc' as P2, null as P3 from dual
union all
select 2 as entity, 'MARC' as customer, 0 as P1, null as P2, 'abc' as P3 from dual
union all
select 3 as entity, 'Mark' as customer, 300 as P1, 'texttt' as P2, null as P3 from dual
)
select * from sample;
If I got it right the expected outcome should say how many correlations are present in the data for each customer. Column P1 is considered on its own and columns P2 and P3 define possible additional ties if they are cross related. Here is one possible solution using your initial sample data.
I try to count relations on columns P1, P2 and P3 by creating cte ("sample_counts")
sample_counts AS
(
Select
s1.ENTITY "ENTITY",
UPPER(s1.CUSTOMER) "CUSTOMER",
Max(CASE WHEN s1.P1 Is Not Null THEN 1 ELSE 0 END) "CNT_P1",
Max((Select Count(*) From sample Where P2 = s1.P3 )) "CNT_P2_P3",
Max((Select Count(*) From sample Where P3 = s1.P2 )) "CNT_P3_P2",
Max(Nvl((Select UPPER(CUSTOMER) From sample Where P2 = s1.P3 ), UPPER(s1.CUSTOMER))) "CUSTOMER_2"
From
sample s1
Group By
UPPER(s1.CUSTOMER), s1.ENTITY
Order By
UPPER(s1.CUSTOMER), s1.ENTITY
)
/*
"sample_counts" (cte) resulting dataset
ENTITY CUSTOMER CNT_P1 CNT_P2_P3 CNT_P3_P2 CUSTOMER_2
---------- -------- ---------- ---------- ---------- ----------
1 DAVID 1 0 0 DAVID
2 DAVID 1 0 0 DAVID
1 LLOYD 0 1 1 LLOYD
2 MARC 1 1 0 MARK
1 MARK 1 0 1 MARK
3 MARK 1 0 0 MARK
*/
The resulting dataset gives us counts of relations (as 1 or 0) over different columns for each customer and did some naming unification in column CUSTOMER_2. Even from this dataset it is obvious that David has just one level of correlations (CNT_P1), that Lloyd has two levels by cross joinning CNT_P2 and CNT_P3 (none on CNT_P1), and finally that Mark (or Marc) has correlation on all three columns. As dataset is grouped by, in the main SQL we should join it to your sample data in order to get all rows but now with Gx representing the group correlations as G1, G2, G3.
Here is the final SQL with the result:
SELECT
sc.ENTITY "ENTITY",
sc.CUSTOMER_2 "CUSTOMER",
s.P1 "P1",
s.P2 "P2",
s.P3 "P3",
'G' || To_Char(
Max(CNT_P1) OVER (PARTITION BY sc.CUSTOMER_2 ORDER BY sc.CUSTOMER_2) +
Max(CNT_P2_P3) OVER (PARTITION BY sc.CUSTOMER_2 ORDER BY sc.CUSTOMER_2) +
Max(CNT_P3_P2) OVER (PARTITION BY sc.CUSTOMER_2 ORDER BY sc.CUSTOMER_2)
) "GRP"
FROM
sample_counts sc
INNER JOIN
sample s ON(s.ENTITY = sc.ENTITY And UPPER(s.CUSTOMER) = sc.CUSTOMER)
ORDER BY
CUSTOMER_2, ENTITY
--
-- R e s u l t :
--
-- ENTITY CUSTOMER P1 P2 P3 GRP
-- ---------- -------- ---------- ------ --- --------
-- 1 DAVID 100 hjk G1
-- 2 DAVID 100 heeee G1
-- 1 LLOYD dfe G2
-- 1 LLOYD dfe G2
-- 1 MARK 300 abc G3
-- 2 MARK 0 abc G3
-- 3 MARK 300 texttt G3
If you want to have the original customer name from your data then just select s.CUSTOMER here (instead of sc.CUSTOMER_2).
Try it with your actual data. I realy do hope this would be usefull. Regards...
A D D I T I O N
Please try this code on your data. I added a few more rows (John and Anne) in the sample data and changed the code according to the comments. Hope it could help you now:
with
sample as
(
select 1 as entity, 'DAVID' as customer, 100 as P1, 'hjk' as P2, null as P3 from dual union all
select 2 as entity, 'DAVID' as customer, 100 as P1, 'heeee' as P2, null as P3 from dual union all
select 1 as entity, 'JOHN' as customer, 200 as P1, 'hjklm' as P2, null as P3 from dual union all
select 2 as entity, 'JOHN' as customer, 200 as P1, 'xdxxdxd' as P2, null as P3 from dual union all
select 1 as entity, 'Lloyd' as customer, null as P1, 'dfe' as P2, null as P3 from dual union all
select 1 as entity, 'LLOYD' as customer, null as P1, null as P2, 'dfe' as P3 from dual union all
select 1 as entity, 'ANNE' as customer, null as P1, Null as P2, 'xls' as P3 from dual union all
select 2 as entity, 'ANNE' as customer, null as P1, 'xls' as P2, Null as P3 from dual union all
select 1 as entity, 'MARK' as customer, 300 as P1, 'abc' as P2, null as P3 from dual union all
select 2 as entity, 'MARC' as customer, 0 as P1, null as P2, 'abc' as P3 from dual union all
select 3 as entity, 'Mark' as customer, 300 as P1, 'texttt' as P2, null as P3 from dual
),
sample_counts AS
(
Select
ROWNUM "RN", s1.ENTITY "ENTITY", UPPER(s1.CUSTOMER) "CUSTOMER", CASE WHEN s1.P1 Is Not Null THEN 1 ELSE 0 END "CNT_P1",
Nvl(To_Char(s1.P1), '0') "P1", (Select Count(*) From sample Where P2 = s1.P3 ) "CNT_P2_P3", Nvl(To_Char(s1.P2), '0') "P2",
(Select Count(*) From sample Where P3 = s1.P2 ) "CNT_P3_P2", Nvl(To_Char(s1.P3), '0') "P3",
Nvl((Select UPPER(CUSTOMER) From sample Where P2 = s1.P3 ), UPPER(s1.CUSTOMER)) "CUSTOMER_2"
From sample s1
Order By RN
),
p_data AS
(
Select RN, CUSTOMER_2, 'P1' "COL", To_Char(P1) "PX", To_Char(CNT_P1) "CNT_X" From sample_counts Union All
Select RN, CUSTOMER_2, 'P2' "COL", To_Char(P2) "PX", To_Char(CNT_P2_P3) "CNT_X" From sample_counts Union All
Select RN, CUSTOMER_2, 'P3' "COL", To_Char(P3) "PX", To_Char(CNT_P3_P2) "CNT_X" From sample_counts
Order By RN, COL
),
matches AS
(
SELECT p.RN, p.CUSTOMER_2, p.COL, p.PX, p.CNT_X, sc.P1, sc.P2, sc.P3
FROM p_data p
INNER JOIN sample_counts sc ON(sc.RN = p.RN)
WHERE p.CNT_X <> '0'
ORDER BY p.RN
)
SELECT DISTINCT
sc.ENTITY, sc.CUSTOMER_2, sc.P1 "P1", sc.P2 "P2", sc.P3 "P3",
'G' || To_Char(Min(m.RN) OVER(PARTITION BY sc.CUSTOMER_2 ORDER BY sc.CUSTOMER_2)) "GRP"
FROM
sample_counts sc
INNER JOIN
matches m ON (m.RN = sc.RN)
ORDER BY
sc.CUSTOMER_2, sc.ENTITY
--
-- R e s u l t :
--
-- ENTITY CUSTOMER_2 P1 P2 P3 GRP
-- ---------- ---------- ---------------------------------------- ------- --- -----------------------------------------
-- 1 ANNE 0 0 xls G7
-- 2 ANNE 0 xls 0 G7
-- 1 DAVID 100 hjk 0 G1
-- 2 DAVID 100 heeee 0 G1
-- 1 JOHN 200 hjklm 0 G3
-- 2 JOHN 200 xdxxdxd 0 G3
-- 1 LLOYD 0 0 dfe G5
-- 1 LLOYD 0 dfe 0 G5
-- 1 MARK 300 abc 0 G9
-- 2 MARK 0 0 abc G9
-- 3 MARK 300 texttt 0 G9
Related
I have data in DB2 table something like this
main_id
sub_id
key_id
type
100
1001
1
0
100
1001
2
0
101
1002
1
0
102
1003
1
1
102
1004
1
1
103
1005
2
2
103
1006
2
2
104
1007
2
0
105
1008
2
1
105
1009
2
1
Now I am trying to create output something like this where :
count1 - main_id count with multiple rows only with key id 1
count2 - main_id count with multiple rows only with key id 2
count3 - main_id count with multiple rows with combo 1 & 2 key id
Type
count_1
count_2
count_3
0
1
1
1
1
2
1
Overall, I need distinct main_id's count with multiple rows of sub_id and then need to segregate them based on type and key_id's
In the above case :
100 - has 2 rows w/ 1001 but key_id's are differnt -count_3
102 - has 2 rows w/ 1002 and 1003 but key_id's are from 1 - count_1
103 - has 2 rows w/ 1005 and 1006 but key_id's are from 2 - count_2
105 - has 2 rows w/ 1008 and 1009 but key_id's are from 2 -count_2
Ignored 101 and 104 as there are no multiple rows for that main_id
WITH main_ids AS (
SELECT main_id, key_id, type, COUNT(sub_id) sub_id_count
FROM your_table
GROUP BY main_id, key_id, type
),
grouped AS (
SELECT type, COUNT(main_id) main_id_count
FROM main_ids
WHERE sub_id_count > 1
GROUP BY type
)
SELECT type,
SUM(CASE WHEN key_id = 1 THEN sub_id_count END) count_1,
SUM(CASE WHEN key_id = 2 THEN sub_id_count END) count_2,
SUM(CASE WHEN sub_id_count > 1 THEN sub_id_count END) count_3
FROM main_ids
JOIN grouped ON grouped.type = main_ids.type
GROUP BY type
Need help with count_3 condition, is there any way where can get count of main_id having multiple rows with both key_id 1 and 2(in the above case only 100 main_id is satisfying that condition)
Appreciate any help
WITH
T (main_id, sub_id, key_id, type) AS
(
VALUES
(100, 1001, 1, 0)
, (100, 1001, 2, 0)
, (101, 1002, 1, 0)
, (102, 1003, 1, 1)
, (102, 1004, 1, 1)
, (103, 1005, 2, 2)
, (103, 1006, 2, 2)
, (104, 1007, 2, 0)
, (105, 1008, 2, 1)
, (105, 1009, 2, 1)
)
, G AS
(
SELECT TYPE, KEY_ID, COUNT (DISTINCT MAIN_ID) C
FROM T
GROUP BY TYPE, KEY_ID
)
SELECT
TYPE
, CASE WHEN C1 = 1 THEN 1 END AS COUNT_1
, CASE WHEN C2 = 1 THEN 1 END AS COUNT_2
, CASE WHEN C1 > 1 AND C2 > 1 THEN 1 END AS COUNT_3
-- Just for convenience
, C1
, C2
FROM
(
SELECT
M.TYPE
, COALESCE (G1.C, 0) AS C1
, COALESCE (G2.C, 0) AS C2
FROM (SELECT DISTINCT TYPE FROM G) M
LEFT JOIN G G1 ON G1.TYPE = M.TYPE AND G1.KEY_ID = 1
LEFT JOIN G G2 ON G2.TYPE = M.TYPE AND G2.KEY_ID = 2
)
TYPE
COUNT_1
COUNT_2
COUNT_3
C1
C2
0
1
2
2
1
1
1
1
1
2
1
0
1
Can someone help here.
I have table employee. I want to find out list of employees having 2 products(P1,P2).
Emp_id Prd_id
E1 P1
E1 P2
E2 P1
E2 P2
E2 P3
E3 P1
E3 P3
E4 P1
E4 P2
So, I want output as
Emp_id
E1
E4
SELECT emp_id
FROM employee
GROUP BY emp_id
HAVING COUNT(CASE WHEN prd_id 'p1' THEN 1 END) > 0 -- p1 exists
AND COUNT(CASE WHEN prd_id 'p2' THEN 1 END) > 0 -- p2 exists
AND COUNT(CASE WHEN prd_id NOT IN ('p1', 'p2') THEN 1 END) = 0 -- but not other
Easier to extend to a larger number of products:
SELECT emp_id
FROM
( -- get a unique list first
SELECT DISTINCT emp_id, prd_id
FROM employee
) AS dt
GROUP BY emp_id
HAVING SUM(CASE WHEN prd_id IN ('p1', 'p2') THEN 1 ELSE -1 END) = 2
If the requirement is to find employees with any two products, you could use a having condition to count them:
SELECT emp_id
FROM employees
GROUP BY emp_id
HAVING COUNT(*) = 2
If those products must be p1 and p2, you could add another condition on that:
SELECT emp_id
FROM employees
GROUP BY emp_id
HAVING COUNT(*) = 2 AND
COUNT(CASE WHEN prd_id IN ('p1', 'p2') THEN 1 END) = 2
i have table like this :
school grade type
------ ----- -----
sc1 g1 t1
sc2 g2 t1
sc3 g4 t3
sc4 g3 t2
sc1 g2 t3
... etc
column grade has 4 distinct value g1,g2,g3,g4
column type has 3 distinct value t1,t2,t3
column school has 120 distinct value
and i shoud get Summary like this table :(for each distinct column 1-school-)
school g1 g2 g3 g4 sum(g1+g2+g3+g4) t1 t2 t3 sum(t1+t2+t3)
sc1 3 5 1 1 10 21 4 2 27
sc2 2 4 5 5 16 5 23 1 29
etc....
How can I write this query to give me the desired result I achieved part of this job by using report builder V6i
i get all number of distinct school in 1st level and order them ascending
i make query for each value (g1,g2,g3,g4,t1,t2,t3)
i want to get that table in sql query without using report
Conditional aggregation:
with
like_this ( school, grade, typ ) as (
select 'sc1', 'g1', 't1' from dual union all
select 'sc2', 'g2', 't1' from dual union all
select 'sc3', 'g4', 't3' from dual union all
select 'sc4', 'g3', 't2' from dual union all
select 'sc1', 'g2', 't3' from dual
)
-- end of test data; SQL query begins below this line
select school,
count(case when grade = 'g1' then 1 end) as g1,
count(case when grade = 'g2' then 1 end) as g2,
count(case when grade = 'g3' then 1 end) as g3,
count(case when grade = 'g4' then 1 end) as g4,
count(grade) as total_g,
count(case when grade = 't1' then 1 end) as t1,
count(case when grade = 't2' then 1 end) as t2,
count(case when grade = 't3' then 1 end) as t3,
count(typ) as total_t
from like_this
group by school
order by school -- optional
;
SCH G1 G2 G3 G4 TOTAL_G T1 T2 T3 TOTAL_T
--- ------- ------- ------- ------- ------- ------- ------- ------- -------
sc1 1 1 0 0 2 0 0 0 2
sc2 0 1 0 0 1 0 0 0 1
sc3 0 0 0 1 1 0 0 0 1
sc4 0 0 1 0 1 0 0 0 1
4 rows selected.
I have an Oracle SQL query where I would like to return all rows where a certain column has a value, but if none of the rows have a value for that column then I would like to return one of the blank rows. How can this be accomplished?
My scenario is a learning path with courses that are to completed, but I want to show the percentage completion. Obviously if there are no courses completed I would like to show the learning path with a zero percentage completion.
The query is very complicated so I rather provide a dummy scenario below:
learning_paths
--------------
learning_path_id learning_path_name
1 Oracle Developer
2 Python Developer
courses
-------
course_id course_name
--------- -----------
1 Oracle SQL
2 Oracle PL/SQL
3 Python
4 Django
5 NLTK
learning_path_items
-------------------
learning_path_id course_id
---------------- ---------
1 1
1 2
2 3
2 4
2 5
learning_path_enrollments
-------------------------
employee_id learning_path_id
----------- ----------------
1 1
2 2
3 2
course_enrollments
------------------
employee_id course_id
----------- ---------
2 3
2 4
So my results should be:
employee_id learning_path_id course_id completion
----------- ---------------- --------- ----------
1 1 0 out of 2
2 2 3 2 out of 3
2 2 4 2 out of 3
3 2 0 out of 3
Below is the actual query, which is very complicated and still a work in progress.
select sub2.director,
sub2.cost_centre,
sub1.employee_number,
sub1.employee_name,
sub2.job_title,
sub1.course_name,
sub1.learning_path_name,
sub2.course_start_date,
sub2.course_end_date,
max(sub2.course_end_date) over (partition by sub1.employee_number, sub1.learning_path_name) max_course_end_date,
sub1.original_date_of_hire,
sub2.job_start_date promotion_date,
nvl(sub1.completion_target_days, 9999999999999999) completion_target_days,
sub1.completion_target_date,
sub1.no_of_completed_courses,
sub1.no_of_mandatory_courses,
round(least(sub1.no_of_completed_courses, sub1.no_of_mandatory_courses) / sub1.no_of_mandatory_courses * 100) completion_percentage
--round() time_percentage
from (
select papf.employee_number,
nvl(papf.known_as, papf.first_name) || ' ' || papf.last_name employee_name,
papf.original_date_of_hire,
oav.version_name course_name,
olpt.name learning_path_name,
ole.completion_target_date completion_target_date,
ole.no_of_completed_courses no_of_completed_courses,
ole.no_of_mandatory_courses no_of_mandatory_courses,
olp.duration completion_target_days,
papf.person_id,
oav.activity_version_id
from ota_lp_enrollments ole,
per_all_people_f papf,
ota_learning_paths olp,
ota_learning_paths_tl olpt,
ota_lp_sections ols,
ota_lp_sections_tl olst,
ota_learning_path_members olpm,
ota_activity_versions oav -- aka Courses
where papf.person_id = ole.person_id
and xxpay_bi_util.get_effective_date(ole.person_id, trunc(sysdate), 'all') between papf.effective_start_date
and papf.effective_end_date
and olp.learning_path_id = ole.learning_path_id
and olpt.learning_path_id = ole.learning_path_id
and olpt.language = userenv('LANG')
and ols.learning_path_id = ole.learning_path_id
and olst.learning_path_section_id = ols.learning_path_section_id
and olst.language = userenv('LANG')
and ols.learning_path_id = ole.learning_path_id
and olpm.learning_path_id = ole.learning_path_id
and olpm.learning_path_section_id = ols.learning_path_section_id
and oav.activity_version_id = olpm.activity_version_id
group by papf.employee_number,
nvl(papf.known_as, papf.first_name) || ' ' || papf.last_name,
papf.original_date_of_hire,
oav.version_name,
olpt.name,
olst.name,
ole.completion_target_date,
ole.no_of_completed_courses,
ole.no_of_mandatory_courses,
olp.duration,
papf.person_id,
oav.activity_version_id
) sub1,
(
select erm.*,
paaf.assignment_id,
paaf.person_id,
pj.name job_title,
haou.name cost_centre,
paafm.job_start_date,
xxpay_util.get_lookup_value(trunc(sysdate), 'TRUW_HR_DIRECTORS', hoi.org_information1) director -- 'Derek Kohler (Stores)'
from (
select odb.booking_id,
odb.delegate_person_id,
odb.date_booking_placed,
oe.course_start_date,
oe.course_end_date,
oe.course_start_time,
oe.course_end_time,
oe.enrolment_start_date,
oe.public_event_flag,
oe.title class_title,
oe.activity_version_id
from ota_delegate_bookings odb,
ota_events oe -- aka Classes
where oe.event_id = odb.event_id
) erm,
per_all_assignments_f paaf,
per_jobs pj,
hr_all_organization_units haou,
hr_organization_information hoi,
(
select paaf.person_id,
paaf.assignment_id,
paaf.job_id,
min(paaf.effective_start_date) job_start_date
from per_all_assignments_f paaf
where paaf.assignment_type in ('E', 'C')
and paaf.primary_flag = 'Y'
group by paaf.person_id,
paaf.assignment_id,
paaf.job_id
) paafm
where paaf.person_id (+) = erm.delegate_person_id
and erm.course_start_date between nvl(paaf.effective_start_date (+), to_date('01/01/1000', 'dd/mm/yyyy'))
and nvl(paaf.effective_end_date (+), to_date('31/12/4712', 'dd/mm/yyyy'))
and paafm.person_id (+) = paaf.person_id
and paafm.assignment_id (+) = paaf.assignment_id
and paafm.job_id (+) = paaf.job_id
and pj.job_id (+) = paaf.job_id
and haou.organization_id (+) = paaf.organization_id
and hoi.organization_id (+) = paaf.organization_id
and hoi.org_information_context (+) = 'TRU_ADD_ORG'
) sub2
where sub2.activity_version_id (+) = sub1.activity_version_id
and sub2.person_id (+) = sub1.person_id
and sub1.employee_number in ('2006591', '2005681', '2004118', '2004212')
order by 3, 1, 2, 4, 5, 7
If you have tables like this:
CREATE TABLE students (
student_id NUMBER PRIMARY KEY
);
CREATE TABLE courses (
course_id NUMBER PRIMARY KEY
);
CREATE TABLE student_courses (
student_id NUMBER REFERENCES Students( student_id ),
course_id NUMBER REFERENCES Courses( course_id ),
completed NUMBER(1,0),
score NUMBER(3,0),
CONSTRAINT student_courses_pk PRIMARY KEY ( student_id, course_id )
);
Then you can do:
SELECT s.student_id,
COUNT( CASE c.completed WHEN 1 THEN 1 END ) / COUNT( c.course_id ) * 100 AS percent_enrolled_completed
FROM student s
LEFT OUTER JOIN
student_courses c
ON ( s.student_id = c.student_id )
GROUP BY s.student_id;
Edited: to answer updated question
SQL Fiddle
Oracle 11g R2 Schema Setup:
create table learning_path_items AS
SELECT 1 AS learning_path_id, 1 AS course_id FROM DUAL
UNION ALL SELECT 1, 2 FROM DUAL
UNION ALL SELECT 2, 3 FROM DUAL
UNION ALL SELECT 2, 4 FROM DUAL
UNION ALL SELECT 2, 5 FROM DUAL;
create table learning_path_enrollments AS
SELECT 1 AS employee_id, 1 AS learning_path_id FROM DUAL
UNION ALL SELECT 2, 2 FROM DUAL
UNION ALL SELECT 3, 2 FROM DUAL;
create table course_enrollments AS
SELECT 2 AS employee_id, 3 AS course_id FROM DUAL
UNION ALL SELECT 2, 4 FROM DUAL;
Query 1:
WITH num_completed AS (
SELECT e.learning_path_id,
e.employee_id,
c.course_id,
COUNT( c.course_id ) OVER ( PARTITION BY e.learning_path_id, e.employee_id ) AS num_completed
FROM learning_path_items i
INNER JOIN
learning_path_enrollments e
ON (e.learning_path_id = i.learning_path_id)
INNER JOIN
course_enrollments c
ON (i.course_id = c.course_id
AND e.employee_id = c.employee_id)
),
num_courses AS (
SELECT e.learning_path_id,
e.employee_id,
COUNT( 1 ) AS num_courses
FROM learning_path_items i
INNER JOIN
learning_path_enrollments e
ON (e.learning_path_id = i.learning_path_id)
GROUP BY
e.learning_path_id,
e.employee_id
)
SELECT c.learning_path_id,
c.employee_id,
x.course_id,
COALESCE( x.num_completed, 0 ) || ' out of ' || c.num_courses AS completion
FROM num_courses c
LEFT OUTER JOIN
num_completed x
ON ( c.employee_id = x.employee_id
AND c.learning_path_id = x.learning_path_id )
ORDER BY 1, 2, 3
Results:
| LEARNING_PATH_ID | EMPLOYEE_ID | COURSE_ID | COMPLETION |
|------------------|-------------|-----------|------------|
| 1 | 1 | (null) | 0 out of 2 |
| 2 | 2 | 3 | 2 out of 3 |
| 2 | 2 | 4 | 2 out of 3 |
| 2 | 3 | (null) | 0 out of 3 |
SELECT whatever FROM wherever UNION ALL SELECT 0 FROM DUAL LIMIT 1;
If you get a result from your first query you would get the 1 row with the percentage you are trying to get
second select returns a row that has value 0 but is stored in a VARCHAR2(1) from the dummy table DUAL so you will either get the result from your first query (assuming you only get 1 result because otherwise it will only show the first row it returns)
if the first select returns no rows, the second select will return a single column single row result with a varchar2(1) '0'
ALTERNATIVELY
SELECT
something
FROM sometable
WHERE somefield = somevalue
UNION ALL
SELECT
0
WHERE NOT EXISTS (SELECT something FROM sometable WHERE somefield = somevalue)
This will do the same except only when your first select query returns no rows, I guess this would be the better answer for your question as the first query might be returning multiple rows
SQL grouping by one value in 2 columns
Source data table:
P2 P3
----------
1 2
2 1
2 3
4 1
I want a query that counts a's and b's in each column, producing something like:
num conut
-------------
1 3
2 3
3 1
4 1
You can do this using union all and group by:
select num, sum(cnt) as conut
from (select p2 as num, count(*) as cnt from source group by p2
union all
select p3 as num, count(*) as cnt from source group by p3
) p
group by num;