SQL合并多行

时间:2012-12-19 15:17:57

标签: sql oracle concatenation grouping

我正在简化问题,但这里的概念应该是相同的......

假设我们有一个包含字段FOOID的表ATTRIB,以及一个包含字段BARID的表A_MATCHING_IDSTATUS。这些表看起来像这样:

表格FOO:

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

etc.

表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.

FOOBAR之间存在一对多的关系。

我想使用计算/从属字段[HAS_STAT_A]对这两个表运行查询:

预期查询结果:

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

我该如何做到这一点?

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

我想过使用CASE,但不知道如何在多个记录中使用它。我还考虑过添加一些额外的子查询,但也不确定如何安排这些。

This is similar,但不是我想要实现的目标。它导致我得到类似下面的内容,但我得到GROUP BY错误。当我添加GROUP BY时,我会收到MISSING KEYWORD个错误。

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; 

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

这是一种方法

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”关键字将过滤掉has_stat_a为0的行

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

答案 2 :(得分:0)

如果foo中的行可能在bar中没有匹配的行,您可以尝试这样的事情:

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

可能有更有效的方法来重写此查询。