【问题标题】:SQL Consolidating Multiple rowsSQL合并多行
【发布时间】:2012-12-19 15:17:56
【问题描述】:

我是在简化问题,但是这里的概念应该是一样的……

假设我们有一个表FOO,其中字段为IDATTRIB,还有一个表BAR,字段为IDA_MATCHING_IDSTATUS。这些表如下所示:

表 FOO:

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

etc.

表格栏:

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; 

【问题讨论】:

    标签: sql oracle concatenation grouping


    【解决方案1】:
    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
    

    【讨论】:

    • 这似乎是有道理的,所以谢谢。但是,我收到一个错误:ORA-00979: not a GROUP BY expression,尽管我使用了一个有效字段来GROUP BY
    • 如果foo 中的行在bar 中没有匹配的行,则这些行不会显示在查询结果中(因为您使用的是内连接),这可能不是你想要的。
    • @BrianCamire 感谢您的额外建议。幸运的是,我知道(或者至少我认为我知道;这不是我的数据库,我只是在抓取数据)总会有匹配的。
    【解决方案2】:

    这是一种方法

    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
    

    您也可以使用“have”关键字过滤掉 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
    

    【讨论】:

      【解决方案3】:

      如果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
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-14
        相关资源
        最近更新 更多