Home > Software engineering >  Query record categories if a no record has missing data in that category
Query record categories if a no record has missing data in that category

Time:10-05

Let's say I have the following data table:

id | data_1 | data_2 | category
1  |    a   |    A   |    1    
2  |    a   |    A   |    1    
3  |        |    B   |    2    
4  |    b   |    B   |    2    
5  |    b   |    B   |    2    
6  |    c   |        |    3    
7  |    c   |        |    3    
8  |    c   |    C   |    3    
9  |        |    D   |    4 
10 |    d   |        |    4    
11 |    d   |    D   |    4    
12 |    d   |    D   |    4    
13 |    e   |    E   |    5    
14 |    e   |    E   |    5     
15 |    f   |    F   |    6      

and a list of (record) id as input:

1, 5, 12, 13, 14

I'd like to make a query which returns all those categories which are "referenced" by any of the record in the input list and the referenced category is "complete".

By

  • referenced category I mean that at least one record from the input list belongs to that category
  • complete category I mean that all record that belongs to that category has value (i.e. not NULL or empty string) in both data_1 and data_2 column. (So in the example table category 1, 5 and 6 is complete)

So for the example table and input the result would be:

category
   1    
   5    

(And for an input of 4, 5, 6 the result would be NULL or empty list)

Is it possible to make single query for this?

(fiddle)

CodePudding user response:

select distinct category from tbl 
where category not in (
select category from tbl
where data_1 is null or data_1 = ''
or  data_2 is null or data_2 = '')

Fixed using your fiddle!

CodePudding user response:

First, query ids where category is completed:

select
    category,
    array_agg(id) as ids
from tbl
group by category
having bool_and(nullif(data_1, '') || nullif(data_2, '') is not null) 
order by category;

 category |   ids
---------- ---------
        1 | {1,2}
        5 | {13,14}
        6 | {15}
(3 rows)

Use this as a derived table to search ids matching the input list:

select category
from (
    select
        category,
        array_agg(id) as ids
    from tbl
    group by category
    having bool_and(nullif(data_1, '') || nullif(data_2, '') is not null) 
    ) s
where ids && array[1, 5, 12, 13, 14] -- input parameter
order by category;

 category
----------
        1
        5
(2 rows)

Test it in db<>fiddle.

Alternative solution using the bool_and() aggregate as a window function:

select distinct category
from (
    select 
        id, 
        category,
        bool_and(nullif(data_1, '') || nullif(data_2, '') is not null) over w as completed
    from tbl
    window w as (partition by category)
    ) s
where completed
and id = any(array[1, 5, 12, 13, 14]) -- input parameter
order by category;
  • Related