How to correlate data and counts from columns to rows in Oracle (19c)?

Solution for How to correlate data and counts from columns to rows in Oracle (19c)?
is Given Below:

I believe there is probably an easy way to solve these problems with pivots or partitions but I can’t seem to find the proper solutions. I have a round about solution for problem 1 by using a long list of select sum()s and a long solution for problem 2 where I just select the count(*) from table B where id = id from table A multiple times in a (select) blocks but if I have a large number of IDs both of those solution equal very long SQL that gets very tedious and I’m sure there is a better way it is just eluding me.

I would really like solutions that would allow me to include a large set of multiple IDs or supply the solution with a table of IDs to evaluate.

Problem 1:

Table: 
------------------
ID   DESC   YEAR
1     A     2021
1     B     2021
1     C     2021
2     A     2021
2     B     2021
2     C     2021
3     A     2019
3     B     2019

I would like to have the count of the ID’s for each DESC by year.

Expected Result:
------------------
Year  CountA  CountB  CountC
2019    1       1       0
2021    2       2       2

Problem 2:

Table A:
------------------
ID  DESC
1    A
2    B
3    C

Table B:
------------------
SET  ID  
10   1   
10   1   
12   1   
13   2   
14   3   

I would like to see (1) how many of each ID from Table A can be found in each SET in Table B and (2) how many of each ID from Table A can be found in each SET in Table B and not in any other SET of Table B (unique matches).

Expected Result 1:
------------------
ID  Count10  Count12  Count13  Count14
1      2        1        0        0
2      0        0        1        0
3      0        0        0        1

Expected Result 2:
------------------
ID  UniqueCount10  UniqueCount12  UniqueCount13  UniqueCount14
1         0              0              0              0
2         0              0              1              0
3         0              0              0              1

Thank you for any and all assistance.

All three problems can be solved with pivoting (calling Problem 2 “two different problems”), although it is not clear what purpose Result 2 would serve (in the second problem; see my comments to you).

Note that desc and set are reserved keywords, and year is a keyword, so they shouldn’t be used as column names. I changed to descr, set_ (with an underscore) and yr. Also, I do not use double-quotes for column names in the output; all-caps column names are just fine.

In the second problem it is not clear why you need Table A. Could you have some id values that don’t appear at all in Table B, but you still want them in the final output? If so, you will need to change my semi-joins to outer joins; left as an exercise, since it’s a different (and much more basic) type of question.

In the first problem, you must pivot the result of a subquery, which selects only the relevant columns from the base table. There is no such need for the second problem (unless your tables have other columns that should not be considered – left for you to figure out).

Problem 1

Data:

create table tbl (id, descr, yr) as
  select 1, 'A', 2021 from dual union all
  select 1, 'B', 2021 from dual union all
  select 1, 'C', 2021 from dual union all
  select 2, 'A', 2021 from dual union all
  select 2, 'B', 2021 from dual union all
  select 2, 'C', 2021 from dual union all
  select 3, 'A', 2019 from dual union all
  select 3, 'B', 2019 from dual
;

Query and output:

select *
from   (select descr, yr from tbl)
pivot  (count(*) for descr in ('A' as count_a, 'B' as count_b, 'C' as count_c))
order  by yr
;

  YR COUNT_A COUNT_B COUNT_C
---- ------- ------- -------
2019       1       1       0
2021       2       2       2

Problem 2

Data:

create table table_a (id, descr) as
  select 1, 'A' from dual union all
  select 2, 'B' from dual union all
  select 3, 'C' from dual
;

create table table_b (set_, id) as
  select 10, 1 from dual union all   
  select 10, 1 from dual union all   
  select 12, 1 from dual union all
  select 13, 2 from dual union all
  select 14, 3 from dual
;

Part 1 – Query and result:

select *
from   table_b
pivot  (count(*) for set_ in (10 as count_10, 12 as count_12,
                              13 as count_13, 14 as count_14))
where  id in (select id from table_a)        -- is this needed?
order  by id                                 -- if needed
;

ID COUNT_10 COUNT_12 COUNT_13 COUNT_14
-- -------- -------- -------- --------
 1        2        1        0        0
 2        0        0        1        0
 3        0        0        0        1

Part 2 – Query and result:

select *
from   (
         select id, case count(distinct set_) when 1 then max(set_) end as set_
         from   table_b
         where  id in (select id from table_a)        -- is this needed?
         group  by id
       )
pivot  (count(*) for set_ in (10 as unique_ct_10, 12 as unique_ct_12,
                              13 as unique_ct_13, 14 as unique_ct_14))
order  by id          -- if needed
;

ID UNIQUE_CT_10 UNIQUE_CT_12 UNIQUE_CT_13 UNIQUE_CT_14
-- ------------ ------------ ------------ ------------
 1            0            0            0            0
 2            0            0            1            0
 3            0            0            0            1

In this last part of the second problem, you might as well just take the subquery and run it separately – what’s the purpose of pivoting its output?