Gaffi
Gaffi

Reputation: 4367

SQL Consolidating Multiple rows

I'm simplifying the problem, but the concept here should be the same...

Let's say we have a table FOO with fields ID and ATTRIB, and a table BAR with fields ID, A_MATCHING_ID, STATUS. These tables look like this:

Table FOO:

ID    -     ATTRIB
=====
1001  -     ATR_A
1002  -     ATR_B
1003  -     ATR_A
1004  -     ATR_B
1005  -     ATR_B

etc.

Table BAR:

ID    -     FOO_MATCHING_ID   -     STATUS
=====
9901  -     1001              -     STAT_A
9902  -     1001              -     STAT_A
9903  -     1001              -     STAT_B
9904  -     1002              -     STAT_C
9905  -     1002              -     STAT_B
9906  -     1002              -     STAT_B
9907  -     1003              -     STAT_A

etc.

There is a one-to-many relationship of FOO to BAR.

I want to run a query on these two tables with a calculated/dependent field [HAS_STAT_A]:

Expected Query Result:

FOO_ID      -     HAS_STAT_A
=====
1001        -     TRUE
1002        -     FALSE
1003        -     TRUE

How can I accomplish this?

SELECT FOO.ID AS FOO_ID, [FILL THIS IN] AS HAS_STAT_A 
FROM FOO 
JOIN BAR ON FOO.ID = BAR.FOO_MATCHING_ID;

I thought of using CASE, but don't know how to use that across multiple records. I also thought of adding in some extra sub-queries, but wasn't sure how to arrange those, either.

This is similar, but not quite what I want to achieve. It led to me to something like the below, but I get GROUP BY errors. When I add GROUP BY, I get MISSING KEYWORD errors.

SELECT FOO.ID AS FOO_ID, 
    INSTR (LISTAGG (BAR.STATUS, ',') WITHIN GROUP (ORDER BY BAR.STATUS), 'STAT_A') AS HAS_STAT_A 
FROM FOO 
JOIN BAR ON FOO.ID = BAR.FOO_MATCHING_ID; 

Upvotes: 0

Views: 295

Answers (3)

Brian Camire
Brian Camire

Reputation: 4825

If it is possible for there to be rows in foo that have no matching rows in bar, you might try something like this:

SELECT
    foo.id AS foo_id,
    NVL
    (
        (
            SELECT
                'TRUE'
            FROM
                bar
            WHERE
                bar.foo_matching_id = foo.id
                AND
                bar.STATUS = 'STAT_A'
                AND
                ROWNUM <= 1
        ),
        'FALSE'
    )
FROM
    foo

There may be more efficient ways to rewrite this query.

Upvotes: 0

Xabur
Xabur

Reputation: 49

Here's one way to do it

SELECT 
    FOO.ID AS FOO_ID, 
    SUM(CASE WHEN BAR.[STATUS]='STAT_A' THEN 1 ELSE 0 END) AS HAS_STAT_A
FROM FOO 
    INNER JOIN BAR ON FOO.ID = BAR.FOO_MATCHING_ID
GROUP BY
    FOO.ID

You can also take this and filter out the rows where has_stat_a is 0 by using the "having" keyword

SELECT 
    FOO.ID AS FOO_ID, 
    SUM(CASE WHEN BAR.[STATUS]='STAT_A' THEN 1 ELSE 0 END) AS HAS_STAT_A
FROM FOO 
    INNER JOIN BAR ON FOO.ID = BAR.FOO_MATCHING_ID
GROUP BY 
    FOO.ID
HAVING
    SUM(CASE WHEN BAR.[STATUS]='STAT_A' THEN 1 ELSE 0 END) = 1

Upvotes: 0

Andomar
Andomar

Reputation: 238088

select  foo.id as foo_id
,       case 
        when max(case when lower(trim(bar.status)) = 'stat_a' then 1 end) = 1 then 'true' 
        else 'false' 
        end as has_stat_a 
from    foo 
join    bar
on      foo.id = bar.foo_matching_id
group by
        foo.id

Upvotes: 4

Related Questions