Sql 在一个简单的查询中有没有办法做到这一点?

Sql 在一个简单的查询中有没有办法做到这一点?,sql,oracle,group-by,subquery,Sql,Oracle,Group By,Subquery,我有一个2300万行的大型表CONTRATOS,其中包含以下列: SELECT CONTRATO, CODIGO_ORIGEN, ORIGEN FROM CONTRATOS; CODIGO_ORIGEN列有多行具有相同的值: CODIGO_ORIGEN CONTRATO ORIGEN ------------- ---------- -------- 1 345 CONT

我有一个2300万行的大型表CONTRATOS,其中包含以下列:

SELECT
    CONTRATO,
    CODIGO_ORIGEN,
    ORIGEN
FROM CONTRATOS;
CODIGO_ORIGEN列有多行具有相同的值:

CODIGO_ORIGEN     CONTRATO       ORIGEN 
-------------    ----------     --------
     1               345          CONT
     1               363          BKP
     1               645          BKP
     1               365          CONT 
我只需要每个CODIGO_ORIGEN获得一个CONTRATO,但始终优先考虑“CONT”值。因此,在这个示例中,它将是值为365的对立面

我试着做这样的事情:

SELECT  
   CODIGO_ORIGEN,
   CASE
    WHEN ORIGEN = 'CONT' THEN
        FIRST_VALUE (CONTRATO) OVER (PARTITION BY CODIGO_ORIGEN ORDER BY CONTRATO DESC) 
    WHEN ORIGEN = 'BKP' THEN
        FIRST_VALUE (CONTRATO) OVER (PARTITION BY CODIGO_ORIGEN ORDER BY CAMPO1 DESC, CAMPO2 DESC, CONTRATO DESC) 
   END AS CONTRATO
FROM CONTRATOS;
如果ORIGEN是“CONTR”,我应该按最高的CONTRATO排序,并获得CONTRATO列。 如果ORIGEN是“BKP”,我应该按不同的列进行排序,并获得CONTRATO列

最后,我应该能够使用CODIGO_ORIGEN->CONTRATO 1:1创建一个唯一的行

是否有一种简单的方法来执行此1查询

提前谢谢

您可以使用ROW\u NUMBER按codigo\u origen对行进行排序。下面是一种编写ORDERBY子句的方法。还有其他的

select *
from
(
  select  
     c.*,
     row_number() over (
       partition by codigo_origen 
       order by 
         case when origen 'BKP' then campo1 end desc,
         case when origen 'BKP' then campo2 end desc,
         origen desc
     ) as rn
  from contratos c
) ranked
where rn = 1
order by codigo_origen;
我想我明白了:

      SELECT 
        C.contrato, C.codigo_origen,  NVL2(MX.CONTRATO, NULL, 'F') AS ESTADO, NVL2(MX.CONTRATO, NULL, '4008') AS ERROR
      FROM MGR_CUENTA_CTL C
      LEFT JOIN
      (
          select /*+ PARALLEL */
            DISTINCT CODIGO_ORIGEN,
            CASE
              WHEN ORIGEN_TABLA = 'CONT' THEN FIRST_VALUE(CONTRATO) OVER (PARTITION BY CODIGO_ORIGEN ORDER BY CONTRATO DESC) 
              WHEN ORIGEN_TABLA = 'BKP' THEN FIRST_VALUE(CONTRATO) OVER (PARTITION BY CODIGO_ORIGEN ORDER BY CAMPO1 DESC, CAMPO2 DESC) 
            END AS CONTRATO
          FROM
          (  
             SELECT /*+ PARALLEL */ ctl.*
             FROM mgr_cuenta_ctl ctl
             LEFT JOIN 
             (
                   select /*+ PARALLEL */ CODIGO_ORIGEN
                   from mgr_cuenta_ctl
                   group by codigo_origen having count(distinct origen) > 1
             ) CTL2 ON ctl.CODIGO_ORIGEN = ctl2.CODIGO_ORIGEN
             WHERE (CTL2.CODIGO_ORIGEN IS NOT NULL AND CTL.ORIGEN <> 'BKP') OR (CTL2.CODIGO_ORIGEN IS NULL)
          )
      ) MX ON MX.CONTRATO = C.CONTRATO;
我想这正是我想解释的

这对你有意义吗

谢谢

检查是否存在origen='CONT',使用分析计数。如果是-使用分析函数和第一排序方法,如果不是-第二排序:

select mgr_cuenta_ctl.*,
       case 
       when count(case origen when 'CONT' then 1 end) over (partition by codigo_origen) > 0
       then first_value(contrato) over (
            partition by codigo_origen
            order by case origen when 'CONT' then 1 end, contrato desc)
       else first_value(contrato) over (
            partition by codigo_origen
            order by case origen when 'BKP' then 1 end, campo1 desc, campo2 desc, contrato desc)
       end as best
  from mgr_cuenta_ctl
如果只需要分组值,而不需要详细信息,请删除partition by子句:


顺便说一句,我试图分析你的查询,但它抛出了一些奇怪的错误,我放弃了。在这里,您只需触摸表一次,没有自联接,因此速度应该更快。

只添加一个示例数据表就可以替换所有文本,您应该这样做。我添加了两个简单的查询来澄清这一情况。你明白这个问题吗?谢谢编辑问题并添加@TimBiegeleisen询问的样本数据。这样得到好答案的机会就会增加。无论如何,回答你们在评论中提出的问题,NOHi伙计们,我编辑了我的问题,我希望你们现在能理解。谢谢你的需求还没有明确界定。首先,您只显示codigo_origen的1个值—一个糟糕的数据世界,并且对origen->cont进行复杂的优先级排序。这是否意味着如果ORIGON->cont然后排除origen->bkp。从结果来看。此外,您的数据不完整,缺少查询中使用的列campo1和campo2。最后,您使用codigo_origen->contrato 1:1请求唯一行,这意味着什么?数据中似乎没有任何东西可以产生1:1的结果。谢谢你的提问!它做的和我最近发布的查询一样吗?
select codigo_origen,
       case when count(case origen when 'CONT' then 1 end) > 0
       then max(contrato) keep (dense_rank first 
                order by case origen when 'CONT' then 1 end, contrato desc) 
       else max(contrato) keep (dense_rank first 
                order by case origen when 'BKP' then 1 end, campo1 desc, campo2 desc) 
       end as best
  from mgr_cuenta_ctl
  group by codigo_origen