带组的 Oracle 查询

Posted

技术标签:

【中文标题】带组的 Oracle 查询【英文标题】:Oracle query with group 【发布时间】:2018-03-25 03:48:18 【问题描述】:

我有一个场景,我需要获取同一来源的 ID 中的所有记录。下面给出的是我的输入记录集

ID  SOURCE  CURR_FLAG       TYPE
1   IBM       Y               P
1   IBM       Y               OF
1   IBM       Y               P
2   IBM       Y               P
2   TCS       Y               P
3   IBM     NULL              P
3   IBM     NULL              P
3   IBM     NULL              P
4   IBM     NULL              OF
4   IBM     NULL              OF
4   IBM      Y                ON

从上述设置中,我需要在同一 ID 组中选择来源为 IBM 的所有记录。在 ID 组中,如果至少有一条记录的来源不是 IBM,那么我不想要任何来自该 ID 组的记录。此外,我们只需要获取该 ID 组中至少有一条 curr_fl='Y' 记录的记录

在上述场景中,即使ID=3的来源为IBM,但没有CURR_FL='Y'的记录,我的查询不应该取值。在ID=4的情况下,它可以取到ID=4 的所有记录,因为其中一条记录的 value='Y'。

同样在满足上述条件的组内,我还需要一个 source_type 的条件。如果有 source_type='P' 的记录,那么我只需要获取那条记录。如果没有 P 的记录,那么我将搜索 source_type='OF' 否则 source_type='ON'

我已经编写了一个如下给出的查询。但是它运行了很长时间并且没有获取任何结果。有没有更好的方法来修改这个查询

select
    ID,
    SOURCE,
    CURR_FL,
   TYPE
from TABLE a
where 
    not exists(select 1 from TABLE B where a.ID = B.ID and source <> 'IBM')
    and exists(select 1 from TABLE C where a.ID = C.ID and CURR_FL = 'Y')  and
        (TYPE, ID) IN (
            select case  type when 1 then 'P' when 2 then 'OF' else 'ON' END TYPE,ID  from
            (select ID,
             max(priority) keep (dense_rank first order by priority asc) as type
      from ( select ID,TYPE,
               case TYPE 
                     when 'P' then 1
                     when 'OF' then 2
                     when 'ON' then 3
                end as priority 
           from TABLE where ID
            in(select ID from TABLE where CURR_FL='Y') AND SOURCE='IBM')
                group by ID)) 

【问题讨论】:

【参考方案1】:

我认为您可以通过 ID 对您的表进行一次聚合并检查 yes 标志以及断言没有出现非 IBM 源。我在下面的 CTE 中执行此操作,然后连接回您的原始表以返回完整匹配的记录。

WITH cte AS (
    SELECT
        ID,
        CASE WHEN SUM(CASE WHEN TYPE = 'P'  THEN 1 ELSE 0 END) > 0
             THEN 1
             WHEN SUM(CASE WHEN TYPE = 'OF' THEN 1 ELSE 0 END) > 0
             THEN 2
             WHEN SUM(CASE WHEN TYPE = 'ON' THEN 1 ELSE 0 END) > 0
             THEN 3 ELSE 4 END AS p_type
    FROM yourTable
    GROUP BY ID
    HAVING
        SUM(CASE WHEN CURR_FLAG = 'Y' THEN 1 ELSE 0 END) > 0 AND
        SUM(CASE WHEN SOURCE <> 'IBM' THEN 1 ELSE 0 END) = 0
)

SELECT t1.*
FROM yourTable t1
INNER JOIN cte t2
    ON t1.ID = t2.ID
WHERE
    t2.p_type = 1 AND t1.TYPE = 'P' OR
    t2.p_type = 2 AND t1.TYPE = 'OF' OR
    t2.p_type = 3 AND t1.TYPE = 'ON';

【讨论】:

谢谢。但是对于 source_type,我还有另一种情况。我可以将其包含在此查询中 非常感谢蒂姆。只是为了澄清一下,我的场景是,只有在没有 source_type='P' 或 source_type='OF' 的记录时才需要 ON 记录,优先级是 P-->OF-->ON。跨度> 非常感谢..这对我来说是一个艰难的过程,你很容易处理它:-) @GIN 一旦我知道了你的所有要求,这很简单。因此提出一个好问题的重要性:-)

以上是关于带组的 Oracle 查询的主要内容,如果未能解决你的问题,请参考以下文章

oracle 查询每组的最大值

从零开始学习Oracle数据库函数与子查询和连接查询

从零开始学习Oracle数据库函数与子查询和连接查询

导出不带组的 s-s-rS 时命名 Excel 工作表

Oracle SQL查询:根据时间检索每组的最新值[重复]

oracle中将同一组的数据拼接(转)